上一讲讲到userCF算法,该算法是根据用户之间相似度,来给目标用户推荐与他们相似用户产生过行为的物品。该算法在某些应用场景并不适用。首先随着网站用户数目越来越大,计算用户兴趣相似矩阵越来越困难,运算时间复杂度和空间复杂度和用户增长近似于平方关系。其次,基于用户的协同过滤很难对推荐结果作出解释。

由此产生了基于物品的协同过滤(itemCF)给用户推荐和他们之前喜欢的物品相似的物品。不过ItemCF算法不是根据物品内容属性计算物品之间相似度,它主要通过分析用户的行为记录来计算物品之间的相似度。

基于物品的协同过滤算法主要分为两步。
①:计算物品之间的相似度
②:根据物品之间相似度和用户的历史行为给用户生产推荐列表。

根据定义可以用以下公式计算物品相似度:

N(i)表示喜欢物品i的用户列表,N(j)表示喜欢物品j的用户列表。上述公式可以理解成喜欢物品i的用户里有多少喜欢物品j。 
 但是有一个问题,如果物品j是个热门物品呢?大家都喜欢。那么上面公式岂不是接近1?因此该公式会造成任何物品都和热门物品有很大的相似性,对于致力于挖掘长尾信息来说不是一件好特性。为避免推荐出热门物品可以用下面公式: 

上面公式惩罚了物品j的权重,因此减轻了热门物品和很多物品的相似性。 
 在实际计算物品相似度时,先建立用户—>物品的倒排表(即对每个用户建立一个包含他喜欢的物品列表),然后对于每个用户,将它的物品列表里面的物品两两在共现矩阵C中加1。

得到物品相似度以后,ItemCF通过如下公式计算用户u对一物品j的兴趣: 

这里N(u)表示用户u喜欢的物品列表,S(j,k)表示和物品j最为相似的k个物品,Wji表示物品j和物品i的相似度。

表示用户u的历史兴趣物品列表中与物品j最为相似的k个物品。 
rui表示用户u对物品i的喜欢程度(对于隐反馈数据,如果用户u对物品i产生过行为,则Rui=1),该公式的含义就是,和用户历史感兴趣的物品越相似的物品越有可能在用户推荐列表获得比较高的排名。

ItemCF算法在各个评测指标上的表现: 
①精度(准确率和召回率):不和k的选取成正相关或者负相关,因此选择合适的k对获得最高精度非常重要。 
②流行度(降低新颖度即提高流行度):和userCF不同,ItemCF推荐结果流行度影响不是完全受k影响,随着k增加,流行度会逐渐提高,但当k提高到一定程度,流行度就不会再有变化。 
③覆盖率:k增加会降低系统的覆盖率。

用户活跃度对物品相似度的影响:活跃用户对物品的相似度的贡献应该小于不活跃的用户,应该增加IUf参数来修正物品相似度的计算公式: 

将上面的算法记为itemCF-IUF,不考虑参数K的影响(即固定K),itemCF-IUF对比iemCF提高了覆盖率,降低了推荐系统的流行度,整体性能有提升

物品相似度归一化:如果将ItemCF的相似度矩阵按最大值归一化,可以提高推荐的准确率,如果得到物品的相似度矩阵,那么可以使用如下公式得到归一化之后相似度:

归一化的好处不仅仅在于增加推荐的准确率还提高了推荐的覆盖率和多样性。 
下面举例说明为何归一化后结果好些: 
假设物品分为两类A和B,A类内的物品相似度为0.5,B类内的物品相似度为0.6,而A类和B类之间的物品相似度为0.2.在这种情况下如果用户历史上喜欢5件A物品,喜欢5件B物品,用ItemCF给他进行推荐,推荐的就全部都是B物品,因为B类物品相似度较高。但如果归一化后,A类物品相似度为1,B类的物品相似度也为1,那么这种情况下,用户如果喜欢5个A类物品和5个B类物品,那么给他推荐的A类物品和B类物品数目应该大致相等,从这个例子来看,相似度的归一化可以提高多样性。

一般来说,热门的类其类内的物品相似度较高,如果不进行归一化,就会推荐比较热门的物品。
UseCF和ItemCF比较:

UserCF给用户推荐那些和他相似用户喜欢的物品;ItemCF给用推荐和他之前喜欢的物品相似的物品。可以看出,UserCF推荐结果着重反映和用户兴趣相似的小群体的热点;而ItemCF推荐结果着重于维系用户的历史兴趣。UserCF更加社会化而ItemCF更加个性化
个性化新闻推荐:UserCF可以给用户推荐和他相似爱好的一群其他用户今天都在看的新闻,这样抓住热点和时效性的同时,保证了一定程度的个性化。从技术方面考虑,作为一种物品,新闻更新速度快,ItemCF需要维护一张物品的相关度的表,技术上很难实现。 
在电子商务,图书电影网站等:ItemCF能发挥极大优势,对这些网站来说,用户的兴趣比较固定和持久。而且物品的更新速度不是很快,一天跟新一次物品相似度矩阵损失不会太大。 
总而言之,USerCF需要维护一个用户相似度的矩阵,而ItemCF需要维护一个物品相似度矩阵,从存储角度来说,如果用户很多,那么维护用户兴趣相似度矩阵需要很大空间,同理,如果物品很多,那么维护物品相似度矩阵代价很大。

