Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/304.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/joomla/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python sklearn列车测试通过多列分层_Python_Pandas_Scikit Learn - Fatal编程技术网

Python sklearn列车测试通过多列分层

Python sklearn列车测试通过多列分层,python,pandas,scikit-learn,Python,Pandas,Scikit Learn,我是sklearn的一个相对较新的用户,在sklearn.model\u选择的train\u test\u中遇到了一些意外行为。我有一个pandas数据框架,我想将其拆分为一个训练集和测试集。我希望在我的数据框架中至少按2列(但最好是4列)对数据进行分层 当我尝试这样做时,sklearn并没有发出警告,但后来我发现在我的最终数据集中有重复的行。我创建了一个示例测试来显示此行为: from sklearn.model_selection import train_test_split a = np

我是sklearn的一个相对较新的用户,在sklearn.model\u选择的train\u test\u中遇到了一些意外行为。我有一个pandas数据框架,我想将其拆分为一个训练集和测试集。我希望在我的数据框架中至少按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\u test\u split()
最终将strata定义为传递到
stratify
参数中的任何内容的唯一值集。由于地层是由两列定义的,一行数据可能代表多个地层,因此采样可能会选择同一行两次,因为它认为它是从不同的类中采样的

train\u test\u split()
函数
StratifiedShuffleSplit
,它在
y
np.unique()
(这是通过
stratifiy
传入的内容)。从源代码:

classes, y_indices = np.unique(y, return_inverse=True)
n_classes = classes.shape[0]
这是一个简化的示例,是您提供的示例的变体:

from sklearn.model_selection import train_test_split
import numpy as np
import pandas as pd

N = 20
a = np.arange(N)
b = np.random.choice(["foo","bar"], size=N)
c = np.random.choice(["y","z"], size=N)
df = pd.DataFrame({'a':a, 'b':b, 'c':c})

print(df)
     a    b  c
0    0  bar  y
1    1  foo  y
2    2  bar  z
3    3  bar  y
4    4  foo  z
5    5  bar  y
...
分层函数认为有四个类可以拆分:
foo
bar
y
z
。但由于这些类本质上是嵌套的,这意味着
y
z
都显示在
b==foo
b==bar
中,因此当拆分器尝试从每个类中采样时,我们将得到重复的

train, test = train_test_split(df, test_size=0.2, random_state=0, 
                               stratify=df[['b', 'c']])
print(len(train.a.values))  # 16
print(len(set(train.a.values)))  # 12

print(train)
     a    b  c
3    3  bar  y   # selecting a = 3 for b = bar*
5    5  bar  y
13  13  foo  y
4    4  foo  z
14  14  bar  z
10  10  foo  z
3    3  bar  y   # selecting a = 3 for c = y
6    6  bar  y
16  16  foo  y
18  18  bar  z
6    6  bar  y
8    8  foo  y
18  18  bar  z
7    7  bar  z
4    4  foo  z
19  19  bar  y

#* We can't be sure which row is selecting for `bar` or `y`, 
#  I'm just illustrating the idea here.
这里有一个更大的设计问题:您是想使用嵌套分层抽样,还是只想将
df.b
df.c
中的每个类作为单独的类进行抽样?如果是后者,那就是你已经得到的。前者更为复杂,而这并不是
train\u test\u split
设置的目的


您可能会发现嵌套分层抽样的方法很有用

您使用的是什么版本的scikit learn?您可以使用
sklearn.\uuuuu version\uuuu
进行检查

在0.19.0之前的版本中,scikit learn无法正确处理二维分层。它在0.19.0中进行了修补

这是在一本书中描述的


更新您的scikit learn应该可以解决此问题。如果无法更新scikit学习,请参阅此提交历史记录以获取修复

如果希望
train\u test\u split
按预期运行(按多个列分层,不重复),请创建一个新列,该列是其他列中值的串联,并在新列上分层

df['bc'] = df['b'].astype(str) + df['c'].astype(str)
train, test = train_test_split(df, test_size=0.2, random_state=0, stratify=df[['bc']])
如果您担心由于
11
3
1
13
这两个值都创建了一个串联值
113
,那么您可以在中间添加一些任意字符串:

df['bc'] = df['b'].astype(str) + "_" + df['c'].astype(str)

这里的“正确”是什么意思?这是否意味着它执行了andrew_reece提到的嵌套分层抽样?我刚刚测试了它,似乎它确实执行了嵌套分层抽样。谢谢你的回答,非常有帮助!Sklearn根本不处理二维分层(此处为0.22)。请参阅:-因此这只适用于一个热向量,而不适用于特征元组!可能上面的字符串concat hack是目前唯一的方法。这是一个残酷的hack,有您描述的问题(可能的冲突…),但现在,它似乎是唯一的方法。使用例如
df[['a','b']].apply(tuple)
raises
ValueError:支持的目标类型为:('binary','multiclass')。改为“未知”。