前言 这是“矩阵分解在推荐系统中的应用”系列的第3篇翻译文章,英文原文请参考nicolas-hug.com

算法Python实现

前一篇文章中我们描述了如何利用随机梯度下降算法来对输入的打分矩阵进行SVD分解,下面是整个算法的主要计算过程。

    1. 随机初始化向量\(p_u\)\(q_i\)
    1. 再有限次迭代次数内,重复以下计算过程:
    • 针对所有已知的\(r_{ui}\)重复以下过程:
      • 计算\(\frac {\partial f_{ui}} {\partial q_i}\)\(\frac {\partial f_{ui}} {\partial p_u}\)
      • 更新\(p_u\)\(q_i\):
        • \(p_u \leftarrow p_u + \alpha \cdot q_i(r_{ui} - p_u \cdot q_i)\)
        • \(q_i \leftarrow q_i + \alpha \cdot p_u(r_{ui} - p_u \cdot q_i)\)

注意上面的计算过程中我们将导数公式中的系数2,归一到学习率\(\alpha\)

下面我们用Python对上面的算法进行实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def SGD(data):
'''Learn the vectors p_u and q_i with SGD.
data is a dataset containing all ratings + some useful info (e.g. number
of items/users).
'''

n_factors = 10 # number of factors
alpha = .01 # learning rate
n_epochs = 10 # number of iteration of the SGD procedure

# Randomly initialize the user and item factors.
p = np.random.normal(0, .1, (data.n_users, n_factors))
q = np.random.normal(0, .1, (data.n_items, n_factors))

# Optimization procedure
for _ in range(n_epochs):
for u, i, r_ui in data.all_ratings():
err = r_ui - np.dot(p[u], q[i])
# Update vectors p_u and q_i
p[u] += alpha * err * q[i]
q[i] += alpha * err * p[u]

我们按照SGD算法计算出\(p_u\)\(q_i\)之后, 我们可以就可以对所有的\(r_{ui}\)进行近似估计。

1
2
3
def estimate(u, i):
'''Estimate rating of user u for item i.'''
return np.dot(p[u], q[i])

整个过程的所有实现都在这里了, 你可以使用surprise来进行自己的实验尝试(里面有很多demo)。 python 用户可以直接使用以下命令进行安装:

1
pip install scikit-surprise

如何评价我们的算法

我们使用RMSE(Root Mean Squared Error)来对算法的预估效果进行评价。RMSE公式如下: \[RMSE = \sqrt{\sum _{u,i}(\hat {r}_{ui} - r_{ui})^2}\]

进一步阅读

(略, 详见原文)