来源:http://blog.csdn.net/liuzhenwen/archive/2009/04/22/4101003.aspx
推荐系统最早在亚马逊的网站上应用,根据以往用户的购买行为,推荐出购买某种产品同时可能购买的其他产品。
直接打分需要用户的参与程度比较高,很多网站都在内容页中留一个打分的按钮,从1~5选一 个,我可能喜欢这篇文章,可我哪里知道我喜欢的程度是几分啊,还要我去思考,而网站设计中一条很重要的原则是:Do not let me think!,于是我就胡打一个分数或者不打,而隐性的打分则不同,只有你喜欢的图书你才会购买,只有你喜欢的歌曲才会听多次。
最近邻搜索算法一般是皮尔森相关系数(Person Correlation Coefficient)、余弦相似性(Cosine-based Similarity)以及调整余弦相似性(Adjusted Cosine Similarity)。关于余弦定理在数据挖掘中的应用,google黑白报有过介绍,可以参考数学之美 系列 12 - 余弦定理和新闻的分类。
基本原理
用户 对事物A打分 对事物B打分 X 3 4 Y 2 4 Z 4 ?
用户Z对事物B的打分可能是多少呢?股票上有个说法是平均值可以掩盖一切异常波动,所以股票上的各个技术指标收拾不同时间段的平均值的曲线图或者柱 状图等。同样的,Slope one算法也认为:平均值也可以代替某两个未知个体之间的打分差异,事物A对事物B的平均很差是:((3 - 4) + (2 - 4)) / 2 = -1.5,也就是说人们对事物B的打分一般比事物A的打分要高1.5,于是Slope one算法就猜测Z对事物B的打分是4 + 1.5 = 5.5
加权算法
有n个人对事物A和事物B打分了,R(A->B)表示这n个人对A和对B打分的平均差(A-B),有m个人对事物B和事物C打分 了,R(C->B)表示这m个人对C和对B打分的平均差(C-B),注意都是平均差而不是平方差,现在某个用户对A的打分是ra,对C的打分是 rc,那么A对B的打分可能是:
rb = (n * (ra - R(A->B)) + m * (rc - R(C->B)))/(m+n)
- # This is the code in plain text out of the technical report.
- #
- # Daniel Lemire, Sean McGrath, Implementing a Rating-Based Item-to-Item
- # Recommender System in PHP/SQL, Technical Report D-01, January 2005.
- #
- # http://www.ondelette.com/lemire/abstracts/TRD01.html
- #
- # This code is in the public domain, use at your own risks.
- # It is assumed that you looked at the report and know some SQL and PHP.
- #
- # Daniel Lemire, February 3rd 2005
- #
- # First part is sample SQL code.
- #########CUT HERE####################
- CREATE TABLE rating (
- userID INT PRIMARY KEY,
- itemID INT NOT NULL,
- ratingValue INT NOT NULL,
- datetimestamp TIMESTAMP NOT NULL
- );
- CREATE TABLE dev (
- itemID1 int(11) NOT NULL default '0',
- itemID2 int(11) NOT NULL default '0',
- count int(11) NOT NULL default '0',
- sum int(11) NOT NULL default '0',
- PRIMARY KEY (itemID1,itemID2)
- );
- # simple query to output 10 most liked items
- # by people who rated item 1
- SELECT itemID2, ( sum / count ) AS average
- FROM dev
- WHERE count > 2 AND itemID1 = 1
- ORDER BY ( sum / count ) DESC
- LIMIT 10;
- # Next part is sample PHP code.
- #########CUT HERE####################
- // This code assumes $itemID is set to that of
- // the item that was just rated.
- // Get all of the user's rating pairs
- $sql = "SELECT DISTINCT r.itemID, r2.ratingValue - r.ratingValue
- as rating_difference
- FROM rating r, rating r2
- WHERE r.userID=$userID AND
- r2.itemID=$itemID AND
- r2.userID=$userID;";
- $db_result = mysql_query($sql, $connection);
- $num_rows = mysql_num_rows($db_result);
- //For every one of the user's rating pairs,
- //update the dev table
- while ($row = mysql_fetch_assoc($db_result)) {
- $other_itemID = $row["itemID"];
- $rating_difference = $row["rating_difference"];
- //if the pair ($itemID, $other_itemID) is already in the dev table
- //then we want to update 2 rows.
- if (mysql_num_rows(mysql_query("SELECT itemID1
- FROM dev WHERE itemID1=$itemID AND itemID2=$other_itemID",
- $connection)) > 0) {
- $sql = "UPDATE dev SET count=count+1,
- sum=sum+$rating_difference WHERE itemID1=$itemID
- AND itemID2=$other_itemID";
- mysql_query($sql, $connection);
- //We only want to update if the items are different
- if ($itemID != $other_itemID) {
- $sql = "UPDATE dev SET count=count+1,
- sum=sum-$rating_difference
- WHERE (itemID1=$other_itemID AND itemID2=$itemID)";
- mysql_query($sql, $connection);
- }
- }
- else { //we want to insert 2 rows into the dev table
- $sql = "INSERT INTO dev VALUES ($itemID, $other_itemID,
- 1, $rating_difference)";
- mysql_query($sql, $connection);
- //We only want to insert if the items are different
- if ($itemID != $other_itemID) {
- $sql = "INSERT INTO dev VALUES ($other_itemID,
- $itemID, 1, -$rating_difference)";
- mysql_query($sql, $connection);
- }
- }
- }
- function predict($userID, $itemID) {
- global $connection;
- $denom = 0.0; //denominator
- $numer = 0.0; //numerator
- $k = $itemID;
- $sql = "SELECT r.itemID, r.ratingValue
- FROM rating r WHERE r.userID=$userID AND r.itemID <> $itemID";
- $db_result = mysql_query($sql, $connection);
- //for all items the user has rated
- while ($row = mysql_fetch_assoc($db_result)) {
- $j = $row["itemID"];
- $ratingValue = $row["ratingValue"];
- //get the number of times k and j have both been rated by the same user
- $sql2 = "SELECT d.count, d.sum FROM dev d WHERE itemID1=$k AND itemID2=$j";
- $count_result = mysql_query($sql2, $connection);
- //skip the calculation if it isn't found
- if(mysql_num_rows($count_result) > 0) {
- $count = mysql_result($count_result, 0, "count");
- $sum = mysql_result($count_result, 0, "sum");
- //calculate the average
- $average = $sum / $count;
- //increment denominator by count
- $denom += $count;
- //increment the numerator
- $numer += $count * ($average + $ratingValue);
- }
- }
- if ($denom == 0)
- return 0;
- else
- return ($numer / $denom);
- }
- function predict_all($userID ) {
- $sql2 = "SELECT d.itemID1 as 'item', sum(d.count) as 'denom',
- sum(d.sum + d.count*r.ratingValue) as 'numer' FROM item i, rating r,
- dev d WHERE r.userID=$userID
- AND d.itemID1<>r.itemID
- AND d.itemID2=r.itemID GROUP BY d.itemID1";
- return mysql_query($sql2, $connection);
- }
Java:
- import java.util.*;
- /**
- * Daniel Lemire
- * A simple implementation of the weighted slope one
- * algorithm in Java for item-based collaborative
- * filtering.
- * Assumes Java 1.5.
- *
- * See main function for example.
- *
- * June 1st 2006.
- * Revised by Marco Ponzi on March 29th 2007
- */
- public class SlopeOne {
- public static void main(String args[]){
- // this is my data base
- Map<UserId,Map<ItemId,Float>> data = new HashMap<UserId,Map<ItemId,Float>>();
- // items
- ItemId item1 = new ItemId(" candy");
- ItemId item2 = new ItemId(" dog");
- ItemId item3 = new ItemId(" cat");
- ItemId item4 = new ItemId(" war");
- ItemId item5 = new ItemId("strange food");
- mAllItems = new ItemId[]{item1, item2, item3, item4, item5};
- //I'm going to fill it in
- HashMap<ItemId,Float> user1 = new HashMap<ItemId,Float>();
- HashMap<ItemId,Float> user2 = new HashMap<ItemId,Float>();
- HashMap<ItemId,Float> user3 = new HashMap<ItemId,Float>();
- HashMap<ItemId,Float> user4 = new HashMap<ItemId,Float>();
- user1.put(item1,1.0f);
- user1.put(item2,0.5f);
- user1.put(item4,0.1f);
- data.put(new UserId("Bob"),user1);
- user2.put(item1,1.0f);
- user2.put(item3,0.5f);
- user2.put(item4,0.2f);
- data.put(new UserId("Jane"),user2);
- user3.put(item1,0.9f);
- user3.put(item2,0.4f);
- user3.put(item3,0.5f);
- user3.put(item4,0.1f);
- data.put(new UserId("Jo"),user3);
- user4.put(item1,0.1f);
- //user4.put(item2,0.4f);
- //user4.put(item3,0.5f);
- user4.put(item4,1.0f);
- user4.put(item5,0.4f);
- data.put(new UserId("StrangeJo"),user4);
- // next, I create my predictor engine
- SlopeOne so = new SlopeOne(data);
- System.out.println("Here's the data I have accumulated...");
- so.printData();
- // then, I'm going to test it out...
- HashMap<ItemId,Float> user = new HashMap<ItemId,Float>();
- System.out.println("Ok, now we predict...");
- user.put(item5,0.4f);
- System.out.println("Inputting...");
- SlopeOne.print(user);
- System.out.println("Getting...");
- SlopeOne.print(so.predict(user));
- //
- user.put(item4,0.2f);
- System.out.println("Inputting...");
- SlopeOne.print(user);
- System.out.println("Getting...");
- SlopeOne.print(so.predict(user));
- }
- Map<UserId,Map<ItemId,Float>> mData;
- Map<ItemId,Map<ItemId,Float>> mDiffMatrix;
- Map<ItemId,Map<ItemId,Integer>> mFreqMatrix;
- static ItemId[] mAllItems;
- public SlopeOne(Map<UserId,Map<ItemId,Float>> data) {
- mData = data;
- buildDiffMatrix();
- }
- /**
- * Based on existing data, and using weights,
- * try to predict all missing ratings.
- * The trick to make this more scalable is to consider
- * only mDiffMatrix entries having a large (>1) mFreqMatrix
- * entry.
- *
- * It will output the prediction 0 when no prediction is possible.
- */
- public Map<ItemId,Float> predict(Map<ItemId,Float> user) {
- HashMap<ItemId,Float> predictions = new HashMap<ItemId,Float>();
- HashMap<ItemId,Integer> frequencies = new HashMap<ItemId,Integer>();
- for (ItemId j : mDiffMatrix.keySet()) {
- frequencies.put(j,0);
- predictions.put(j,0.0f);
- }
- for (ItemId j : user.keySet()) {
- for (ItemId k : mDiffMatrix.keySet()) {
- try {
- float newval = ( mDiffMatrix.get(k).get(j).floatValue() + user.get(j).floatValue() ) * mFreqMatrix.get(k).get(j).intValue();
- predictions.put(k, predictions.get(k)+newval);
- frequencies.put(k, frequencies.get(k)+mFreqMatrix.get(k).get(j).intValue());
- } catch(NullPointerException e) {}
- }
- }
- HashMap<ItemId,Float> cleanpredictions = new HashMap<ItemId,Float>();
- for (ItemId j : predictions.keySet()) {
- if (frequencies.get(j)>0) {
- cleanpredictions.put(j, predictions.get(j).floatValue()/frequencies.get(j).intValue());
- }
- }
- for (ItemId j : user.keySet()) {
- cleanpredictions.put(j,user.get(j));
- }
- return cleanpredictions;
- }
- /**
- * Based on existing data, and not using weights,
- * try to predict all missing ratings.
- * The trick to make this more scalable is to consider
- * only mDiffMatrix entries having a large (>1) mFreqMatrix
- * entry.
- */
- public Map<ItemId,Float> weightlesspredict(Map<ItemId,Float> user) {
- HashMap<ItemId,Float> predictions = new HashMap<ItemId,Float>();
- HashMap<ItemId,Integer> frequencies = new HashMap<ItemId,Integer>();
- for (ItemId j : mDiffMatrix.keySet()) {
- predictions.put(j,0.0f);
- frequencies.put(j,0);
- }
- for (ItemId j : user.keySet()) {
- for (ItemId k : mDiffMatrix.keySet()) {
- //System.out.println("Average diff between "+j+" and "+ k + " is "+mDiffMatrix.get(k).get(j).floatValue()+" with n = "+mFreqMatrix.get(k).get(j).floatValue());
- float newval = ( mDiffMatrix.get(k).get(j).floatValue() + user.get(j).floatValue() ) ;
- predictions.put(k, predictions.get(k)+newval);
- }
- }
- for (ItemId j : predictions.keySet()) {
- predictions.put(j, predictions.get(j).floatValue()/user.size());
- }
- for (ItemId j : user.keySet()) {
- predictions.put(j,user.get(j));
- }
- return predictions;
- }
- public void printData() {
- for(UserId user : mData.keySet()) {
- System.out.println(user);
- print(mData.get(user));
- }
- for (int i=0; i<mAllItems.length; i++) {
- System.out.print("\n" + mAllItems[i] + ":");
- printMatrixes(mDiffMatrix.get(mAllItems[i]), mFreqMatrix.get(mAllItems[i]));
- }
- }
- private void printMatrixes(Map<ItemId,Float> ratings,
- Map<ItemId,Integer> frequencies) {
- for (int j=0; j<mAllItems.length; j++) {
- System.out.format("%10.3f", ratings.get(mAllItems[j]));
- System.out.print(" ");
- System.out.format("%10d", frequencies.get(mAllItems[j]));
- }
- System.out.println();
- }
- public static void print(Map<ItemId,Float> user) {
- for (ItemId j : user.keySet()) {
- System.out.println(" "+ j+ " --> "+user.get(j).floatValue());
- }
- }
- public void buildDiffMatrix() {
- mDiffMatrix = new HashMap<ItemId,Map<ItemId,Float>>();
- mFreqMatrix = new HashMap<ItemId,Map<ItemId,Integer>>();
- // first iterate through users
- for(Map<ItemId,Float> user : mData.values()) {
- // then iterate through user data
- for(Map.Entry<ItemId,Float> entry: user.entrySet()) {
- if(!mDiffMatrix.containsKey(entry.getKey())) {
- mDiffMatrix.put(entry.getKey(), new HashMap<ItemId,Float>());
- mFreqMatrix.put(entry.getKey(), new HashMap<ItemId,Integer>());
- }
- for(Map.Entry<ItemId,Float> entry2: user.entrySet()) {
- int oldcount = 0;
- if(mFreqMatrix.get(entry.getKey()).containsKey(entry2.getKey()))
- oldcount = mFreqMatrix.get(entry.getKey()).get(entry2.getKey()).intValue();
- float olddiff = 0.0f;
- if(mDiffMatrix.get(entry.getKey()).containsKey(entry2.getKey()))
- olddiff = mDiffMatrix.get(entry.getKey()).get(entry2.getKey()).floatValue();
- float observeddiff = entry.getValue() - entry2.getValue();
- mFreqMatrix.get(entry.getKey()).put(entry2.getKey(),oldcount + 1);
- mDiffMatrix.get(entry.getKey()).put(entry2.getKey(),olddiff+observeddiff);
- }
- }
- }
- for (ItemId j : mDiffMatrix.keySet()) {
- for (ItemId i : mDiffMatrix.get(j).keySet()) {
- float oldvalue = mDiffMatrix.get(j).get(i).floatValue();
- int count = mFreqMatrix.get(j).get(i).intValue();
- mDiffMatrix.get(j).put(i,oldvalue/count);
- }
- }
- }
- }
- class UserId {
- String content;
- public UserId(String s) {
- content = s;
- }
- public int hashCode() { return content.hashCode();}
- public String toString() { return content; }
- }
- class ItemId {
- String content;
- public ItemId(String s) {
- content = s;
- }
- public int hashCode() { return content.hashCode();}
- public String toString() { return content; }
- }
Python:
- # Copyright 2006 Bryan O'Sullivan <bos@serpentine.com>.
- #
- # This software may be used and distributed according to the terms
- # of the GNU General Public License, version 2 or later, which is
- # incorporated herein by reference.
- class SlopeOne(object):
- def __init__(self):
- self.diffs = {}
- self.freqs = {}
- def predict(self, userprefs):
- preds, freqs = {}, {}
- for item, rating in userprefs.iteritems():
- for diffitem, diffratings in self.diffs.iteritems():
- try:
- freq = self.freqs[diffitem][item]
- except KeyError:
- continue
- preds.setdefault(diffitem, 0.0)
- freqs.setdefault(diffitem, 0)
- preds[diffitem] += freq * (diffratings[item] + rating)
- freqs[diffitem] += freq
- return dict([(item, value / freqs[item])
- for item, value in preds.iteritems()
- if item not in userprefs and freqs[item] > 0])
- def update(self, userdata):
- for ratings in userdata.itervalues():
- for item1, rating1 in ratings.iteritems():
- self.freqs.setdefault(item1, {})
- self.diffs.setdefault(item1, {})
- for item2, rating2 in ratings.iteritems():
- self.freqs[item1].setdefault(item2, 0)
- self.diffs[item1].setdefault(item2, 0.0)
- self.freqs[item1][item2] += 1
- self.diffs[item1][item2] += rating1 - rating2
- for item1, ratings in self.diffs.iteritems():
- for item2 in ratings:
- ratings[item2] /= self.freqs[item1][item2]
- if __name__ == '__main__':
- userdata = dict(
- alice=dict(squid=1.0,
- cuttlefish=0.5,
- octopus=0.2),
- bob=dict(squid=1.0,
- octopus=0.5,
- nautilus=0.2),
- carole=dict(squid=0.2,
- octopus=1.0,
- cuttlefish=0.4,
- nautilus=0.4),
- dave=dict(cuttlefish=0.9,
- octopus=0.4,
- nautilus=0.5),
- )
- s = SlopeOne()
- s.update(userdata)
- print s.predict(dict(squid=0.4))
=-========================== 延伸文章===========================
来源 : http://my.donews.com/clickstone/2006/10/16/fktEQWUckzvGDyfjugcqcJjkaDpdjemooGTf/
本文是关于推荐系统的系列研究文章之一,其他内容将陆续发布。这些内容,大多数来自我在2004年底完成的一篇项目方案建议书。放在这里,抛砖引玉,供大家讨论之用。
-------------------------------------------------
在推荐系统简介中,我们给出了推荐系统的一般框架。很明显,推荐方法是整个推荐系统中最核心、最关键的部分,很大程度上决定了推荐系统性能的优劣。目前,主要的推荐方法包括:基于内容推荐、协同过滤推荐、基于关联规则推荐、基于效用推荐、基于知识推荐和组合推荐。
一、基于内容推荐
基于内容的推荐(Content-based Recommendation)是信息过滤技术的延续与发展,它是建立在项目的内容信息上作出推荐的,而不需要依据用户对项目的评价意见,更多地需要用机 器学习的方法从关于内容的特征描述的事例中得到用户的兴趣资料。在基于内容的推荐系统中,项目或对象是通过相关的特征的属性来定义,系统基于用户评价对象 的特征,学习用户的兴趣,考察用户资料与待预测项目的相匹配程度。用户的资料模型取决于所用学习方法,常用的有决策树、神经网络和基于向量的表示方法等。 基于内容的用户资料是需要有用户的历史数据,用户资料模型可能随着用户的偏好改变而发生变化。
基于内容推荐方法的优点是:
1)不需要其它用户的数据,没有冷开始问题和稀疏问题。
2)能为具有特殊兴趣爱好的用户进行推荐。
3)能推荐新的或不是很流行的项目,没有新项目问题。
4)通过列出推荐项目的内容特征,可以解释为什么推荐那些项目。
5)已有比较好的技术,如关于分类学习方面的技术已相当成熟。
缺点是要求内容能容易抽取成有意义的特征,要求特征内容有良好的结构性,并且用户的口味必须能够用内容特征形式来表达,不能显式地得到其它用户的判断情况。
二、协同过滤推荐
协同过滤推荐(Collaborative Filtering Recommendation)技术是推荐系统中应用最早和最为成功的技术之一。它一般采用最近邻技术,利用用户的历史喜好信息计算用户之间的距离,然后 利用目标用户的最近邻居用户对商品评价的加权评价值来预测目标用户对特定商品的喜好程度,系统从而根据这一喜好程度来对目标用户进行推荐。协同过滤最大优 点是对推荐对象没有特殊的要求,能处理非结构化的复杂对象,如音乐、电影。
协同过滤是基于这样的假设:为一用户找到他真正感兴趣的内容的好方法是首先找到与此用户有相似兴趣的其他用户,然后将他们感兴趣的内容推荐给此用 户。其基本思想非常易于理解,在日常生活中,我们往往会利用好朋友的推荐来进行一些选择。协同过滤正是把这一思想运用到电子商务推荐系统中来,基于其他用 户对某一内容的评价来向目标用户进行推荐。
基于协同过滤的推荐系统可以说是从用户的角度来进行相应推荐的,而且是自动的,即用户获得的推荐是系统从购买模式或浏览行为等隐式获得的,不需要用户努力地找到适合自己兴趣的推荐信息,如填写一些调查表格等。
和基于内容的过滤方法相比,协同过滤具有如下的优点:
1) 能够过滤难以进行机器自动内容分析的信息,如艺术品,音乐等。
2) 共享其他人的经验,避免了内容分析的不完全和不精确,并且能够基于一些复杂的,难以表述的概念(如信息质量、个人品味)进行过滤。
3) 有推荐新信息的能力。可以发现内容上完全不相似的信息,用户对推荐信息的内容事先是预料不到的。这也是协同过滤和基于内容的过滤一个较大的差别,基于内容的过滤推荐很多都是用户本来就熟悉的内容,而协同过滤可以发现用户潜在的但自己尚未发现的兴趣偏好。
4) 能够有效的使用其他相似用户的反馈信息,较少用户的反馈量,加快个性化学习的速度。
虽然协同过滤作为一种典型的推荐技术有其相当的应用,但协同过滤仍有许多的问题需要解决。最典型的问题有稀疏问题(Sparsity)和可扩展问题(Scalability)。
三、基于关联规则推荐
基于关联规则的推荐(Association Rule-based Recommendation)是以关联规则为基础,把已购商品作为规则头,规则体为推荐对象。关联规则挖掘可以发现不同商品在销售过程中的相关性,在零 售业中已经得到了成功的应用。管理规则就是在一个交易数据库中统计购买了商品集X的交易中有多大比例的交易同时购买了商品集Y,其直观的意义就是用户在购 买某些商品的时候有多大倾向去购买另外一些商品。比如购买牛奶的同时很多人会同时购买面包。
算法的第一步关联规则的发现最为关键且最耗时,是算法的瓶颈,但可以离线进行。其次,商品名称的同义性问题也是关联规则的一个难点。
四、基于效用推荐
基于效用的推荐(Utility-based Recommendation)是建立在对用户使用项目的效用情况上计算的,其核心问题是怎么样为每一个用户去创建一个效用函数,因此,用户资料模型很大 程度上是由系统所采用的效用函数决定的。基于效用推荐的好处是它能把非产品的属性,如提供商的可靠性(Vendor Reliability)和产品的可得性(Product Availability)等考虑到效用计算中。
五、基于知识推荐
基于知识的推荐(Knowledge-based Recommendation)在某种程度是可以看成是一种推理(Inference)技术,它不是建立在用户需要和偏好基础上推荐的。基于知识的方法因 它们所用的功能知识不同而有明显区别。效用知识(Functional Knowledge)是一种关于一个项目如何满足某一特定用户的知识,因此能解释需要和推荐的关系,所以用户资料可以是任何能支持推理的知识结构,它可以 是用户已经规范化的查询,也可以是一个更详细的用户需要的表示。
六、组合推荐
由于各种推荐方法都有优缺点,所以在实际中,组合推荐(Hybrid Recommendation)经常被采用。研究和应用最多的是内容推荐和协同过滤推荐的组合。最简单的做法就是分别用基于内容的方法和协同过滤推荐方法 去产生一个推荐预测结果,然后用某方法组合其结果。尽管从理论上有很多种推荐组合方法,但在某一具体问题中并不见得都有效,组合推荐一个最重要原则就是通 过组合后要能避免或弥补各自推荐技术的弱点。
在组合方式上,有研究人员提出了七种组合思路:
1)加权(Weight):加权多种推荐技术结果。
2)变换(Switch):根据问题背景和实际情况或要求决定变换采用不同的推荐技术。
3)混合(Mixed):同时采用多种推荐技术给出多种推荐结果为用户提供参考。
4)特征组合(Feature combination):组合来自不同推荐数据源的特征被另一种推荐算法所采用。
5)层叠(Cascade):先用一种推荐技术产生一种粗糙的推荐结果,第二种推荐技术在此推荐结果的基础上进一步作出更精确的推荐。
6)特征扩充(Feature augmentation):一种技术产生附加的特征信息嵌入到另一种推荐技术的特征输入中。
7)元级别(Meta-level):用一种推荐方法产生的模型作为另一种推荐方法的输入。
七、主要推荐方法的对比
各种推荐方法都有其各自的优点和缺点,见表1。
|
表1 主要推荐方法对比 |
||
| 推荐方法 | 优点 | 缺点 |
| 基于内容推荐 | 推荐结果直观,容易解释;
不需要领域知识 |
新用户问题;
复杂属性不好处理; 要有足够数据构造分类器 |
| 协同过滤推荐 | 新异兴趣发现、不需要领域知识;
随着时间推移性能提高; 推荐个性化、自动化程度高; 能处理复杂的非结构化对象 |
稀疏问题;
可扩展性问题; 新用户问题; 质量取决于历史数据集; 系统开始时推荐质量差; |
| 基于规则推荐 | 能发现新兴趣点;
不要领域知识 |
规则抽取难、耗时;
产品名同义性问题; 个性化程度低; |
| 基于效用推荐 | 无冷开始和稀疏问题;
对用户偏好变化敏感; 能考虑非产品特性 |
用户必须输入效用函数;
推荐是静态的,灵活性差; 属性重叠问题; |
| 基于知识推荐 | 能把用户需求映射到产品上;
能考虑非产品属性 |
知识难获得;
推荐是静态的 |