再来分析一下为什么原始ItemCF算法覆盖度和新颖度都不高:
哈利波特问题:设计ItemCF之初发现ItemCf算法计算出图书相关表时存在一个问题,就是很多书都和《哈利波特》相关。也就是说购买一本书的人都有可能购买《哈利波特》这本书,主要是因为《哈利波特》太热门了。
回归下ItemCF计算物品相似度的经典公式:

分母里面的N(j)用来惩罚热门的j,但在实际应用中,热门的j任然会获得较高的相似度。
为此我们可以在分母中加大对热门j的惩罚力度。

通过实验得知:只有a=0.5时才会有较高的准确率和召回率,但是a越大,覆盖率越高,并且结果的平均热门程度会降低。因此这种办法可以通过在适当牺牲准确率和召回率的情况下提升结果的覆盖率和新颖度。 
两个不同热门物品类,即使不属于一种类,但是因为用户经常同时购买他们,许多用户历史兴趣物品列表里都含有这两种不同的热门类物品,这就导致ItemCF计算这两种不同类的物品相似度的结果很高。这个时候仅仅依靠用户行为是不能解决这个问题的。

#coding:utf-8import random
import math
from numpy import *
import csv
import datetimeNumOfItems=1690def GetData(datafile='u.data'):'''把datafile文件中数据读出来,返回data对象:param datafile: 数据源文件名称:return: 一个列表,每一个元素是一个元组(userId,movieId)'''data=[]try:file=open(datafile)except:print ("No such file name"+datafile)for line in file:line=line.split('\t')try:data.append((int(line[0]),int(line[1])))except:passfile.close()return datadef SplitData(data,M,k,seed):'''划分训练集和测试集:param data:传入的数据:param M:测试集占比:param k:一个任意的数字,用来随机筛选测试集和训练集:param seed:随机数种子,在seed一样的情况下,其产生的随机数不变:return:train:训练集 test:测试集,都是字典,key是用户id,value是电影id集合'''test=dict()train=dict()random.seed(seed)# 在M次实验里面我们需要相同的随机数种子,这样生成的随机序列是相同的for user,item in data:if random.randint(0,M)!=k:# 相等的概率是1/M,所以M决定了测试集在所有数据中的比例# 选用不同的k就会选定不同的训练集和测试集if user not in test.keys():test[user]=set()test[user].add(item)else:if user not in train.keys():train[user]=set()train[user].add(item)return train,testdef Recall(train,test,N,k,W,relateditems,k_similar):''':param train: 训练集:param test: 测试集:param N: TopN推荐中N数目:param k::return:返回召回率'''hit=0# 预测准确的数目totla=0# 所有行为总数for user in train.keys():tu=test[user]rank=GetRecommendation(user,train,W,relateditems,k,N,k_similar)for item in rank:if item in tu:hit+=1totla+=len(tu)return hit/(totla*1.0)def Precision(train,test,N,k,W,relateditems,k_similar):''':param train::param test::param N::param k::return:'''hit=0total=0for user in train.keys():tu = test[user]rank = GetRecommendation(user,train,W,relateditems,k,N,k_similar)for item in rank:if item in tu:hit += 1total += Nreturn hit / (total * 1.0)def Coverage(train,test,N,k,W,relateditems,k_similar):'''计算覆盖率:param train:训练集 字典user->items:param test: 测试机 字典 user->items:param N: topN推荐中N:param k::return:覆盖率'''recommend_items=set()all_items=set()for user in train.keys():for item in train[user]:all_items.add(item)rank=GetRecommendation(user,train,W,relateditems,k,N,k_similar)for item in rank:recommend_items.add(item)return len(recommend_items)/(len(all_items)*1.0)def Popularity(train,test,N,k,W,relateditems,k_similar):'''计算平均流行度:param train:训练集 字典user->items:param test: 测试机 字典 user->items:param N: topN推荐中N:param k::return:覆盖率'''item_popularity=dict()for user,items in train.items():for item in items:if item not in item_popularity:item_popularity[item]=0item_popularity[item]+=1ret=0n=0for user in train.keys():rank= GetRecommendation(user,train,W,relateditems,k,N,k_similar)for item in rank:if item!=0:ret+=math.log(1+item_popularity[item])n+=1ret/=n*1.0return retdef getW(train):#train本身已经是用户->物品倒排表#W[u][v]表示物品u和物品v的相似度W=zeros([NumOfItems,NumOfItems],dtype=float16)#C[u][v]表示喜欢u有喜欢v物品的用户有多少个C=zeros([NumOfItems,NumOfItems],dtype=float16)#N[u]表示有多少用户喜欢物品uN=zeros([NumOfItems],dtype=float16)item_relateditems=dict()for user,items in train.items():for item1 in items:N[item1]+=1for item2 in items:if item1==item2:continueif item1 not in item_relateditems:item_relateditems[item1]=set()item_relateditems[item1].add(item2)C[item1][item2]+=(1/math.log(1+len(items)*1.0))for item1 in range(1,NumOfItems):if item1 in item_relateditems:for item2 in item_relateditems[item1]:W[item1][item2]=C[item1][item2]/sqrt(N[item1]*N[item2])return W,item_relateditemsdef k_similar_item(W,item_relateditems,k):''':param W::param item_relateditems::param k::return:返回一个字典,key是每个item,value是item对应的k个最相似的物品'''begin=datetime.datetime.now()k_similar=dict()for i in range(1,NumOfItems):relateditems=dict()try:for x in item_relateditems[i]:relateditems[x]=W[i][x]relateditems=sorted(relateditems.items(),key=lambda x:x[1],reverse=True)k_similar[i]=set(dict(relateditems[0:k]))#返回k个与物品i最相似的物品except KeyError:print(i, " doesn't have any relateditems")k_similar[i]=set()for x in range(1,k+1):k_similar[i].add(x)end=datetime.datetime.now()print("it takes ", (end - begin).seconds, " seconds to get k_similar_item for all items.")return k_similardef GetRecommendation(user,train,W,relateditems,k,N,k_similar_items):''':param user: 目标用户:param train: 训练集 字典user->items:param W: 物品相似度矩阵:param relateditems: 字典 items->相关item:param k: 从目标用户历史兴趣列表中选取k个与推荐item最为相似的物品:param N: 给目标用户推荐N个物品:param k_similar_items: 一个字典,key是每个item,value是item对应的k个最相似的物品:return:'''rank=dict()#key是电影id,value是兴趣大小for  i in range(NumOfItems):rank[i]=0possible_recommend=set()for item in train[user]:##返回训练集中和目标用户历史兴趣物品相似度不为0的物品itempossible_recommend=possible_recommend.union(relateditems[item])for item in possible_recommend:k_items=k_similar_items[item]#返回与item最为相似的k个物品for i in k_items:if i in train[user]:#且返回的k个物品必须在目标用户历史兴趣物品列表里rank[item]+=1.0*W[item][i]##rank字典,key是itemId,value是用户user对这个推荐的itemId的兴趣程度,前提是这个item不能出现在用户user历史兴趣物品列表里for rank_key in rank:if rank_key in train[user]:##如果推荐的item出现在用户历史兴趣物品列表里,则赋值0rank[rank_key]=0#按照用户user对推荐的item兴趣程度,从大到小排序,推荐N个物品return dict(sorted(rank.items(),key=lambda x:x[1],reverse=True)[0:N])def evaluate(train,test,N,k):##计算一系列评测标准recommends=dict()W,relateditems=getW(train)k_similar = k_similar_item(W, relateditems, k)for user in test:recommends[user]=GetRecommendation(user,train,W,relateditems,k,N,k_similar)recall=Recall(train,test,N,k,W,relateditems,k_similar)precision=Precision(train,test,N,k,W,relateditems,k_similar)coverage=Coverage(train,test,N,k,W,relateditems,k_similar)popularity=Popularity(train,test,N,k,W,relateditems,k_similar)return recall,precision,coverage,popularitydef test2():N=int(input("input the number of recommendations: \n"))k=int(input("input the number of related items: \n"))data=GetData()train,test=SplitData(data,2,1,1)del datarecall,precision,coverage,popularity=evaluate(train,test,N,k)print("Recall: ",recall)print("Precision: ",precision)print("Coverage: ",coverage)print("Popularity: ",popularity)if __name__=='__main__':test2()

