【问题标题】:Sklearn train_test_split; retaining unique values from column(s) in training setsklearn train_test_split;保留训练集中列中的唯一值
【发布时间】:2018-05-21 20:39:38
【问题描述】:

有没有办法使用sklearn.model_selection.train_test_split 来保留训练集中特定列的所有唯一值。

让我举个例子。我知道的最常见的矩阵分解问题是预测用户在Netflix ChallengeMovielens 数据集中的电影评分。现在这个问题并不真正围绕任何单一的矩阵分解方法,但在可能的范围内,有一个小组将只对已知的用户和项目组合进行预测。

例如,在 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 中是否有办法拆分数据集,以确保在训练集中保留来自特定列的唯一值集?

我对这个问题的初步解决方案如下。

  1. 将总评分数较少/用户的项目分开。
  2. 在数据上创建一个train_test_split,不包括这些很少评分的项目/用户(确保拆分大小 + 排除大小等于您想要的拆分大小)。
  3. 将两者结合得到最终的代表性训练集

例子:

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 提出的方法适用于每个类都表示不止一次的数据。该数据并非如此,大多数推荐/排名数据集也并非如此。

【问题讨论】:

  • 所以你希望你所有的稀有物品都只在训练集中?还是在训练和测试集中都被复制?我认为您不会在 sklearn 中找到此功能,我猜这两种方法都会影响您的验证指标。反正第一个听起来更好
  • 我目前的情况更复杂一些,因为我有十几个列需要将唯一值保留在训练集中。
  • @Grr 你希望从训练集中这些非常稀有的项目中获得什么?
  • 我认为对这样的数据集最好的做法是使用基于 stratified K-fold 的方法,并在这些 K-folds 上平均模型的性能,而不是简单的训练测试分裂。
  • @coldspeed:好主意。如果 sklearn 抱怨班级太小,你会如何分层? (顺便说一句:在 Google 的生活怎么样?)

标签: python pandas numpy scikit-learn matrix-factorization


【解决方案1】:

您正在寻找的东西称为分层。幸运的是,sklearn 就是这样。只需将行更改为

itrain, itest, utrain, utest, rtrain, rtest = train_test_split(
     items, users, ratings, train_size=train_ratio, stratify=users)

如果没有设置stratify,数据会随机打乱。见http://scikit-learn.org/stable/modules/generated/sklearn.model_selection.train_test_split.html

如果 [stratify is] 不是 None,则以分层方式拆分数据,并将其用作类标签。


更新更新的问题:似乎将唯一实例放入训练集中没有内置在 scikit-learn 中。您可以滥用 PredefinedSplitextend StratifiedShuffleSplit,但这可能比您自己滚动更复杂。

【讨论】:

  • stratify 不是每个班级至少需要两个样本吗? train_test_split(ml, train_size=0.9, stratify=ml.Item_id)ValueError: The least populated class in y has only 1 member, which is too few. The minimum number of groups for any class cannot be less than 2.。即如果只有一个元素要拆分,它如何将数据分成两组保持分层?
  • 正如@filippo 指出的那样,当类具有单个数据点时,这种方法不起作用,就像这个和大多数其他推荐/排名数据集一样。
  • @serv-inc 使用Inductive Matrix Completion,您可以将辅助信息合并到推荐模型中。通过这种方式,随着模型了解来自用户和项目的辅助信息如何交互以产生给定的结果,单个评分变得更有价值。
  • @serv-inc 你可以“学习”,但没多大用处。无论使用的方法多么复杂,通过一个示例,您只能猜测样本是它所在类别的平均值。这总比什么都不知道要好(并且您可以利用可用信息做的最好的事情),但您会期望这个“猜测”很少接近您从更大样本中获得的信息。
  • 不要卖空自己。即使它对最初的提问者没有多大帮助,你的回答对于试图通过谷歌解决他们的机器学习问题并发现“分层”是他们需要的神奇技术词并且你给他们一个实施指南的人来说是很好的它。
【解决方案2】:

也许您可以按电影中的输入数据进行分组,然后取样,然后将所有样本组合成一个大数据集。

# 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)
 .
 .
 .

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-27
    • 2018-08-14
    • 2016-05-25
    • 2019-03-23
    • 2021-08-03
    • 2022-11-23
    • 2016-10-14
    • 2020-03-09
    相关资源
    最近更新 更多