推荐算法---协同过滤2021-4-13

前言

下面主要以个别例子来探讨一下何为协同过滤以及鄙人一些个性化的理解,希望能帮到你们。


提示:以下是本篇文章正文内容,下面案例可供参考

一、什么是协同过滤?(Collaborative Filtering)

协同过滤(简称CF)是推荐系统最重要的思想之一。协同协同,不明思议,那就是有“共同”部分,过滤是指滤去相关性不强的部分。不管是基于用户的协同过滤还是基于物品的协同过滤,均是由一定的数据计算出得相关性大小来对使用者进行较为合理的推荐而衍生出的一种算法。

二、协同过滤涉及的相关性强弱的计算(相似度)

计算相似度强弱时,用英文单词similarity的简写sim(a,b)表示a与b的相识度,下面主要介绍一种基于用户协同过滤的例子用到的经典算法皮尔逊相关系数(Pearson Correlation Coefficient)的详细用法,当然还有余弦相识度(Cosine-based Similarity),调整后的余弦相识度(Adjusted Cosine Similarity),欧式距离相似度,杰卡德相似系数等(有关公式可上网查询)

1.皮尔逊相关系数

公式:
其中,i 表示项,例如商品;Iu 表示用户 u 评价的项集;Iv 表示用户 v 评价的项 集;ru.i表示用户 u 对项 i 的评分;rv.i 表示用户 v 对项 i 的评分;带上划线的表示用户 的平均评分。

2.余弦相似度

公式:在这里插入图片描述

余弦距离通过向量空间中两个向量夹角的余弦值作为衡量两个个体间差异的大小的度量。

三角形余弦定理公式:在这里插入图片描述
由三角形余弦定理公式可知,角 A 越小,bc 两边越接近。当 A 为 0 度时,bc 两边完全重合。

在向量空间中,对于向量 a 和向量 b 符合公式在这里插入图片描述
当 a 和 b 越接近(越相似),即两个向量越接近时,二者之间的夹角为0,此时余弦值为1,恰恰这个时候,二者的相似度最大。
所以在比对 a 和 b 的相似度时,可以将其向量化后,计算它的余弦值,从而比较其相似度。即:在这里插入图片描述
类似的也可以推广到n个样本的相似性度量公式:在这里插入图片描述
对于用户A和B两者形成的数据集合的相似性度量,为了方便起见,我们常常也用到下面的公式:在这里插入图片描述

3.评分预测公式

不管是由余弦,皮尔逊系数,还是其他的相似度公式求得的关联常数,都可代入以下公式求得预测值。
在这里插入图片描述
ru加上划线记做aver(ru)表示用户u的评分的平均值等类似的信息,s(u,u*)表示两者的相似度

三、具体分类

1.基于用户的协同过滤(UserCF)

简介:用户指的是商品的购买者或者说是某件商品的使用者,基于他们涉及购买的物品的交集以及相关性的有关计算(通常为购买后的评价或者有关浏览量)来锁定两个相关性最强的用户,假设为A和B,然后把A方未购买的物品推荐给B方。

1.1实例解说UserCF

为了能更直观的解释基于用户的协同过滤,下面映入的将是实实在在的现实中应用的有关数据以及推荐原理的解说。

1.11 例子

假设你通过网络后台得到了一些用户与商品的一些评分数据,那你是否能用刚才提到的相关知识和理论来探讨以下基于用户的推荐原理吗?

当然实际上的数据是不能拿来讲理论知识的,这里只是极简极简的丁点数据,欢迎大家深探,当然也可发明更为可靠的算法推荐,后生可畏也。

用户商品1商品 2商品 3商品 4average
A40354
B05404.5
C54203.667
D24033
E34504

(1)寻找可利用的“好友”
比如现在我们需要预测用户 C 对商品 4 的评分,我们就要找到已经对商品4进行过评分的用户来“利用”,肉眼可见,为用户A和D。然后根据公共评分来求相关系数。
在这里插入图片描述

根据皮尔逊相关系数公式有:在这里插入图片描述
其他的计算类似。

1.12 代码实现

温馨提示:下面两个代码虽然长,除了相似度计算函数不一样外,其他大致相同,不必被纸老虎吓住。

(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))     

2,基于物品的协同过滤(ItemCF)

基于物品,是指主要以计算物品间的相似度,来对用户推荐另一件物品。假设你购买了手机和笔记本,有相当一部分人在购买了手机,笔记本之后也购买了ipad,那么通过相关计算就会定下ipad与手机和笔记本的相似度较高,而给你推荐ipad。声明的是这里用购买的相关记录的统计来计算物品间的相似度大小。

2.1 相似度计算的套路公式

两物品的相似度的计算与用户的相似度的计算大体相同,公式如下:在这里插入图片描述
上述图片为修改过的计算公式,是为了避开热门商品的巨大影响,有兴趣的可以了解一下。公式中的N(i)^N(j)表示用户N对商品i和j同时喜欢(即购买)的次数,Wij表示i与j的相似度。

2.11 直接上例子

由于某种力量,你又再次得到了好几个用户与商品的历史信息,如下表所示:

Aabd
Bacb
Cbec
Dcde

结果你发现并不能很好的得到物品之间同时被你和他一起喜欢的次数,于是接下来要引入的是共现矩阵
提示:下表纯粹是为了更直观的统计同时购买两件商品的用户数,与代码没有任何联系,不要误以为我会在代码中建立图1的矩阵.

abcde
a2110
b2211
c2212
d1121
e0121
                        图1

然后由公式计算a与b的相似度:
1在这里插入图片描述

2.2 求用户对某件商品的兴趣

如何让计算机去帮我们求用户u对于物品j的兴趣浓厚呢?
下面给出如下公式:在这里插入图片描述
这里 N(u)是用户喜欢(购买)的物品的集合,S(j,K)是和物品 j 最相似的 K 个物品的集合,Wji 是物品 j 和 i 的相似度,rui 是用户 u 对物品 i 的兴趣。(对于隐反馈数据集, 如果用户 u 对物品 i 有过购买评分的行为,即可令rui=1。为啥令他等于1不是等于其他数值呢?个人认为是因为物品与物品之间的相似度最大值为1的原因,就是绝对关联) 该公式的含义是,和用户历史 上感兴趣的物品越相似的物品,越有可能在用户的推荐列表中获得比较高的排名。

注意:那么这个公式具体要表达什么呢?看不懂怎么办?那就用上面的例子代入使用一下:在这里插入图片描述
得到共现矩阵:(物品相似度矩阵)

abcde
a00.81640.70710.50
b0.816400.86600.40820.4082
c0.70710.866000.70710.7071
d0.50.40820.707100.5
e00.40820.70710.50

那么问题来了,如何能更快捷的对每两件物品计算出他们的相似度呢?接下来要引入的是另一种计算方法(更确切的说是更为简便的计算形式):在这里插入图片描述
其中,Pa 为新用户对已有产品的向量,(这里我们把用户有过的记为1,不曾拥有的记为0,构造列为1的向量)T 为物品的共现矩阵,得到的 P`a 为新用 户对每个产品的兴趣度。

2.21 矩阵乘法

(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以上的进行过滤

2.12 例子的代码实现

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)                

结果:在这里插入图片描述
总是需要一些温暖。哪怕是一点点自以为是的纪念。都看到最后了,我要为你点赞!在这里插入图片描述

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小威程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值