一、背景介绍
互联网的迅猛发展将人类带入了信息社会和网络经济时代,信息化影响到了生活的方方面面。但是随着互联网产业的扩大,为用户提供更多选的同时也带来了筛选与推荐的难题。于是便提出了推荐算法帮助用户快速找到自己喜爱的东西。例如京东、淘宝、美团等,在用户购买物品后,均会给用户推荐他们可能喜欢的物品,不仅免去了用户不断查找类似物品的烦恼,而且也使得用户可以货比多家,最终找到自己物美价廉的商品,而相关的网站平台也可以提升自己的销量。电影推荐也是比较常见的,例如用户观看了阿甘正传,可能推荐给用户肖申克的救赎、当幸福来敲门等,推荐相关的应用数不胜数,但其核心就是相关的推荐算法的组合。
二、推荐算法相关介绍
目前有关个性化推荐算法主要分为三大类:1.基于协同过滤的推荐;2.基于内容过滤的推荐和3.社会化推荐。
本文主要讨论基于协同过滤的推荐,而该算法也可以划分为两类:
1.基于用户的协同过滤算法(UserCF)
该算法利用用户之间的相似性来推荐用户感兴趣的信息,个人通过合作的机制给予信息相当程度的回应(如评分)并记录下来以达到过滤的目的进而帮助别人筛选信息,回应不一定局限于特别感兴趣的,特别不感兴趣信息的纪录也相当重要。但有很难解决的两个问题,一个是稀疏性,即在系统使用初期由于系统资源还未获得足够多的评价,很难利用这些评价来发现相似的用户。另一个是可扩展性,随着系统用户和资源的增多,系统的性能会越来越差。
2.基于物品的协同过滤算法(ItemCF)
内容过滤根据信息资源与用户兴趣的相似性来推荐商品,通过计算用户兴趣模型和商品特征向量之间的向量相似性,主动将相似度高的商品发送给该模型的客户。由于每个客户都独立操作,拥有独立的特征向量,不需要考虑别的用户的兴趣,不存在评价级别多少的问题,能推荐新的项目或者是冷门的项目。这些优点使得基于内容过滤的推荐系统不受冷启动和稀疏问题的影响
三、基于物品的推荐算法以及流程
例如前面背景中介绍的,用户喜欢看阿甘正传,且给了高评分后,那么系统将会寻找与阿甘正传类似的电影推荐给用户。
- 算法流程
- 1.构建用户–>物品的倒排;
- 2.构建物品与物品的同现矩阵;
- 3.计算物品之间的相似度,即计算相似矩阵;
- 4.根据用户的历史记录,给用户推荐物品;
算法流程1
构建用户–>物品的倒排
如下表,行表示用户,列表示物品,1表示用户喜欢该物品
用户\物品 | a | b | c | d | e |
---|---|---|---|---|---|
A | 1 | 1 | 1 | ||
B | 1 | 1 | 1 | ||
C | 1 | 1 | |||
D | 1 | 1 | 1 | ||
E | 1 | 1 |
例如python构建的数据格式如下
{
'A': {'a': '1', 'b': '1', 'd': '1'},
'B': {'c': '1', 'b': '1', 'e': '1'},
'C': {'c': '1', 'd': '1'},
'D': {'c': '1', 'b': '1', 'd': '1'},
'E': {'a': '1', 'd': '1'}
}
算法流程2
构建物品与物品的同现矩阵
共现矩阵C表示同时喜欢两个物品的用户数,是根据用户物品倒排表计算出来的。如根据上面的用户物品倒排表可以计算出如下的共现矩阵C:
物品\物品 | a | b | c | d | e |
---|---|---|---|---|---|
a | 1 | 2 | |||
b | 1 | 2 | 2 | 1 | |
c | 2 | 2 | 1 | ||
d | 2 | 2 | 2 | ||
e | 1 | 1 |
算法流程3
计算物品之间的相似度,即计算相似矩阵
其中两个物品之间的相似度如何计算?
设|N(i)|表示喜欢物品i的用户数,|N(i)⋂N(j)|表示同时喜欢物品i,j的用户数,则物品i与物品j的相似度为:
wij=|N(i)⋂N(j)||N(i)|(1) (1) w i j = | N ( i ) ⋂ N ( j ) | | N ( i ) |
(1)式有一个问题,当物品j是一个很热门的商品时,人人都喜欢,那么 wij w i j 就会很接近于1,即(1)式会让很多物品都和热门商品有一个很大的相似度,所以可以改进一下公式:
wij=|N(i)⋂N(j)||N(i)||N(j)|√(2) (2) w i j = | N ( i ) ⋂ N ( j ) | | N ( i ) | | N ( j ) |
算法流程2中的共现矩阵C其实就是式(2)的分子,矩阵N(用于计算分母)表示喜欢某物品的用户数(是总的用户数),则(2)式中的分母便很容易求解出来了。
矩阵N如下所示:
物品 | a | b | c | d | e |
---|---|---|---|---|---|
用户数 | 2 | 3 | 3 | 4 | 1 |
利用式(2)便能计算物品之间的余弦相似矩阵如下:
物品\物品 | a | b | c | d | e |
---|---|---|---|---|---|
a | 0.41 | 0.71 | |||
b | 0.41 | 0.67 | 0.58 | 0.58 | |
c | 0.67 | 0.58 | 0.58 | ||
d | 0.71 | 0.58 | 0.58 | ||
e | 0.58 | 0.58 |
算法流程4
根据用户的历史记录,给用户推荐物品;
最终推荐的是什么物品,是由预测兴趣度决定的。
物品j预测兴趣度=用户喜欢的物品i的兴趣度×物品i和物品j的相似度
例如:A用户喜欢a,b,d ,兴趣度分别为1,1,1
- 推荐c的预测兴趣度=1X0.67+1X0.58=1.25
- 推荐e的预测兴趣度=1X0.58=0.58
四、python实现算法
1.数据描述
该数据为用户,兴趣度,物品
#用户,兴趣度,物品
uid_score_bid = ['A,1,a', 'A,1,b', 'A,1,d', 'B,1,b', 'B,1,c', 'B,1,e', 'C,1,c', 'C,1,d', 'D,1,b', 'D,1,c', 'D,1,d',
'E,1,a', 'E,1,d'];
2.python实现物品推荐
#!/usr/bin/python
# -*- coding: UTF-8 -*-
from math import sqrt
import operator
#1.构建用户-->物品的倒排
def loadData(files):
data ={};
for line in files:
user,score,item=line.split(",");
data.setdefault(user,{});
data[user][item]=score;
print "----1.用户:物品的倒排----"
print data
return data
#2.计算
# 2.1 构造物品-->物品的共现矩阵
# 2.2 计算物品与物品的相似矩阵
def similarity(data):
# 2.1 构造物品:物品的共现矩阵
N={};#喜欢物品i的总人数
C={};#喜欢物品i也喜欢物品j的人数
for user,item in data.items():
for i,score in item.items():
N.setdefault(i,0);
N[i]+=1;
C.setdefault(i,{});
for j,scores in item.items():
if j not in i:
C[i].setdefault(j,0);
C[i][j]+=1;
print "---2.构造的共现矩阵---"
print ('N:',N);
print ('C',C);
#2.2 计算物品与物品的相似矩阵
W={};
for i,item in C.items():
W.setdefault(i,{});
for j,item2 in item.items():
W[i].setdefault(j,0);
W[i][j]=C[i][j]/sqrt(N[i]*N[j]);
print "---3.构造的相似矩阵---"
print W
return W
#3.根据用户的历史记录,给用户推荐物品
def recommandList(data,W,user,k=3,N=10):
rank={};
for i,score in data[user].items():#获得用户user历史记录,如A用户的历史记录为{'a': '1', 'b': '1', 'd': '1'}
for j,w in sorted(W[i].items(),key=operator.itemgetter(1),reverse=True)[0:k]:#获得与物品i相似的k个物品
if j not in data[user].keys():#该相似的物品不在用户user的记录里
rank.setdefault(j,0);
rank[j]+=float(score) * w;
print "---4.推荐----"
print sorted(rank.items(),key=operator.itemgetter(1),reverse=True)[0:N];
return sorted(rank.items(),key=operator.itemgetter(1),reverse=True)[0:N];
if __name__=='__main__':
#用户,兴趣度,物品
uid_score_bid = ['A,1,a', 'A,1,b', 'A,1,d', 'B,1,b', 'B,1,c', 'B,1,e', 'C,1,c', 'C,1,d', 'D,1,b', 'D,1,c', 'D,1,d',
'E,1,a', 'E,1,d'];
data=loadData(uid_score_bid);#获得数据
W=similarity(data);#计算物品相似矩阵
recommandList(data,W,'A',3,10);#推荐
实验结果如下:
----1.用户:物品的倒排----
{'A': {'a': '1', 'b': '1', 'd': '1'}, 'C': {'c': '1', 'd': '1'}, 'B': {'c': '1', 'b': '1', 'e': '1'}, 'E': {'a': '1', 'd': '1'}, 'D': {'c': '1', 'b': '1', 'd': '1'}}
---2.构造的共现矩阵---
('N:', {'a': 2, 'c': 3, 'b': 3, 'e': 1, 'd': 4})
('C', {'a': {'b': 1, 'd': 2}, 'c': {'b': 2, 'e': 1, 'd': 2}, 'b': {'a': 1, 'c': 2, 'e': 1, 'd': 2}, 'e': {'c': 1, 'b': 1}, 'd': {'a': 2, 'c': 2, 'b': 2}})
---3.构造的相似矩阵---
{'a': {'b': 0.4082482904638631, 'd': 0.7071067811865475}, 'c': {'b': 0.6666666666666666, 'e': 0.5773502691896258, 'd': 0.5773502691896258}, 'b': {'a': 0.4082482904638631, 'c': 0.6666666666666666, 'e': 0.5773502691896258, 'd': 0.5773502691896258}, 'e': {'c': 0.5773502691896258, 'b': 0.5773502691896258}, 'd': {'a': 0.7071067811865475, 'c': 0.5773502691896258, 'b': 0.5773502691896258}}
---4.推荐----
[('c', 1.2440169358562925), ('e', 0.5773502691896258)]
五、电影推荐应用小案例
1.电影数据描述
电影数据很多,在此示范下基于物品的电影推荐,数据为基于用户--->电影的倒排,数据如下
data = {'Lisa Rose': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.5,
'Just My Luck': 3.0, 'Superman Returns': 3.5, 'You, Me and Dupree': 2.5,
'The Night Listener': 3.0},
'Gene Seymour': {'Lady in the Water': 3.0, 'Snakes on a Plane': 3.5,
'Just My Luck': 1.5, 'Superman Returns': 5.0, 'The Night Listener': 3.0,
'You, Me and Dupree': 3.5},
'Michael Phillips': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.0,
'Superman Returns': 3.5, 'The Night Listener': 4.0},
'Claudia Puig': {'Snakes on a Plane': 3.5, 'Just My Luck': 3.0,
'The Night Listener': 4.5, 'Superman Returns': 4.0,
'You, Me and Dupree': 2.5},
'Mick LaSalle': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0,
'Just My Luck': 2.0, 'Superman Returns': 3.0, 'The Night Listener': 3.0,
'You, Me and Dupree': 2.0},
'Jack Matthews': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0,
'The Night Listener': 3.0, 'Superman Returns': 5.0, 'You, Me and Dupree': 3.5},
'Toby': {'Snakes on a Plane': 4.5, 'You, Me and Dupree': 1.0, 'Superman Returns': 4.0}
}
2.推荐
推荐过程和上面的代码过程一样,仅不用构造倒排数据
#!/usr/bin/python
# -*- coding: UTF-8 -*-
from math import sqrt
import operator
#1.构建用户-->物品的倒排(此推荐无需使用)
def loadData(files):
data ={};
for line in files:
user,score,item=line.split(",");
data.setdefault(user,{});
data[user][item]=score;
print "----1.用户:物品的倒排----"
print data
return data
#2.计算
# 2.1 构造物品-->物品的共现矩阵
# 2.2 计算物品与物品的相似矩阵
def similarity(data):
# 2.1 构造物品:物品的共现矩阵
N={};#喜欢物品i的总人数
C={};#喜欢物品i也喜欢物品j的人数
for user,item in data.items():
for i,score in item.items():
N.setdefault(i,0);
N[i]+=1;
C.setdefault(i,{});
for j,scores in item.items():
if j not in i:
C[i].setdefault(j,0);
C[i][j]+=1;
print "---2.构造的共现矩阵---"
print ('N:',N);
print ('C',C);
#2.2 计算物品与物品的相似矩阵
W={};
for i,item in C.items():
W.setdefault(i,{});
for j,item2 in item.items():
W[i].setdefault(j,0);
W[i][j]=C[i][j]/sqrt(N[i]*N[j]);
print "---3.计算的相似矩阵---"
print W
return W
#3.根据用户的历史记录,给用户推荐物品
def recommandList(data,W,user,k=3,N=10):
rank={};
for i,score in data[user].items():#获得用户user历史记录,如A用户的历史记录为{'a': '1', 'b': '1', 'd': '1'}
for j,w in sorted(W[i].items(),key=operator.itemgetter(1),reverse=True)[0:k]:#获得与物品i相似的k个物品
if j not in data[user].keys():#该相似的物品不在用户user的记录里
rank.setdefault(j,0);
rank[j]+=float(score) * w;
print "---3.推荐----"
print sorted(rank.items(),key=operator.itemgetter(1),reverse=True)[0:N];
return sorted(rank.items(),key=operator.itemgetter(1),reverse=True)[0:N];
if __name__=='__main__':
print "---1.构造数据---"
data = {'Lisa Rose': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.5,
'Just My Luck': 3.0, 'Superman Returns': 3.5, 'You, Me and Dupree': 2.5,
'The Night Listener': 3.0},
'Gene Seymour': {'Lady in the Water': 3.0, 'Snakes on a Plane': 3.5,
'Just My Luck': 1.5, 'Superman Returns': 5.0, 'The Night Listener': 3.0,
'You, Me and Dupree': 3.5},
'Michael Phillips': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.0,
'Superman Returns': 3.5, 'The Night Listener': 4.0},
'Claudia Puig': {'Snakes on a Plane': 3.5, 'Just My Luck': 3.0,
'The Night Listener': 4.5, 'Superman Returns': 4.0,
'You, Me and Dupree': 2.5},
'Mick LaSalle': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0,
'Just My Luck': 2.0, 'Superman Returns': 3.0, 'The Night Listener': 3.0,
'You, Me and Dupree': 2.0},
'Jack Matthews': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0,
'The Night Listener': 3.0, 'Superman Returns': 5.0, 'You, Me and Dupree': 3.5},
'Toby': {'Snakes on a Plane': 4.5, 'You, Me and Dupree': 1.0, 'Superman Returns': 4.0}
}
W=similarity(data);#计算物品相似矩阵
recommandList(data,W,'Toby',10,10);#推荐
推荐结果:
---1.构造数据---
---2.构造的共现矩阵---
('N:', {'Lady in the Water': 5, 'Snakes on a Plane': 7, 'Just My Luck': 4, 'Superman Returns': 7, 'The Night Listener': 6, 'You, Me and Dupree': 6})
('C', {'Lady in the Water': {'Snakes on a Plane': 5, 'Just My Luck': 3, 'The Night Listener': 5, 'Superman Returns': 5, 'You, Me and Dupree': 4}, 'Snakes on a Plane': {'Lady in the Water': 5, 'Just My Luck': 4, 'The Night Listener': 6, 'Superman Returns': 7, 'You, Me and Dupree': 6}, 'Just My Luck': {'Lady in the Water': 3, 'Snakes on a Plane': 4, 'The Night Listener': 4, 'Superman Returns': 4, 'You, Me and Dupree': 4}, 'Superman Returns': {'Lady in the Water': 5, 'Snakes on a Plane': 7, 'The Night Listener': 6, 'Just My Luck': 4, 'You, Me and Dupree': 6}, 'The Night Listener': {'Lady in the Water': 5, 'Snakes on a Plane': 6, 'Just My Luck': 4, 'Superman Returns': 6, 'You, Me and Dupree': 5}, 'You, Me and Dupree': {'Lady in the Water': 4, 'Snakes on a Plane': 6, 'Just My Luck': 4, 'Superman Returns': 6, 'The Night Listener': 5}})
---3.计算的相似矩阵---
{'Lady in the Water': {'Snakes on a Plane': 0.8451542547285166, 'Just My Luck': 0.6708203932499369, 'You, Me and Dupree': 0.7302967433402214, 'Superman Returns': 0.8451542547285166, 'The Night Listener': 0.9128709291752769}, 'Snakes on a Plane': {'Lady in the Water': 0.8451542547285166, 'Just My Luck': 0.7559289460184544, 'You, Me and Dupree': 0.9258200997725514, 'Superman Returns': 1.0, 'The Night Listener': 0.9258200997725514}, 'Just My Luck': {'Lady in the Water': 0.6708203932499369, 'Snakes on a Plane': 0.7559289460184544, 'You, Me and Dupree': 0.8164965809277261, 'Superman Returns': 0.7559289460184544, 'The Night Listener': 0.8164965809277261}, 'Superman Returns': {'Lady in the Water': 0.8451542547285166, 'Snakes on a Plane': 1.0, 'Just My Luck': 0.7559289460184544, 'You, Me and Dupree': 0.9258200997725514, 'The Night Listener': 0.9258200997725514}, 'You, Me and Dupree': {'Lady in the Water': 0.7302967433402214, 'Snakes on a Plane': 0.9258200997725514, 'Just My Luck': 0.8164965809277261, 'Superman Returns': 0.9258200997725514, 'The Night Listener': 0.8333333333333334}, 'The Night Listener': {'Lady in the Water': 0.9128709291752769, 'Snakes on a Plane': 0.9258200997725514, 'Just My Luck': 0.8164965809277261, 'Superman Returns': 0.9258200997725514, 'You, Me and Dupree': 0.8333333333333334}}
---4.推荐----
[('The Night Listener', 8.70280418140002), ('Lady in the Water', 7.914107908532612), ('Just My Luck', 7.241892622084588)]