sklearn 管道在应用于测试集时不记得其状态
Posted
技术标签:
【中文标题】sklearn 管道在应用于测试集时不记得其状态【英文标题】:sklearn pipeline not remembering its state when applied on the testing set 【发布时间】:2020-06-21 20:37:59 【问题描述】:当在训练集上调用我的管道的 fit_transform
方法,然后在测试集上调用 transform 方法时,管道正在根据测试集更新其内部状态,而不是简单地应用在训练中学到的知识放。
例如。给定以下数据框:
df = pd.DataFrame(
'Sex':['female', 'male', 'male', 'male', 'female', 'female','neutral', 'male'],
'Survived':['no', 'no', 'yes', 'no', 'yes', 'no', 'yes', 'no']
)
并将其拆分为 X_train、X_test、y_train、y_test: 重要提示:请注意,我的拆分方式是只有测试集的值为“中性”。
X_train = df.loc[:4,'Sex']
y_train = df.loc[:4,'Survived']
X_test = df.loc[5:, 'Sex']
y_test = df.loc[5:, 'Survived']
下面我创建了一个名为 Dummifier
的转换器并插入到我的管道中(为了简单起见,管道这里只有一种方法):
class Dummifier(BaseEstimator, TransformerMixin):
def fit(self, X, y=None):
return self
def transform(self, X, y=None):
X_dummies = pd.get_dummies(X)
return X_dummies
my_pipe = Pipeline([
('get_dummies', Dummifier())
])
现在,当我在训练集中调用fit_transform
,然后在测试集上调用变换方法时,给定的输出如下:
X_train_trans = my_pipe.fit_transform(X_train, y_train)
X_test_trans = my_pipe.transform(X_test)
Output:
female male neutral
5 1 0 0
6 0 0 1
7 0 1 0
问题:既然训练集中没有值“中性”,为什么转换器现在在测试集中创建一个“中性”列?
预期的输出是:
Output:
female male
5 1 0
6 0 0
7 0 1
我已经尝试使用来自 sklearn 的 OneHotEncoder
,但输出基本相同。
【问题讨论】:
只是因为你的transform方法没有使用任何状态,而pd.get_dummies没有状态。 您能再解释一下吗?我想当我调用方法“fit_transform”时,我的管道对象会从数据中学习并存储这个状态。当我调用“transform”时,管道将采用之前的状态来转换新数据,因为我使用的是相同的管道对象。 是的,但是您的转换不使用任何状态,它只是调用 pd.get_dummies,您在该代码的哪个位置使用在 fit_transform 中学习的状态? 我明白你的意思,但我不知道如何将它翻译成代码。这正是我正在寻找的答案。 【参考方案1】:OneHotEncoder
的handle_unknown
参数需要设置为ignore
以满足您的要求。这可能会有所帮助!
from sklearn.preprocessing import OneHotEncoder
from sklearn.pipeline import Pipeline
import pandas as pd
df = pd.DataFrame(
'Sex': ['female', 'male', 'male', 'male', 'female',
'female', 'neutral', 'male'],
'Survived': ['no', 'no', 'yes', 'no', 'yes', 'no', 'yes', 'no']
)
X_train = df.loc[:4, 'Sex'].to_frame()
y_train = df.loc[:4, 'Survived']
X_test = df.loc[5:, 'Sex'].to_frame()
y_test = df.loc[5:, 'Survived']
my_pipe = Pipeline([
('get_dummies', OneHotEncoder(handle_unknown='ignore'))
])
my_pipe.fit_transform(X_train)
print(my_pipe.transform(X_test).toarray())
# [[1. 0.]
# [0. 0.]
# [0. 1.]]
【讨论】:
【参考方案2】:按照您的代码原样,您的两个转换输出如下:
X_train_trans
female male
0 1 0
1 0 1
2 0 1
3 0 1
4 1 0
X_test_trans
female male neutral
5 1 0 0
6 0 0 1
7 0 1 0
您的问题是:为什么转换器现在在测试集中创建一个“中性”列?看起来原因是因为你声明X_test_trans设置为X_test_trans = my_pipe.transform(X_test)
,它接受X_test
数据,如下:
X_test
5 female
6 neutral
7 male
代码完全按照您的要求执行。所以让我们想一个解决方案:
from sklearn.preprocessing import OneHotEncoder
df = pd.DataFrame(
'Sex':['female', 'male', 'male', 'male', 'female', 'female','neutral', 'male'],
'Survived':['no', 'no', 'yes', 'no', 'yes', 'no', 'yes', 'no']
)
features = pd.DataFrame(OneHotEncoder().fit_transform(df['Sex'].values.reshape(-1, 1)).toarray())
one-hot 编码器会将您的三个类别转换为学习算法可以识别的格式。在此阶段之后,您可以开始将数据拆分为测试和训练using train_test_split:
from sklearn.model_selection import train_test_split
features = pd.DataFrame(OneHotEncoder().fit_transform(df['Sex'].values.reshape(-1, 1)).toarray())
labels = df['Survived']
X_train, X_test, y_train, y_test = train_test_split(features, labels)
【讨论】:
我不能对变量进行热编码然后“train_test_split”,因为测试数据会泄露,导致性能过于乐观。 好点。我建议看看@Venkatachalam 提供的答案以上是关于sklearn 管道在应用于测试集时不记得其状态的主要内容,如果未能解决你的问题,请参考以下文章