有没有一种方法可以sklearn.model_selection.train_test_split
用来保留训练集中特定列的所有唯一值。
让我举个例子。我知道的最常见的矩阵分解问题是在Netflix Challenge或Movielens数据集中预测用户的电影评分。现在这个问题并不真正围绕任何单一的矩阵分解方法,但在可能性范围内,有一个小组将只对已知的用户和项目组合进行预测。
例如,在 Movielens 100k 中,我们有 943 个独立用户和 1682 个独立电影。如果我们train_test_split
甚至使用高train_size
比率(例如 0.9),唯一用户和电影的数量也不会相同。这带来了一个问题,因为我提到的这组方法对于未经训练的电影或用户只能预测 0。这是我的意思的一个例子。
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
ml = pd.read_csv('ml-100k/u.data', sep='\t', names=['User_id', 'Item_id', 'Rating', 'ts'])
ml.head()
User_id Item_id Rating ts
0 196 242 3 881250949
1 186 302 3 891717742
2 22 377 1 878887116
3 244 51 2 880606923
4 166 346 1 886397596
ml.User_id.unique().size
943
ml.Item_id.unique().size
1682
utrain, utest, itrain, itest, rtrain, rtest = train_test_split(ml, train_size=0.9)
np.unique(utrain).size
943
np.unique(itrain).size
1644
尽可能多地尝试这个,你最终不会在火车组中得到 1682 部独特的电影。这是由于许多电影在数据集中只有一个评分。幸运的是,用户的情况并非如此(用户的最低评分为 20),所以这不是问题。但是为了有一个有效的训练集,我们需要所有独特的电影至少在训练集中出现一次。此外,我无法使用stratify=
kwarg,train_test_split
因为所有用户或所有电影的条目不超过 1 个。
我的问题是这个。
sklearn 中是否有办法拆分数据集以确保来自特定列的唯一值集保留在训练集中?
我对该问题的基本解决方案如下。
- 将/用户的总评分数较低的项目分开。
- 在不包括这些很少评分的项目/用户的数据上创建一个
train_test_split
(确保拆分大小 + 排除大小将等于您想要的拆分大小)。 - 将两者结合得到最终的代表性训练集
例子:
item_counts = ml.groupby(['Item_id']).size()
user_counts = ml.groupby(['User_id']).size()
rare_items = item_counts.loc[item_counts <= 5].index.values
rare_users = user_counts.loc[user_counts <= 5].index.values
rare_items.size
384
rare_users.size
0
# We can ignore users in this example
rare_ratings = ml.loc[ml.Item_id.isin(rare_items)]
rare_ratings.shape[0]
968
ml_less_rare = ml.loc[~ml.Item_id.isin(rare_items)]
items = ml_less_rare.Item_id.values
users = ml_less_rare.User_id.values
ratings = ml_less_rare.Rating.values
# Establish number of items desired from train_test_split
desired_ratio = 0.9
train_size = desired_ratio * ml.shape[0] - rare_ratings.shape[0]
train_ratio = train_size / ml_less_rare.shape[0]
itrain, itest, utrain, utest, rtrain, rtest = train_test_split(items, users, ratings, train_size=train_ratio)
itrain = np.concatenate((itrain, rare_ratings.Item_id.values))
np.unique(itrain).size
1682
utrain = np.concatenate((utrain, rare_ratings.User_id.values))
np.unique(utrain).size
943
rtrain = np.concatenate((rtrain, rare_ratings.Rating.values))
这种方法有效,但我只是觉得有一种方法可以使用train_test_split
sklearn 或另一种拆分方法来完成相同的操作。
警告 - 数据包含用户和电影的单个条目
虽然@serv-inc 提出的方法适用于每个类都表示不止一次的数据。该数据不是这种情况,大多数推荐/排名数据集也不是这种情况。