You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于截断SVD计算MovieLens测试集的RMSE?

问题描述

我正在尝试对拆分后的MovieLens数据集使用截断SVD计算RMSE。原始数据集是610用户×9724电影的评分矩阵(评分范围1-5),用model_selection.train_test_split拆分后,训练集维度为610×9379,验证集维度为603×3653。对训练集执行SVD后,能计算训练矩阵与预测矩阵A=U·S·Vᵀ的RMSE,但测试集的维度和电影集合与训练集不同,不知道怎么计算预测评分与测试集的RMSE。

解决思路

核心问题是训练集和验证集的用户、电影集合不完全重叠,直接用矩阵运算会出现维度不匹配。推荐从原始长表(而非宽表)入手,对验证集的每条评分条目单独生成预测值,再计算RMSE,这种方式更高效且避免维度对齐的麻烦:

步骤说明

  1. 保留索引映射:从训练宽表中提取userId到行索引、movieId到列索引的字典映射,方便快速查找训练集中的用户和电影位置。
  2. 构建嵌入矩阵:将U与Sigma的对角矩阵相乘得到用户嵌入矩阵,将VT转置得到电影嵌入矩阵,两者的点积即可还原预测评分。
  3. 生成验证集预测:遍历验证集的每条评分记录,对存在于训练集中的用户和电影,计算对应嵌入的点积作为预测值;对未出现过的用户/电影,用训练集的全局评分均值填充(避免无预测值的情况)。
  4. 计算RMSE:收集所有真实评分和预测评分,直接调用mean_squared_error计算并开平方得到RMSE。
修改后的代码
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.utils.extmath import randomized_svd
from sklearn.metrics import mean_squared_error

# 读取数据
df = pd.read_csv('data/ml-latest-small/ratings.csv')

# 拆分训练集和验证集
df_train, df_valid = train_test_split(df, test_size=0.1, random_state=42)

# 构建训练宽表并填充0
train_data = df_train.pivot_table(index='userId', columns='movieId', values='rating').fillna(0)

# 获取用户和电影的索引映射
user_to_idx = {user: idx for idx, user in enumerate(train_data.index)}
movie_to_idx = {movie: idx for idx, movie in enumerate(train_data.columns)}

# 执行截断SVD
U, Sigma, VT = randomized_svd(np.array(train_data), 
                              n_components=15,
                              n_iter=5,
                              random_state=None)

# 构建用户嵌入和电影嵌入矩阵
user_embeddings = U @ np.diag(Sigma)  # shape: (610, 15)
movie_embeddings = VT.T  # shape: (9379, 15)

# 计算训练集全局均值,用于处理未见过的用户/电影
train_global_mean = df_train['rating'].mean()

# 生成验证集的预测值
y_true = []
y_pred = []

for _, row in df_valid.iterrows():
    user_id = row['userId']
    movie_id = row['movieId']
    true_rating = row['rating']
    
    # 检查用户和电影是否在训练集中
    if user_id in user_to_idx and movie_id in movie_to_idx:
        user_idx = user_to_idx[user_id]
        movie_idx = movie_to_idx[movie_id]
        # 计算点积得到预测评分
        pred_rating = user_embeddings[user_idx] @ movie_embeddings[movie_idx]
        # 限制评分在1-5范围内(可选,符合原始评分范围)
        pred_rating = np.clip(pred_rating, 1, 5)
    else:
        # 用训练集全局均值替代
        pred_rating = train_global_mean
    
    y_true.append(true_rating)
    y_pred.append(pred_rating)

# 计算RMSE
rmse = np.sqrt(mean_squared_error(y_true, y_pred))
print(f"验证集RMSE: {rmse:.4f}")

内容的提问来源于stack exchange,提问作者Bothurin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 02:57:33