推荐系统之itemCF相关推荐

  1. 第10课:动手实战基于 CNN 的电影推荐系统

    本文从深度学习卷积神经网络入手,基于 Github 的开源项目来完成 MovieLens 数据集的电影推荐系统. 什么是推荐系统呢? 什么是推荐系统呢?首先我们来看看几个常见的推荐场景. 如果你经常通 ...

  2. 大数据学习路线copy自淘宝

    一.hadoop视频学习(入门到精通) 二.数据挖掘(入门到精通) 三.Hadoop学习路线 1.开发前期准备 首先,如果你没有Java和Linux基础,建议你先简单学一下这两门课程,此宝贝里面都为你 ...

  3. 推荐模型是怎样由窄变宽、越变越深的?

    星标/置顶小屋,带你解锁 最萌最前沿的NLP.搜索与推荐技术 文 | 邢智皓 编 | 兔子酱 当前,深度学习推荐模型已经成功应用于推荐.广告.搜索等领域,但在了解它之前,简单回顾传统推荐模型仍是有必要 ...

  4. 【推荐系统】手写ItemCF/UserCF代码,你会吗?

    前言 之前朋友说有同学在面字节算法实习时让复现DeepFM算法(包括训练),然后就懵了.因此最近在整理传统推荐算法的一些内容时,大概是这样的: 就想到「基于邻域的协同过滤(UserCF与ItemCF) ...

  5. 【推荐系统(一)】协同过滤之基于领域的方法(UserCF,ItemCF)

    文章目录 一.基于用户的协同过滤算法(UserCF) 1,找到相似用户 2,推荐未接触过的物品 UserCF 改进 二.基于物品的协同过滤算法(ItemCF) 1,物品相似度计算 2,推荐列表计算 I ...

  6. 推荐系统(2)-协同过滤1-UserCF、ItemCF

    协同过滤 1.CF概述 2.数据表示 3.衡量相似度 4.共现矩阵 5.UserCF 6.ItemCF 7.UserCF 与ItemCF 应用场景.主要缺陷 8.基于UserCF 电影推荐demo & ...

  7. 《推荐系统笔记(十七)》userCF和itemCF —— 基于领域的推荐

    面对用户-物品评分矩阵,我们有一种推荐思路,叫做基于领域的推荐. 什么是itemCF和userCF?可以这样理解, 我喜欢这个商品,那么和这个商品非常类似的其他商品,可能也是我喜欢的,这个是itemC ...

  8. 大数据-实时推荐系统最主流推荐系统itemCF和userCF视频教程下载

    大数据-实时推荐系统最主流推荐系统itemCF和userCF视频教程下载38套大数据,云计算,架构,数据分析师,Hadoop,Spark,Storm,Kafka,人工智能,机器学习,深度学习,项目实战 ...

  9. 推荐系统召回之itemCF

    基于物品的协同过滤算法itemCF 基本思想 该算法向用户推荐与他们之间喜欢的物品相似的其它物品,例如,如果你购买过<数据挖掘导论>,会向你推荐<机器学习>. itemCF算法 ...

  10. 推荐系统学习(二)--UserCF与ItemCF推荐算法

    文章目录 基于近邻的推荐算法 UserCF算法原理 1. 构建用户物品评分表 2. 相似度度量 3. 计算推荐结果 4. 惩罚热门物品 ItemCF算法原理 1. 计算物品之间的相似度 1. 建立用户 ...

