一、背景介绍
当我们浏览某些购物软件或者刷一些短视频软件时,经常会遇见一些弹窗,去推荐你喜欢的一些东西。这就涉及到我们一会要学习的内容:推荐系统—协同过滤。
协同过滤在我们的日常生活之中无处不在,例如,在电子商城购物中,系统会根据用户的记录或者用户的浏览和点击等信息来推荐相应的产品给客户,是一种较为主流的推荐方式。
二、 算法简介
2.1 算法概述
协同过滤(Collaborative Filtering,简写CF) 简单来说就是根据已有数据来推测未知的数据的一种算法。在推荐系统中协同过滤算法一般是指在海量用户中发掘一小部分和你品味比较类似的。在协同过滤中这些用户成为你的邻居,从而为你推荐商品。基于启发式的协同过滤算法可以分为基于用户的协同过滤算法(User-Based)和基于项目的协同过滤算法(Item-Based)。
2.2算法核心和原理
协同过滤算法核心步骤如下:
1)收集用户偏好;
2)找到相似的用户或物品;
3)计算并推荐。
三、基于用户的协同过滤算法(User-Based)
3.1相似度及预测值的计算
基于用户的算法是用户对物品的评分不同,对不同的物品的评分去比较不同用户之间的相似度, 找到一些邻居,并对没有购买其他物品的用户推荐该物品。
例:A用户对物品a评分5分,对物品b评分4分,B用户对物品a评分3.8分,对物品b评分4.2分,但C用户只对a物品有评价,对b物品没有评价。所以就根据用户A和B去预测用户C对物品b的预测评分,并向用户c推荐物品b。
在基于用户的系统过滤算法中,我们主要分为两步。
一,计算两个用户间的相似度。
二,对于未评分的用户去预测他对于这个物品的评分
3.2.1相似度计算
在协同过滤中,一个重要的环节就是如何选择合适的相似度计算方法,常用的相似度计算方法包括皮尔逊相关系数等。
注:在这里我们采用皮尔逊相似度算法
皮尔逊相关系数的计算公式如下所示:
其中,i 表示项,例如商品;I
u
_{u}
u 表示用户 u 评价的项集;I
v
_{v}
v 表示用户 v 评价的项集;r
u
,
i
_{u,i}
u,i表示用户 u 对项 i 的评分;r
v
,
i
_{v,i}
v,i表示用户 v 对项 i 的评分;
r
ˉ
u
\bar{r}_{u}
rˉu表示用户 u 的平均评分;
r
ˉ
v
\bar{r}_{v}
rˉv表示用户 v 的平均评分。
3.2.2 预测值的计算
另一个重要的环节就是计算用户 u 对未评分商品的预测分值。
首先根据上一步中 的相似度计算,寻找用户 u 的邻居集 N∈U,其中 N 表示邻居集,U 表示用户集。 然后结合用户评分数据集,预测用户 u 对项 i 的评分,计算公式如下所示:
其中,s(u,u’)表示用户 u 和用户 u’的相似度。
3.3通过例子理解
假设有如下电子商务评分数据集,预测用户 C 对商品 4 的评分。
表3-1 电子商务评分数据集
表中 ?表示评分未知。根据基于用户的协同过滤算法步骤,计算用户 C 对商品 4 的评分,其步骤如下所示。
(1)寻找用户 C 的邻居 从数据集中可以发现,只有用户 A 和用户 D 对商品 4 评过分,因此候选邻居只 有 2 个,分别为用户 A 和用户 D。用户 A 的平均评分为 4,用户 C 的平均评分为 3.667,用户 D 的平均评分为 3。
根据皮尔逊相关系数公式:
红色区域计算 C 用户与 A 用户,用户 C 和用户 A 的相似度为:
蓝色区域计算 C 用户与 D 用户的相似度为:
(2)预测用户 C 对商品 4 的评分 根据上述评分预测公式,计算用户 C 对商品 4 的评分,如下所示: 用户 C 对商品 4 的评分
依此类推,可以计算出其他未知的评分。
3.4演算手稿
结论:通过计算,可得s(M,N)=s(N,M)(其中M,N为用户名)
通过得到的预测值可以补全未知数据,如图表4-1所示
表4-1 电子商务评分数据集
3.5python代码实现
本算法采用皮尔逊相关系数实现协同过滤
#!/usr/bin/python
-- coding: UTF-8 --
'''
基于用户的推荐算法
'''
from math import sqrt,pow
import operator
class UserCf():
#获得初始化数据
def __init__(self,data):
self.data=data;
#通过用户名获得电影列表,仅调试使用
def getItems(self,username1,username2):
return self.data[username1],self.data[username2]
#计算两个用户的皮尔逊相关系数
def pearson(self,user1,user2):#数据格式为:电影,评分 {'Snakes on a Plane': 4.5, 'You, Me and Dupree': 1.0, 'Superman Returns': 4.0}
sumXY=0.0;
n=0;
sumX=0.0;
sumY=0.0;
sumX2=0.0;
sumY2=0.0;
try:
for movie1,score1 in user1.items():
if movie1 in user2.keys():#计算公共的电影的评分
n+=1;
sumXY+=score1*user2[movie1]
sumX+=score1;
sumY+=user2[movie1]
sumX2+=pow(score1,2)
sumY2+=pow(user2[movie1],2)
molecule=sumXY-(sumX*sumY)/n;
denominator=sqrt((sumX2-pow(sumX,2)/n)*(sumY2-pow(sumY,2)/n))
r=molecule/denominator
except Exception,e:
print "异常信息:",e.message
return None
return r
#计算与当前用户的距离,获得最临近的用户
def nearstUser(self,username,n=1):
distances={};#用户,相似度
for otherUser,items in self.data.items():#遍历整个数据集
if otherUser not in username:#非当前的用户
distance=self.pearson(self.data[username],self.data[otherUser])#计算两个用户的相似度
distances[otherUser]=distance
sortedDistance=sorted(distances.items(),key=operator.itemgetter(1),reverse=True);#最相似的N个用户
print "排序后的用户为:",sortedDistance
return sortedDistance[:n]
#给用户推荐电影
def recomand(self,username,n=1):
recommand={};#待推荐的电影
for user,score in dict(self.nearstUser(username,n)).items():#最相近的n个用户
print "推荐的用户:",(user,score)
for movies,scores in self.data[user].items():#推荐的用户的电影列表
if movies not in self.data[username].keys():#当前username没有看过
print "%s为该用户推荐的电影:%s"%(user,movies)
if movies not in recommand.keys():#添加到推荐列表中
recommand[movies]=scores
return sorted(recommand.items(),key=operator.itemgetter(1),reverse=True);#对推荐的结果按照电影评分排序
if __name__=='__main__':
users = {'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}
}
userCf=UserCf(data=users)
recommandList=userCf.recomand('Toby', 2)
print "最终推荐:%s"%recommandList
代码转载于:https://blog.csdn.net/wickedvalley/article/details/80095007
四、基于项目的协同过滤算法(Item-Based)
基于物品的协同过滤算法通过计算不同用户对不同物品的评分获得物品间的关系,基于物品间的关系对用户进行相似物品的推荐,评分即代表用户对物品的态度和偏好。比如,用户A同时购买了物品x,y,那么说明x,y之间的相关度高,当用户B也购买了物品x时,那么可以预测B也可能买物品y。
4.1 算法流程:
1)构建用户–>物品的倒排(即倒查表);
2)构建物品与物品的共现矩阵;
3)计算物品之间的相似度,即计算相似矩阵;
4)根据用户的历史记录,给用户推荐物品。
(其中,2、3步实际上可以合为一步,相似矩阵为共现矩阵的改进优化。)
注:该算法也适合解决基于用户的协同过滤问题
4.2 实例
如下表,行表示用户,列表示物品,1 表示用户喜欢该物品
表1
4.2.1 构建用户—>物品的倒排
A : a 、 b 、 d 、e
B : b 、 c 、 e
C : c 、 d
D : b 、 c 、 d
E : a 、 d
4.2.2构建物品与物品的共现矩阵
共现矩阵表示同时喜欢两个物品的用户数,是一个对称矩阵,是由用户—>物品的倒排表计算出来的。
4.2.3 计算物品之间的相似度,即计算相似矩阵
设
∣
N
(
i
)
∣
\left | N(i) \right |
∣N(i)∣表示喜欢物品的用户数,
∣
N
(
i
)
⋂
N
(
j
)
∣
\left | N(i)\bigcap N(j) \right |
∣N(i)⋂N(j)∣表示同时喜欢物品i、j用户数,则物品i与物品j的相似度为:
但上式有一个问题,当物品j是一个很热门的物品时,人人都喜欢,那么w
i
j
_{ij}
ij就会很接近 1 ,那上式会让很多物品都和热门物品有一个很大的相似度。所以,需要改进一下公式:
上式中,分子即为共现矩阵,矩阵 N(用于计算分母)表示喜欢某物品的用户数(是总的用户数).
矩阵N如下:
所以,物品之间的余弦相似矩阵如下(因为该矩阵是对阵的,所以在矩阵右上部分我写出了相似度计算的公式,左下部分写出了对应公式的值):
4.2.4 根据用户的历史记录,给用户推荐物品
ItemCF 通过如下公式计算用户 u 对一个物品 j的兴趣度:
其中:
N(u):用户喜欢的物品的集合
S(j,k):和物品j最相似的k个物品的集合
W
j
i
_{ji}
ji:物品j和i的相似度
r
u
i
_{ui}
ui: 用户u对物品i的兴趣度(对于因反馈的数据集,如果用户u对物品i有过行为即可令r
u
i
_{ui}
ui=1)
上式的含义是:和用户历史上感兴趣的物品越相似的物品,越有可能在用户的推荐列表中获得比较高的排名。
如:以用户 A 为例,建立用户对物品的评分矩阵(即 A对物品的兴趣度)如下:
用户 A 已经见过物品 a , b , d并对其进行了评分,所以我们需要选择是推荐物品c还是物品e给用户 A
推荐结果:
其中(0,0.67,0,0.58,0,041)*
(
11010
)
\begin{pmatrix} 1 1 0 1 0 \end{pmatrix}
(11010),(0.5,0.81,0.41,0.35,0)*
(
11010
)
\begin{pmatrix} 1 1 0 1 0 \end{pmatrix}
(11010)
则可以看出,用户 A 对物品 c 的预测兴趣度(即喜爱程度)为1.25, 对物品 e 的预测兴趣度(即喜爱程度)为1.66。所以,可向 A推荐物品 e .
4.3 python 代码实现
#/python/Item_CF.py
# -*- 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
def loadData2(files):
data={}
for line in files:
user,item,score,timestamp=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__':
# 用户,兴趣度,物品
# 实例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']
data=loadData(uid_score_bid) #获得数据
W=similarity(data) #计算物品相似矩阵
recommandList(data,W,'A',3,10) #推荐
# 实例2
users2 = []
fp_2 = open("u.data", "r", encoding='utf-8')
for line2 in fp_2.readlines():
line_2=line2.replace("\t",",")
lines2 = line_2.strip().split("\n")
users2+=lines2
data2 = loadData2(users2) # 获得数据
W2 = similarity(data2) # 计算物品相似矩阵
recommandList(data2, W3, '160', 3, 20) # 推荐
代码转载链接:https://blog.csdn.net/qq_42851418/article/details/85265723
感谢查阅,一起进步,点个赞再走吧~ qwq。