【Python机器学习】利用SVD简化数据——基于协同过滤的推荐引擎

有很多方法可以实现推荐功能,其中协同过滤是通过将用户和其他用户的数据进行对比来实现推荐的。

这里的数据是从概念上组织成了矩阵形式。当数据采用这种方式进行组织时,我们就可以比较用户或物品之间的相似度了。这两种做法都会使用相似度的概念。当知道了两个用户或两个物品之间的相似度,我们就可以利用已有的数据来预测未知的用户的喜好。例如我们试图对某个用户喜欢的电影进行预测,推荐引擎会发现有一部电影该用户还没看过,然后,它就会计算该电影和用户看过的电影之间的相似度,如果相似度很高,推荐算法就会认为用户喜欢这部电影。

在上述场景下,唯一所需要的数学方法就是相似度的计算。

相似度计算

我们希望拥有一些物品之间相似度的定量方法,我们不利用专家所给出的重要属性来描述物品从而计算它们之间的相似度,而是利用用户对它们的意见来计算相似度。这就是协同过滤中所使用的方法。它并不关心物品的描述属性,而是严格的按照许多用户的观点来计算相似度。

下图给出了由一些用户及其对部分菜肴的评级信息所组成的矩阵。

我们计算一下手撕猪肉和烤牛肉之间的相似度。一开始我们使用欧式距离来计算。手撕猪肉和烤牛肉的欧式距离为:

\sqrt{(4-4)^{2}+(3-3)^{2}+(2-1)^{2}}=1

而手撕猪肉和鳗鱼饭的欧氏距离为:

\sqrt{(4-2)^{2}+(3-5)^{2}+(2-2)^{2}}=2.83

在该数据中,由于手撕猪肉和烤牛肉的距离小于手撕猪肉和鳗鱼饭的距离,因此手撕猪肉与烤牛肉比与鳗鱼饭更为相似。我们希望,相似度在0到1之间变化,并且物品越相似,它们的相似度值也就越大。我们可以用“相似度=1/(1+举例)”这样的算式来计算相似度。当距离为0时,相似度为1.0。如果距离真的非常大时,相似度也就趋近于0。

第二种计算距离的方法是皮尔逊相关系数。它度量的是两个向量之间的相似度。该方法相对于欧式距离的一个优势在于:它对用户评级的量级并不敏感。比如某个狂躁者对所有物品的评分都是5分,而另一个忧郁者对所有物品的评分都是1分,皮尔逊相关系数会认为这两个向量是相等的。在NumPy中,皮尔逊相关系数的计算是由corrcoef()进行的。皮尔逊相关系数的取值范围从-1到+1。我们通过0.5+0.5*corrcoef()这个函数计算,并且把其取值范围归一化0到1之间。

另一个常用的距离计算方法就是余弦相似度,其计算的是两个向量夹角的余弦值。如果夹角为90度,则相似度为0,如果两个向量的方向相同,则相似度为1.0。同皮尔逊相关系数一样,余弦相似度的取值范围也在-1到+1之间,因此我们也将它归一化到0到1之间。计算余弦相似度,我们采用的两个向量A和B夹角的余弦相似度的定义如下:

cos\theta =\frac{A\cdot B}{\left \| A \right \|\cdot \left \| B \right \|}

其中\left \| A \right \|\left \| B \right \|表示向量A、B的2范数,你可以定义向量的任一范数,但是如果不指定范数阶数,则都假设为2范数。向量[4,2,2]的2范数为:

\sqrt{4^{2}+2^{2}+2^{2}}

同样,NumPy的线性代数工具箱中提供了范数的计算方法linalg.norm()。

接下来是具体的代码实现:

from numpy import *
from numpy import linalg as la

def euclidSim(inA,inB):
        return 1.0/(1.0+la.norm(inA-inB))
def pearsSim(inA,inB):
        if len(inA)<3:
                return 1.0
        return 0.5+0.5*corrcoef(inA,inB,rowvar=0)[0][1]
def cosSim(inA,inB):
        num=float(inA.T*inB)
        denom=la.norm(inA)*la.norm(inB)
        return 0.5+0.5*(num/denom)

上述代码就是上面所说的几种相似度的计算方法。函数中假定inA和inB都是列向量。pearsSim()函数会检查是否存在3个或更多的点。如果不存在,则函数返回1.0,这是因为此时两个向量完全相关。

下面是实际运行效果:

myMat=mat(loadExData())
print('欧式距离:',euclidSim(myMat[:,0],myMat[:,4]))

print('余弦相似度:',cosSim(myMat[:,0],myMat[:,4]))
print('余弦相似度:',cosSim(myMat[:,0],myMat[:,0]))

print('皮尔逊相关系数:',pearsSim(myMat[:,0],myMat[:,4]))
print('皮尔逊相关系数:',pearsSim(myMat[:,0],myMat[:,0]))

上面的相似度计算都是假设数据采用了列向量方式进行表示。如果利用上述函数来进行两个行向量的相似度就会碰到问题。

基于物品的相似度还是基于用户的相似度?

我们计算了两个餐馆菜肴之间的距离,这称为基于物品的相似度。另一种计算用户距离的方法则称为基于用户的相似度。上一节的图中,行与行之间比较的是基于用户的相似度,列与列质检比较的则是基于物品的相似度。使用哪一种相似度去局域用户或物品的数目。基于物品相似度计算的时间会随着物品数目的增加而增加,基于用户的相似度计算的时间会随着用户数目的增加而增加。如果用户的数目很多,我们可能倾向于使用基于物品相似度的计算方法。

对于大部分产品导向的推荐引擎而言,用户的数目往往大于物品的数量,即购买商品的用户数会多于出售的商品种类。

推荐引擎的评价

对于推荐引擎的评价,我们可以采用交叉测试的方法,具体的做法就是,我们将某些已知的评分值去掉,然后对它们进行预测,最后计算预测值和真实值之间的差异。

通常用于推荐引擎评价的指标是称为最小均方根误差(RMSE)的指标,它首先计算均方误差的平均值然后取其平方根。如果评级在1星到5星这个范围内,而我们得到的RMSE为1.0,就意味着我们的预测值和用户给出的真实评价相差了一个星级。

  • 10
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值