我是sklearn的一个相对较新的用户,在sklearn.model_选择的train_test_中遇到了一些意想不到的行为。我有一个熊猫数据框,我想分成一个训练和测试集。我想将我的数据分层至少2列,但理想情况下在我的数据框中是4列。
当我尝试这样做时,sklearn没有发出警告,但是后来我发现在我的最终数据集中有重复的行。我创建了一个示例测试来显示此行为:
from sklearn.model_selection import train_test_split
a = np.array([i for i in range(1000000)])
b = [i%10 for i in a]
c = [i%5 for i in a]
df = pd.DataFrame({'a':a, 'b':b, 'c':c})
如果我按任意一列进行分层,它似乎可以按预期工作:
train, test = train_test_split(df, test_size=0.2, random_state=0, stratify=df[['b']])
print(len(train.a.values)) # prints 800000
print(len(set(train.a.values))) # prints 800000
train, test = train_test_split(df, test_size=0.2, random_state=0, stratify=df[['c']])
print(len(train.a.values)) # prints 800000
print(len(set(train.a.values))) # prints 800000
但当我尝试按两列进行分层时,会得到重复的值:
train, test = train_test_split(df, test_size=0.2, random_state=0, stratify=df[['b', 'c']])
print(len(train.a.values)) # prints 800000
print(len(set(train.a.values))) # prints 640000
得到重复的原因是因为
train_test_split()
最终将strata定义为传入stratify
参数的任何值的唯一值集。由于层是由两列定义的,因此一行数据可能代表多个层,因此采样可能会选择同一行两次,因为它认为它是从不同的类采样。函数}(这是通过
train_test_split()
,在y
上的uses{stratify
传入的)。从源代码:这是一个简化的示例,是您提供的示例的变体:
分层函数认为有四个类可以拆分:
foo
、bar
、y
和z
。但是由于这些类本质上是嵌套的,意味着y
和z
都出现在b == foo
和b == bar
中,所以当拆分器尝试从每个类中进行采样时,我们将获得重复项。这里有一个更大的设计问题:您是想使用嵌套分层抽样,还是实际上只想将
df.b
和df.c
中的每个类作为单独的类进行抽样?如果是后者,那就是你已经得到的。前者更复杂,而这不是train_test_split
的目的。您可能会发现this discussion嵌套分层抽样很有用。
如果希望
train_test_split
按预期的方式运行(按多个列分层,没有重复项),请创建一个新列,该列是其他列中的值的串联,并在新列上分层。如果您担心由于
11
和3
以及1
和13
这两个值都会创建一个连接值113
,那么您可以在中间添加一些任意字符串:你在用什么版本的scikit learn?您可以使用
sklearn.__version__
进行检查。在0.19.0之前的版本中,scikit learn无法正确处理二维分层。它是在0.19.0中修补的。
它在issue #9044中有描述。
更新scikit learn应该可以解决问题。如果无法更新scikit学习,请参阅此提交历史记录here以获取修复。
相关问题 更多 >
编程相关推荐