最新文章

  1. 趣谈 23 种设计模式(多图 + 代码)
  2. 轻松入门模型转换和可视化
  3. arcgis ERROR:000824 该工具未获得许可
  4. 信用卡逾期三个月以上不还?小心坐牢!
  5. java程序猿面试问缺点怎么回答_JAVA程序员面试32问,你能回答多少题
  6. Java 算法 复数求和
  7. 编译原理完整学习笔记(三):词法分析
  8. 5G协议学习(38.300-总体描述)
  9. html设置ie9兼容性视图,ie9兼容性设置在哪里 IE兼容性视图在哪里设置?
  10. matlab解一元三次方程组,如何用matlab求解一元高次方程
  11. SkeyeVSS综合安防视频云服务提供网页无插件直播、录像、检索、回放、报警综合解决方案
  12. 再来学习一下“八荣八耻”
  13. 【代码猴子-培养正确的编程态度和方法】--《编程匠艺》
  14. 惠普M1136 MFP激光打印机打印整张纸全黑
  15. isNaN、Number.isNaN、isFinite、Number.isFinite
  16. weblogic-cve_2020_2883漏洞复现
  17. Advanced Practices:一款新型恶意监测工具的改进过程
  18. java随机生成中文昵称_Java 中文姓名随机生成
  19. jquery 获取父级元素、子级元素、兄弟元素的方法
  20. 基于网页可信特征的信息可信度评估方法(IEEE2011)

热门文章

  1. Ubuntu下安装网易有道词典
  2. 螺旋分级机与水力分级机间的优缺点
  3. 硬盘服务器哪个好用吗,服务器用固态硬盘好还是机械硬盘好
  4. 微服务可用性设计(二):过载保护,限流
  5. RS触发器、D触发器、JK触发器、T,T‘触发器的功能详细总结
  6. 旋转的描述【2】——等效旋转矢量与四元数
  7. Java顺序结构综合练习三之金融投资收益计算
  8. 分析入门股票量化交易券商接口的方法
  9. php股票量化交易接口有什么优势?
  10. 梦幻服务器最新开服时间,梦幻服务器开区及合服时间汇总查询(2)