You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.
# 10.3 基于矩阵分解的协同过滤算法原理
将用户喜好矩阵与内容矩阵进行矩阵乘法就能得到用户对物品的预测结果,而我们的目的是预测结果与真实情况越接近越好。所以,我们将预测值与评分表中已评分部分的值构造平方差损失函数:
$$
loss = \frac{1}{2}\sum\limits_{(i,j)\in r(i,j)=1}(\sum\limits_{l=1}^dx_{il}w_{lj}-y_{ij})^2
$$
其中:
- i:第i个用户
- j:第j个物品
- d:第d种因素
- x:用户喜好矩阵
- w:内容矩阵
- y:评分矩阵
- r:评分记录矩阵, 无评分记为0, 有评分记为1。r(i,j)=1代表用户i对物品j进行过评分, r(i,j)=0代表用户i对物品j未进行过评分
损失函数`python`实现代码如下:
```python
import numpy as np
loss = np . mean ( np . multiply (( y - np . dot ( x , w )) ** 2 , record ))
```
其中,`record`为评分记录矩阵。
我们的目的就是最小化平方差损失函数,通常机器学习都是使用梯度下降的方法来最小化损失函数得到正确的参数。
梯度下降可以看成是我们被蒙住了双眼,然后要从山顶走到山下的过程。既然是被蒙住双眼,那么只能用脚去小步试探,看看哪个方向是朝着山下最陡的方向,找到了这个方向后就往该方向走一小步。然后不断地试探,走,试探,走,最终就可能会成功地走到山下。
如果我们将损失函数的值的大小看成是山的高度,那么我们就可以使用这种类似爬山的梯度下降算法来求解。其中,试探这个动作就是计算参数对于损失函数的偏导(即梯度),走这个动作就是根据梯度来更新参数,至于走的时候步子迈多大就是学习率。
因此梯度下降算法的伪代码如下:
设置学习率 α
设置损失值变化的最小阈值 β
while 到达迭代次数:
计算当前参数 θ 的损失值 J
计算参数对损失函数的偏导 G
计算新参数 Newθ, 公式为 Newθ = θ - α G
计算参数为 Newθ 时的损失值 NewJ
if abs(NewJ - j) < β:
break
对每个参数求得偏导如下:
$$
\frac{\partial loss}{\partial x_{ik}} = \sum\limits_{j\in r(i,j)=1}(\sum\limits_{l=1}^dx_{il}w_{lj}-y_{ij})w_{kj}
$$
$$
\frac{\partial loss}{\partial w_{kj}} = \sum\limits_{i\in r(i,j)=1}(\sum\limits_{l=1}^dx_{il}w_{lj}-y_{ij})x_{ik}
$$
则梯度为:
$$
\Delta x = r.(xw-y)w^T
$$
$$
\Delta w = x^T[(xw-y).r]
$$
其中:
.表示点乘法,无则表示矩阵相乘
上标T表示矩阵转置
梯度`python`代码如下:
```python
x_grads = np . dot ( np . multiply ( record , np . dot ( x , w ) - y ), w . T )
w_grads = np . dot ( x . T , np . multiply ( record , np . dot ( x , w ) - y ))
```
然后再进行梯度下降:
```python
#梯度下降
for i in range ( n_iter ):
# 计算x和w的梯度
x_grads = np . dot ( np . multiply ( record , np . dot ( x , w ) - y ), w . T )
w_grads = np . dot ( x . T , np . multiply ( record , np . dot ( x , w ) - y ))
# 更新参数
x = alpha * x - lr * x_grads
w = alpha * w - lr * w_grads
```
其中:
n_iter:训练轮数
lr:学习率
alpha: 权重衰减系数, 用来防止过拟合