原理图示
矩阵分解算法:期望为每个用户和物品生成一个隐向量,将用户和物品定位在隐向量的表示空间上,距离相近的用户和物品表名兴趣特点接近,在推荐过程中,就应该把相近的物品推荐给目标用户。
注:k表示隐向量的维度,k的大小决定了隐向量表达能力的强弱,而k的取值要经过多次试验找到一个推荐效果和工程开销的平衡点;
原理 & 公式
对矩阵进行矩阵分解主要有三种方法:
- 特征值分解:只能作用于方阵,显然不适合分解用户-物品矩阵;
- 奇异值分解:奇异值分解要求原始的共现矩阵是稠密的,同时计算复杂度达到O(mn^2),不适合工程实现;
- 梯度下降:确定目标函数,求解偏导,求取梯度下降的方向和幅度;
公式
- 矩阵分解公式;
基于用户矩阵 和物品矩阵 ,用户 对物品 的预估评分为:
;
其中 是用户 在用户矩阵 中的对应行向量, 是物品 在物品矩阵 中的对应列向量;
- 目标函数(加入正则化项)
xi
- 消除用户和物品打分偏差
其中 为全局偏差常数, 是物品偏差系数,可以使用物品 收到的所有评分的均值; 是用户偏差系数,可以使用用户 给出的所有评分的均值;
优缺点
优点
- 泛化能力强:一定程度上解决了“协同过滤算法”中的数据稀疏问题;
- 空间复杂度低:只需要存储用户和物品的隐向量,空间复杂度从 降低到 ;
- 更好的拓展性和灵活性:矩阵分解的结果便于和其他特征进行组合和拼接,并便于与深度学习网络进行无缝链接;
缺点
- 不方便加入用户、物品和上下文相关特征,丧失了利用很多有效信息的机会,同时缺乏用户历史行为,无法进行有效推荐;
应用场景
- 话题识别:对文本信息进行处理提取信息,如下图所示
- 特征学习:类似于主成分分析(PCA)
- 例如人物脸部特征学习中,利用NMF算法将人脸部不同的特征显示出来;
代码实现
def matrix_factorization(self, r, p, q, hide): """ :param r: 评分矩阵 :param p: 用户矩阵 :param q: 物品矩阵 :param hide: 隐向量维度 :return: """ q = q.T loss_log = [] err_old = 0 # 记录前一个的loss for step in range(self.steps): for i in range(len(r)): for j in range(len(r[i])): if r[i][j] > 0: eij = r[i][j] - np.dot(p[i, :], q[:, j]) for k in range(hide): p[i][k] = p[i][k] + self.alpha * (2 * eij * q[k][j] - self.beta * p[i][k]) q[k][j] = q[k][j] + self.alpha * (2 * eij * p[i][k] - self.beta * q[k][j]) err = 0 for i in range(len(r)): for j in range(len(r[i])): if r[i][j] > 0: err = err + pow(r[i][j] - np.dot(p[i, :], q[:, j]), 2) for k in range(hide): err = err + (self.beta / 2) * (pow(p[i][k], 2) + pow(q[k][j], 2)) loss_log.append(err) if step == 0: err_old = err continue if abs(err_old - err) < 1e-10: break else: err_old = err if err < 0.001: break return p, q.T, loss_log