下面主要以个别例子来探讨一下何为协同过滤以及鄙人一些个性化的理解,希望能帮到你们。
提示:以下是本篇文章正文内容,下面案例可供参考
协同过滤(简称CF)是推荐系统最重要的思想之一。协同协同,不明思议,那就是有“共同”部分,过滤是指滤去相关性不强的部分。不管是基于用户的协同过滤还是基于物品的协同过滤,均是由一定的数据计算出得相关性大小来对使用者进行较为合理的推荐而衍生出的一种算法。
计算相似度强弱时,用英文单词similarity的简写sim(a,b)表示a与b的相识度,下面主要介绍一种基于用户协同过滤的例子用到的经典算法皮尔逊相关系数(Pearson Correlation Coefficient)的详细用法,当然还有余弦相识度(Cosine-based Similarity),调整后的余弦相识度(Adjusted Cosine Similarity),欧式距离相似度,杰卡德相似系数等(有关公式可上网查询)
公式:
其中,i 表示项,例如商品;Iu 表示用户 u 评价的项集;Iv 表示用户 v 评价的项 集;ru.i表示用户 u 对项 i 的评分;rv.i 表示用户 v 对项 i 的评分;带上划线的表示用户 的平均评分。
余弦距离通过向量空间中两个向量夹角的余弦值作为衡量两个个体间差异的大小的度量。
三角形余弦定理公式:
由三角形余弦定理公式可知,角 A 越小,bc 两边越接近。当 A 为 0 度时,bc 两边完全重合。
在向量空间中,对于向量 a 和向量 b 符合公式
当 a 和 b 越接近(越相似),即两个向量越接近时,二者之间的夹角为0,此时余弦值为1,恰恰这个时候,二者的相似度最大。
所以在比对 a 和 b 的相似度时,可以将其向量化后,计算它的余弦值,从而比较其相似度。即:
类似的也可以推广到n个样本的相似性度量公式:
对于用户A和B两者形成的数据集合的相似性度量,为了方便起见,我们常常也用到下面的公式:
不管是由余弦,皮尔逊系数,还是其他的相似度公式求得的关联常数,都可代入以下公式求得预测值。
ru加上划线记做aver(ru)表示用户u的评分的平均值等类似的信息,s(u,u*)表示两者的相似度
简介:用户指的是商品的购买者或者说是某件商品的使用者,基于他们涉及购买的物品的交集以及相关性的有关计算(通常为购买后的评价或者有关浏览量)来锁定两个相关性最强的用户,假设为A和B,然后把A方未购买的物品推荐给B方。
为了能更直观的解释基于用户的协同过滤,下面映入的将是实实在在的现实中应用的有关数据以及推荐原理的解说。
假设你通过网络后台得到了一些用户与商品的一些评分数据,那你是否能用刚才提到的相关知识和理论来探讨以下基于用户的推荐原理吗?
当然实际上的数据是不能拿来讲理论知识的,这里只是极简极简的丁点数据,欢迎大家深探,当然也可发明更为可靠的算法推荐,后生可畏也。
用户 | 商品1 | 商品 2 | 商品 3 | 商品 4 | average |
---|---|---|---|---|---|
A | 4 | 0 | 3 | 5 | 4 |
B | 0 | 5 | 4 | 0 | 4.5 |
C | 5 | 4 | 2 | 0 | 3.667 |
D | 2 | 4 | 0 | 3 | 3 |
E | 3 | 4 | 5 | 0 | 4 |
(1)寻找可利用的“好友”
比如现在我们需要预测用户 C 对商品 4 的评分,我们就要找到已经对商品4进行过评分的用户来“利用”,肉眼可见,为用户A和D。然后根据公共评分来求相关系数。
温馨提示:下面两个代码虽然长,除了相似度计算函数不一样外,其他大致相同,不必被纸老虎吓住。
(1)利用皮尔逊系数的代码实现
import numpy as np
from math import sqrt
def pier(lst_1,lst_2,M,N):#求皮尔逊系数的函数的构建
aver_1=0
aver_2=0
a=0
b=0
fenzi=0
fang_1=0
fang_2=0
for i in range(M):#前两个for循环用于求得两个用户的平均值
if lst_1[i]!=0:
a+=1
aver_1+=lst_1[i]
aver_1=aver_1/a
for i in range(M):
if lst_2[i]!=0:
b+=1
aver_2+=lst_2[i]
aver_2=aver_2/b
for i in range(M):
fenzi+=(lst_1[i]-aver_1)*(lst_2[i]-aver_2)
fang_1+=pow((lst_1[i]-aver_1),2)
fang_2+=pow(lst_2[i]-aver_2,2)
fenmu=sqrt(fang_1)*sqrt(fang_2)
return fenzi/fenmu
def yuping(lst_u,R,u_u,M,N,n,m):#求预测评分函数
#lst_u表示需要预测的用户,R为原始的用户和物品形成的二维数组,n表示用户数据所在行,m表示没有评分物品所在列
fenzi=0
fenmu=0
aver_1=0#平均值
aver_2=0
a=0#当前用户购买物品数量
b=0
for i in range(M):
if lst_u[i]!=0:
a+=1
aver_1 +=lst_u[i]
aver_1=aver_1/a
for o in range(N):
if R[o][m]!=0:
for i in range(M):
if R[o][i]!=0:
b+=1
aver_2 +=R[o][i]
aver_2=aver_2/b
fenzi+=u_u[n][o]*(R[o][m]-aver_2)
fenmu+=abs(pier(lst_u,R[o],M,N))
return aver_1+fenzi/fenmu
R=np.array([[4,0,3,5],#生成原始矩阵R
[0,5,4,0],
[5,4,2,0],
[2,4,0,3],
[3,4,5,0]])
N=len(R) #行数
M=len(R[0]) #列数
u_u=np.zeros((N,N))#建立用户与用户之间相关性矩阵u_u
for n in range(N):#建立一个对R的循环筛选未评分item并进行预测评分
for m in range(N):
if n<m:
u_u[n][m]=pier(R[n],R[m],M,N)
u_u[m][n]=u_u[n][m]
print("得到的用户-用户相似度矩阵:")
print(u_u)#打印用户与用户相似度矩阵
user=['A','B','C','D','E']#用户集合
items=['p1','p2','p3','p4']#商品集合
for n in range(N):#建立一个对R循环寻找未评分项并且对未评分项进行预测
for m in range(M):
if R[n][m]==0:
R[n][m]=yuping(R[n],R,u_u,M,N,n,m)
if R[n][m]>3:
print("将商品{:}推荐给用户{:}".format(items[m],user[n]))
print("评分预测矩阵R^:")
print("{:}".format(R))
(2)余弦相似度的代码实现:
import numpy as np
from math import sqrt
def pex(ls_1,ls_2,M): #求余弦相似度的函数 ls_1,ls_2表示用户1,2的相关数组,M表示总的物品数
fenzi=0#余弦相似度分子
fenmu=0#分母
abs_1=0#分母左边绝对值里的值
abs_2=0#分母右边绝对值里的值
for i in range(M):
fenzi += ls_1[i] * ls_2[i]
abs_1 += pow(ls_1[i],2)
abs_2 += pow(ls_2[i],2)
fenmu=sqrt(abs_1*abs_2)
return fenzi/fenmu#ls_1,ls_2用户相关系数
def yuping(lst_u,R,u_u,M,N,n,m):#求预测评分函数
#lst_u表示需要预测的用户,R为原始的用户和物品形成的二维数组,n表示用户数据所在行,m表示没有评分物品所在列
fenzi=0
fenmu=0
aver_1=0#平均值
aver_2=0
a=0#当前用户购买物品数量
b=0
for i in range(M):
if lst_u[i]!=0:
a+=1
aver_1 +=lst_u[i]
aver_1=aver_1/a
for o in range(N):
if R[o][m]!=0:
for i in range(M):
if R[o][i]!=0:
b+=1
aver_2 +=R[o][i]
aver_2=aver_2/b
fenzi+=u_u[n][o]*(R[o][m]-aver_2)
fenmu+=abs(pex(lst_u,R[o],M))
return aver_1+fenzi/fenmu
R=np.array([[4,0,3,5],#生成原始矩阵R
[0,5,4,0],
[5,4,2,0],
[2,4,0,1],
[3,4,5,0]])
N=len(R)#列长
M=len(R[0])#行长
u_u=np.zeros((N,N))#建立用户与用户之间相关性矩阵u_u
for n in range(N):#建立一个对R的循环筛选未评分item并进行预测评分
for m in range(N):
if n<m:
u_u[n][m]=pex(R[n],R[m],M)
u_u[m][n]=u_u[n][m]
print("得到的用户-用户相似度矩阵:")
print(u_u)#打印用户与用户相关系数矩阵
user=['A','B','C','D','E']#用户集合
items=['p1','p2','p3','p4']#商品集合
for n in range(N):#建立一个对R循环寻找未评分项并且对未评分项进行预测
for m in range(M):
if R[n][m]==0:
R[n][m]=yuping(R[n],R,u_u,M,N,n,m)
if R[n][m]>3:
print("将商品{:}推荐给用户{:}".format(items[m],user[n]))
print("评分预测矩阵R^:")
print("{:}".format(R))
基于物品,是指主要以计算物品间的相似度,来对用户推荐另一件物品。假设你购买了手机和笔记本,有相当一部分人在购买了手机,笔记本之后也购买了ipad,那么通过相关计算就会定下ipad与手机和笔记本的相似度较高,而给你推荐ipad。声明的是这里用购买的相关记录的统计来计算物品间的相似度大小。
两物品的相似度的计算与用户的相似度的计算大体相同,公式如下:
上述图片为修改过的计算公式,是为了避开热门商品的巨大影响,有兴趣的可以了解一下。公式中的N(i)^N(j)表示用户N对商品i和j同时喜欢(即购买)的次数,Wij表示i与j的相似度。
由于某种力量,你又再次得到了好几个用户与商品的历史信息,如下表所示:
A | a | b | d |
---|---|---|---|
B | a | c | b |
C | b | e | c |
D | c | d | e |
结果你发现并不能很好的得到物品之间同时被你和他一起喜欢的次数,于是接下来要引入的是共现矩阵
提示:下表纯粹是为了更直观的统计同时购买两件商品的用户数,与代码没有任何联系,不要误以为我会在代码中建立图1的矩阵.
a | b | c | d | e | |
---|---|---|---|---|---|
a | 2 | 1 | 1 | 0 | |
b | 2 | 2 | 1 | 1 | |
c | 2 | 2 | 1 | 2 | |
d | 1 | 1 | 2 | 1 | |
e | 0 | 1 | 2 | 1 |
图1
如何让计算机去帮我们求用户u对于物品j的兴趣浓厚呢?
下面给出如下公式:
这里 N(u)是用户喜欢(购买)的物品的集合,S(j,K)是和物品 j 最相似的 K 个物品的集合,Wji 是物品 j 和 i 的相似度,rui 是用户 u 对物品 i 的兴趣。(对于隐反馈数据集, 如果用户 u 对物品 i 有过购买评分的行为,即可令rui=1。为啥令他等于1不是等于其他数值呢?个人认为是因为物品与物品之间的相似度最大值为1的原因,就是绝对关联) 该公式的含义是,和用户历史 上感兴趣的物品越相似的物品,越有可能在用户的推荐列表中获得比较高的排名。
注意:那么这个公式具体要表达什么呢?看不懂怎么办?那就用上面的例子代入使用一下:
得到共现矩阵:(物品相似度矩阵)
a | b | c | d | e | |
---|---|---|---|---|---|
a | 0 | 0.8164 | 0.7071 | 0.5 | 0 |
b | 0.8164 | 0 | 0.8660 | 0.4082 | 0.4082 |
c | 0.7071 | 0.8660 | 0 | 0.7071 | 0.7071 |
d | 0.5 | 0.4082 | 0.7071 | 0 | 0.5 |
e | 0 | 0.4082 | 0.7071 | 0.5 | 0 |
那么问题来了,如何能更快捷的对每两件物品计算出他们的相似度呢?接下来要引入的是另一种计算方法(更确切的说是更为简便的计算形式):
其中,Pa 为新用户对已有产品的向量,(这里我们把用户有过的记为1,不曾拥有的记为0,构造列为1的向量)T 为物品的共现矩阵,得到的 P`a 为新用 户对每个产品的兴趣度。
(1)以上用到的矩阵相乘的知识点,本博主大浪淘沙给你们找了B站上比较不错的视频,链接在下面,请取所需:
女学霸详解矩阵相乘
上面例子的解释如下图:
[ 0 0.8164 0.7071 0.5 0 0.8164 0 0.8660 0.4082 0.4082 0.7071 0.8660 0 0.7071 0.7071 0.5 0.4082 0.7071 0 0.5 0 0.4082 0.7071 0.5 0 ] \begin{bmatrix} 0&0.8164&0.7071&0.5&0\\ 0.8164&0&0.8660&0.4082&0.4082\\0.7071&0.8660&0&0.7071&0.7071\\ 0.5&0.4082&0.7071&0&0.5\\ 0&0.4082&0.7071&0.5&0\end{bmatrix} ⎣⎢⎢⎢⎢⎡00.81640.70710.500.816400.86600.40820.40820.70710.866000.70710.70710.50.40820.707100.500.40820.70710.50⎦⎥⎥⎥⎥⎤* [ 0 1 0 1 1 ] \begin{bmatrix} 0\\1\\0\\1\\1\end{bmatrix} ⎣⎢⎢⎢⎢⎡01011⎦⎥⎥⎥⎥⎤= [ 1.3164 0.8164 2.2802 0.9082 0.9082 ] \begin{bmatrix}1.3164\\0.8164\\2.2802\\0.9082\\0.9082\end{bmatrix} ⎣⎢⎢⎢⎢⎡1.31640.81642.28020.90820.9082⎦⎥⎥⎥⎥⎤
由于这种计算方法没有像公式那样进行物品相似度大小的比较,所以可能导致过拟合,写代码时可以用遍历的方法来对相似度在0.6以上的进行过滤
import numpy as np
from math import sqrt
'''
用户/物品 | 物品a | 物品b | 物品c | 物品d | 物品e |
用户A | 1 | 1 | 1 | 1 | |
用户B | 1 | 1 | 1 | | |
用户C | | 1 | 1 | | 1 |
用户d | | | 1 | 1 | 1 |
'''
#定义余弦相似性度量计算
def simil(ls_1,ls_2,n): #求item之间的相似度
fenzi=0#分子
fenmu=0#分母
n_1=n_2=0#喜欢商品的用户数初始值
for k in range(n):
#分子值为同时喜欢两个物品的用户数,若ls_1,ls_2同时为1(即用户都购买过这两件商品),相乘得1,分子加1即统计一次
fenzi+=ls_1[k] * ls_2[k]
n_1 += ls_1[k]
n_2 += ls_2[k]
fenmu=sqrt(n_1*n_2)
return fenzi/fenmu#ls_1,ls_2物品相似度
#定义预测兴趣度函数
def fore(ls_1,ls_2):
return np.dot(ls_1,ls_2)
#构建用户——商品矩阵
user_item=np.array([[1,1,1,1,0],
[1,1,1,0,0],
[0,1,1,0,1],
[0,0,1,1,1]])
print("用户-物品矩阵:")
print(user_item)
#建立用户列表
user = ['用户A','用户B','用户C','用户D']
#建立物品列表
item = ['物品a','物品b','物品c','物品d','物品e']
n = len(user) #n个用户
m = len(item) #m个物品
#建立物品——用户倒排表
item_user=user_item.T
print(item_user)
#建立物品——物品相似度共现矩阵
sim = np.zeros((m,m)) #相似度矩阵,默认全为0
#下面对相似度空矩阵循环并填充
for i in range(m):
for j in range(m):
if i < j:
sim[i][j] = simil(item_user[i],item_user[j],n)
sim[j][i] = sim[i][j]
print("得到的物品-物品相似度矩阵:")
print(sim) #打印物品-物品相似度矩阵
#做一个物品——物品最相似物品相似度矩阵
#相似度矩阵有了,我们预测兴趣度
REuser_item=np.zeros((n,m))#建立预测空矩阵
for i in range(n):#遍历用户
for j in range(m):#遍历商品
if user_item[i][j]==0:#将原矩阵里空兴趣度进行预测并填补到预测空矩阵中
REuser_item[i][j]=fore(sim[j],user_item[i])
if REuser_item[i][j]>0.6:
print("对{:}推荐商品{:}".format(user[i],item[j]))
print("用户——物品预测矩阵:\n",REuser_item)