推荐算法概述
对于推荐系统(Recommend System, RS),从广义上的理解为:为用户(User)推荐相关的商品(Items)。常用的推荐算法主要有:
- 基于内容的推荐(Content-Based Recommendation)
- 协同过滤的推荐(Collaborative Filtering Recommendation)
- 基于关联规则的推荐(Association Rule-Based Recommendation)
- 基于效用的推荐(Utility-Based Recommendation)
- 基于知识的推荐(Knowledge-Based Recommendation)
- 组合推荐(Hybrid Recommendation)
在推荐系统中,最重要的数据是用户对商品的打分数据,数据形式如下所示:
其中,U1⋯U5表示的是5个不同的用户,D1⋯D4表示的是4个不同的商品,这样便构成了用户-商品矩阵,在该矩阵中,有用户对每一件商品的打分,其中“-”表示的是用户未对该商品进行打分。
在推荐系统中有一类问题是对未打分的商品进行评分的预测。
目前推荐系统中用的最多的就是矩阵分解方法,在Netflix Prize推荐系统大赛中取得突出效果。以用户-项目评分矩阵为例,矩阵分解就是预测出评分矩阵中的缺失值,然后根据预测值以某种方式向用户推荐。常见的矩阵分解方法有基本矩阵分解(basic MF),正则化矩阵分解)(Regularized MF),基于概率的矩阵分解(PMF)等。今天以“用户-项目评分矩阵R(N×M)”说明三种分解方式的原理以及应用。
-
Basic MF:
Basic MF是最基础的分解方式,将评分矩阵R分解为用户矩阵U和项目矩阵S, 通过不断的迭代训练使得U和S的乘积越来越接近真实矩阵,矩阵分解过程如图:
预测值接近真实值就是使其差最小,这是我们的目标函数,然后采用梯度下降的方式迭代计算U和S,它们收敛时就是分解出来的矩阵。我们用损失函数来表示误差(等价于目标函数):
公式1公式1中R_ij是评分矩阵中已打分的值,U_i和S_j相当于未知变量。为求得公式1的最小值,相当于求关于U和S二元函数的最小值(极小值或许更贴切)。通常采用梯度下降的方法:
是学习速率,表示迭代的步长。其值为1.5时,通常以震荡形式接近极值点;若<1迭代单调趋向极值点;若>2围绕极值逐渐发散,不会收敛到极值点。具体取什么值要根据实验经验。
-
Regularized MF
正则化矩阵分解是Basic MF的优化,解决MF造成的过拟合问题。其不是直接最小化损失函数,而是在损失函数基础上增加规范化因子,将整体作为损失函数。
红线表示正则化因子,在求解U和S时,仍然采用梯度下降法,此时迭代公式变为:(图片截取自相关论文,S和V等价)
其中, 。
梯度下降结束条件:f(x)的真实值和预测值小于自己设定的阈值(很小的值,之前一直理解为是变量U和V的迭代值差小于阈值就行,弄了一天才懂。)
程序实现
对于上述的评分矩阵,通过矩阵分解的方法对其未打分项进行预测,最终的结果为:
程序代码如下:
#!/bin/python ''' Date:20160411 @author: zhaozhiyong ''' from numpy import * def load_data(path): f = open(path) data = [] for line in f.readlines(): arr = [] lines = line.strip().split("\t") for x in lines: if x != "-": arr.append(float(x)) else: arr.append(float(0)) #print arr data.append(arr) #print data return data def gradAscent(data, K): dataMat = mat(data) print dataMat m, n = shape(dataMat) p = mat(random.random((m, K))) q = mat(random.random((K, n))) alpha = 0.0002 beta = 0.02 maxCycles = 10000 for step in xrange(maxCycles): for i in xrange(m): for j in xrange(n): if dataMat[i,j] > 0: #print dataMat[i,j] error = dataMat[i,j] for k in xrange(K): error = error - p[i,k]*q[k,j] for k in xrange(K): p[i,k] = p[i,k] + alpha * (2 * error * q[k,j] - beta * p[i,k]) q[k,j] = q[k,j] + alpha * (2 * error * p[i,k] - beta * q[k,j]) loss = 0.0 for i in xrange(m): for j in xrange(n): if dataMat[i,j] > 0: error = 0.0 for k in xrange(K): error = error + p[i,k]*q[k,j] loss = (dataMat[i,j] - error) * (dataMat[i,j] - error) for k in xrange(K): loss = loss + beta * (p[i,k] * p[i,k] + q[k,j] * q[k,j]) / 2 if loss < 0.001: break #print step if step % 1000 == 0: print loss return p, q if __name__ == "__main__": dataMatrix = load_data("./data") p, q = gradAscent(dataMatrix, 5) ''' p = mat(ones((4,10))) print p q = mat(ones((10,5))) ''' result = p * q #print p #print q print result
其中,利用梯度下降法进行矩阵分解的过程中的收敛曲线如下所示:
''' Date:20160411 原文作者:@author: zhaozhiyong ''' from pylab import * from numpy import * data = [] f = open("result") for line in f.readlines(): lines = line.strip() data.append(lines) n = len(data) x = range(n) plot(x, data, color='r',linewidth=3) plt.title('Convergence curve') plt.xlabel('generation') plt.ylabel('loss') show()
来源:https://www.cnblogs.com/onemorepoint/p/8167942.html