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

基于Surprise的协同过滤推荐系统训练测试集问题求助

问题分析与修复方案

1. RMSE测试预测为空的原因

你注释的测试集过滤代码逻辑错误:trainset.all_items()返回的是内部item ID(整数类型),而testset里的x[1]是原始item ID(字符串类型),直接用x[1] in trainset.all_items()会把所有测试样本过滤掉,导致testset为空,最终predictions为空,RMSE计算失败。

修复方式:改用训练集的原始item ID字典判断:

# 正确过滤测试集:保留训练集中存在的item
testset = [x for x in testset if x[1] in trainset._raw2inner_id_items]

2. 推荐部分的ValueError问题

错误点1:列表误用numpy索引

trainset.ur[user_inner_id]返回的是元组列表(每个元素是(内部item ID, 评分)),你用user_ratings[:,0]这种numpy数组索引方式会触发错误。可以用列表推导式提取已评分item ID:

# 提取用户已评分的item内部ID
rated_item_inner_ids = [iid for (iid, _) in trainset.ur[user_inner_id]]

错误点2:未导入defaultdict

代码中使用defaultdict但未导入,会触发NameError,需在开头添加:

from collections import defaultdict

错误点3:内部ID与原始ID混淆

trainset.all_items()返回的是内部item ID,你直接调用to_inner_iid会报错,应该转成原始ID存入推荐列表:

for inner_item_id in trainset.all_items():
    if inner_item_id not in rated_item_inner_ids:
        item_id = trainset.to_raw_iid(inner_item_id)
        items_to_recommend.append(item_id)

修复后的完整代码

# import necessary libraries
import numpy as np
from collections import defaultdict
from surprise import SVD
from surprise import Dataset
from surprise import accuracy
from surprise.model_selection import train_test_split

# load the dataset
data = Dataset.load_builtin('ml-100k')

# define the algorithm
algo = SVD()

# split the data into training and testing sets
trainset, testset = train_test_split(data, test_size=.25)

# 正确过滤测试集:保留训练集中存在的item
testset = [x for x in testset if x[1] in trainset._raw2inner_id_items]

# train the algorithm on the training set
algo.fit(trainset)

# make predictions on the testing set
predictions = algo.test(testset)

# calculate RMSE (Root Mean Squared Error)
accuracy.rmse(predictions)

# recommend items to a specific user
user_id = '196'
items_to_recommend = []

# get all the items that the user hasn't rated
if user_id in trainset._raw2inner_id_users:  # check if user id is present in the trainset
    user_inner_id = trainset.to_inner_uid(user_id)
    rated_item_inner_ids = [iid for (iid, _) in trainset.ur[user_inner_id]]
    # 遍历训练集所有item,筛选未评分的
    for inner_item_id in trainset.all_items():
        if inner_item_id not in rated_item_inner_ids:
            item_id = trainset.to_raw_iid(inner_item_id)
            items_to_recommend.append(item_id)

# predict ratings for all items that the user hasn't rated
user_items = [(user_id, item_id, 4.0) for item_id in items_to_recommend] # 4.0 is a placeholder rating
item_ratings = algo.test(user_items)

# if item_ratings is empty, recommend the most popular items
if len(item_ratings) == 0:
    item_popularity = defaultdict(int)
    for (u, i, r) in trainset.all_ratings():
        item_id = trainset.to_raw_iid(i)
        item_popularity[item_id] += 1
    sorted_items = sorted(item_popularity.items(), key=lambda x: x[1], reverse=True)
    items_to_recommend = [iid for (iid, _) in sorted_items][:10]
    print(f"No recommendations found for user {user_id}. Recommending the most popular items.")
else:
    # sort the predicted ratings in descending order
    item_ratings.sort(key=lambda x: x.est, reverse=True)
    # print the top 10 recommended items for the user
    print(f"Top 10 items recommended for user {user_id}:")
    for item in item_ratings[:10]:
        print(f"Item ID: {item.iid}, Estimated Rating: {item.est}")

额外提示

  • Surprise中trainset的内部ID和原始ID是不同类型,必须用to_inner_uid/to_raw_uid、to_inner_iid/to_raw_iid转换,避免类型不匹配错误。
  • 统计热门物品时,trainset.all_ratings()返回的是内部ID,要转成原始ID再统计,否则输出的ID不符合数据集原始格式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 19:53:15