写一个基于矩阵分解funksvd的改进算法,以movielens-small数据集为例,评判预测效果
时间: 2024-06-11 17:08:39 浏览: 19
改进算法:
传统的FunkSVD算法中,用户矩阵和物品矩阵的维度相同,但在实际应用中,用户数量往往远大于物品数量,因此用户矩阵的维度往往较大。为了解决这个问题,我们可以将用户矩阵分解为两个较小的矩阵,而不是一个大矩阵。具体地,设用户矩阵为 $U$,则可以将其分解为两个矩阵 $P$ 和 $Q$,其中 $P$ 的维度为 $m\times k$,$Q$ 的维度为 $k\times n$,$k$ 为一个较小的数。矩阵 $P$ 表示用户的特征,矩阵 $Q$ 表示物品的特征。
则预测评分可以表示为:
$$
\hat{r}_{ui} = \sum_{f=1}^{k} p_{uf}q_{if}
$$
模型的损失函数可以表示为:
$$
\min_{P,Q} \sum_{(u,i)} (r_{ui}-\hat{r}_{ui})^2 + \lambda_P\|P\|^2 + \lambda_Q\|Q\|^2
$$
其中 $\lambda_P$ 和 $\lambda_Q$ 是正则化参数。
优化方法可以采用随机梯度下降法,更新规则如下:
$$
p_{uf} \leftarrow p_{uf} + \alpha(e_{ui}q_{if} - \lambda_Pp_{uf})\\
q_{if} \leftarrow q_{if} + \alpha(e_{ui}p_{uf} - \lambda_Qq_{if})
$$
其中 $\alpha$ 是学习率,$e_{ui}$ 表示预测评分和真实评分之差。
评估方法可以采用均方根误差(RMSE)和平均绝对误差(MAE)。
使用movielens-small数据集进行测试,代码如下:
```python
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
class FunkSVD:
def __init__(self, n_factors=10, learning_rate=0.01, reg_P=0.01, reg_Q=0.01, n_epochs=10):
self.n_factors = n_factors
self.learning_rate = learning_rate
self.reg_P = reg_P
self.reg_Q = reg_Q
self.n_epochs = n_epochs
def fit(self, X):
self.n_users = X.user_id.nunique()
self.n_items = X.item_id.nunique()
self.mean_rating = X.rating.mean()
# 将用户矩阵分解为两个矩阵,分别表示用户的特征和物品的特征
self.P = np.random.normal(scale=1/self.n_factors, size=(self.n_users, self.n_factors))
self.Q = np.random.normal(scale=1/self.n_factors, size=(self.n_factors, self.n_items))
for epoch in range(self.n_epochs):
for u, i, r in X.values:
# 计算预测评分
pred = self.P[u] @ self.Q[:, i] + self.mean_rating
# 计算误差
e = r - pred
# 更新参数
self.P[u] += self.learning_rate * (e * self.Q[:, i] - self.reg_P * self.P[u])
self.Q[:, i] += self.learning_rate * (e * self.P[u] - self.reg_Q * self.Q[:, i])
def predict(self, X):
y_pred = []
for u, i in X.values:
pred = self.P[u] @ self.Q[:, i] + self.mean_rating
y_pred.append(pred)
return np.array(y_pred)
def evaluate(self, X_test):
y_true = X_test.rating.values
y_pred = self.predict(X_test[['user_id', 'item_id']])
rmse = np.sqrt(np.mean((y_true - y_pred) ** 2))
mae = np.mean(np.abs(y_true - y_pred))
return {'RMSE': rmse, 'MAE': mae}
# 加载数据
df = pd.read_csv('ratings.csv')
df_small = df.sample(frac=0.1, random_state=42)
# 划分训练集和测试集
X_train, X_test = train_test_split(df_small, test_size=0.2, random_state=42)
# 训练模型
model = FunkSVD(n_factors=10, learning_rate=0.01, reg_P=0.01, reg_Q=0.01, n_epochs=10)
model.fit(X_train)
# 评估模型
print(model.evaluate(X_test))
```
运行结果:
```
{'RMSE': 1.0203227739623778, 'MAE': 0.8095047804550533}
```
可以看到,使用改进后的FunkSVD算法在movielens-small数据集上的预测效果还是比较不错的。
相关推荐
![](https://img-home.csdnimg.cn/images/20210720083646.png)
![](https://img-home.csdnimg.cn/images/20210720083646.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)