推荐数据集特点
推荐系统数据集通常具有以下特点:
- • 稀疏性
推荐系统的数据通常是高度稀疏的,因为用户与项目(如电影、书籍或商品)之间的交互通常只占所有可能交互的一小部分。例如,在MovieLens数据集中,尽管有数百万条评分记录,但由于庞大的用户基数和项目数量,大部分用户-项目组合仍然没有交互记录。因此,在进行数据集切分时,必须确保每个用户和项目在训练集中有足够的交互记录,以便模型能够学习到有意义的模式。 - • 时间依赖性
许多推荐场景中,用户的偏好和行为随时间变化,这要求我们在构建训练集和测试集时考虑到时间因素。一个常见的做法是按照时间顺序将数据划分为训练集和测试集,即较早的数据用于训练,而最近的数据用于测试。这样做的好处是可以评估模型对未来趋势的预测能力。例如,Netflix Prize竞赛中的数据集就是基于这种时间分割方法设计的。 - • 冷启动问题
冷启动问题是推荐系统中特有的挑战之一,指的是当新用户加入系统或新产品上线时,由于缺乏足够的历史交互数据,难以对这些新实体做出准确的推荐。为了解决这个问题,在构建测试集时可以特意保留一些完全没有历史交互的新用户或新物品,以此来评估系统在面对冷启动情况下的表现
这些特点使得传统的随机切分方法可能不适用。因此,需要采用专门的策略来切分测试集。
划分策略
1. 按用户或物品分组
将数据按用户或物品分组,确保每个用户或物品在测试集中有足够多的交互数据。例如,选择每个用户的最后一个交互作为测试集,其余作为训练集。
但是也要确保测试集中的用户和物品在训练集中有足够的数据,避免测试集过于稀疏。如果某个用户在训练集中只有一次交互,可以考虑将其排除在测试集之外,或者将其交互数据全部放入训练集。
2. 按时间排序切分
按时间顺序排序数据,将最后的时间段作为测试集,模拟真实场景。例如将所有交互按时间排序,取最近的10%作为测试集,其余作为训练集。或者按照时间窗口切分:将数据按时间窗口切分,例如训练集为过去6个月,测试集为最近1个月。
3. 保留新用户或新物品
保留新用户/物品:保留一部分完全不包含在训练集中的新用户或新物品,用于评估冷启动性能,选择最近加入的用户或物品作为测试集的一部分。例如,将最近一个月内注册的用户作为测试集中的新用户,评估模型对新用户的推荐效果。
4. 混合切分策略
结合多种方法:结合时间和用户/物品分组的方法,确保测试集中包含足够多的新用户和新物品。
示例:将数据按时间排序后,选择最近一个月的数据作为测试集,并从中筛选出新用户和新物品作为冷启动测试集的一部分。同时,从每个用户的交互中选择最后一个行为作为常规测试集的一部分。
实现代码
import pandas as pd
from sklearn.model_selection import train_test_split
# 1. 加载数据集
# 假设数据集文件名为 'ratings.dat',格式为:UserID::MovieID::Rating::Timestamp
data_path = 'ratings.dat'
data = pd.read_csv(data_path, sep='::', header=None, names=['UserID', 'MovieID', 'Rating', 'Timestamp'], engine='python')
# 2. 按时间排序
data.sort_values(by='Timestamp', inplace=True)
# 3. 划分训练集和测试集
# 方法1:按时间划分
# 取最后10%的数据作为测试集
test_size = 0.1
split_index = int(len(data) * (1 - test_size))
train_data = data[:split_index]
test_data = data[split_index:]
# 方法2:按用户分组划分
# 对于每个用户,选择其最后一次评分作为测试集
user_groups = data.groupby('UserID')
test_data_user = user_groups.tail(1)
train_data_user = data.drop(test_data_user.index)
# 4. 设置冷启动测试集
# 选择最近一段时间内加入的用户作为冷启动测试集
# 假设冷启动测试集包含最近10%的用户
new_users = data['UserID'].unique()[-int(len(data['UserID'].unique()) * test_size):]
cold_start_test_data = data[data['UserID'].isin(new_users)]
# 5. 验证切分效果
print("训练集大小:", len(train_data))
print("测试集大小:", len(test_data))
print("用户分组测试集大小:", len(test_data_user))
print("冷启动测试集大小:", len(cold_start_test_data))
# 保存切分后的数据集
train_data.to_csv('train_data.csv', index=False)
test_data.to_csv('test_data.csv', index=False)
test_data_user.to_csv('test_data_user.csv', index=False)
cold_start_test_data.to_csv('cold_start_test