Grr*_*Grr 20 python numpy pandas scikit-learn matrix-factorization
有没有办法用于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
Run Code Online (Sandbox Code Playgroud)
尽可能多地试试这个,你最终不会在火车组中找到1682个独特的电影.这是许多电影在数据集中只有一个评级的结果.幸运的是,对于用户来说情况并非如此(用户的最低评级数是20),所以这不是问题.但是为了拥有一个有效的训练集,我们需要所有独特的电影至少在训练集中一次.此外,我无法使用stratify=kwarg train_test_split因为所有用户或所有电影的条目不超过1个.
我的问题是这个.
我对这个问题的初步解决方案如下.
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))
Run Code Online (Sandbox Code Playgroud)
这种方法有效,但我只需要感觉有一种方法可以实现与train_test_splitsklearn 相同或另一种分割方法.
虽然@ serv-inc提出的方法适用于每个类不止一次表示的数据.这种数据不是这种情况,也不是大多数推荐/排名数据集.
您要查找的内容称为分层。幸运的是,sklearn只有这样。只需将行更改为
itrain, itest, utrain, utest, rtrain, rtest = train_test_split(
items, users, ratings, train_size=train_ratio, stratify=users)
Run Code Online (Sandbox Code Playgroud)
如果stratify未设置,则数据随机打乱。见http://scikit-learn.org/stable/modules/generated/sklearn.model_selection.train_test_split.html
如果 [
stratifyis] 不是None,则以分层方式拆分数据,将其用作类标签。
更新更新的问题:似乎将独特的实例放入训练集中并没有内置到 scikit-learn 中。您可以滥用PredefinedSplit或扩展 StratifiedShuffleSplit,但这可能比简单地滚动您自己的更复杂。
也许您可以对电影上的输入数据进行分组,然后取样,然后将所有样本组合成一个大数据集。
# initialize lists
utrain_all =[]
utest_all =[]
itrain_all = []
itest_all = []
rtrain_all = []
rtest__all = []
grp_ml = ml.groupby('Item_id')
for name, group in grp_ml:
utrain, utest, itrain, itest, rtrain, rtest = train_test_split(group, train_size=0.9)
utrain_all.append(utrain)
utest_all.append(utest)
itrain_all.append(itrain)
.
.
.
Run Code Online (Sandbox Code Playgroud)