我刚刚阅读了k-fold交叉验证,并意识到我无意中使用当前的预处理设置泄漏了数据。
通常,我有一个火车和测试数据集。我在整个火车数据集上做了一堆数据插补和一次热编码,然后运行k-fold交叉验证。
泄漏是因为,如果我进行5倍交叉验证,我会对80%的列车数据进行培训,并对其余20%的列车数据进行测试。
我真的应该根据80%的火车来估算20%(而我之前使用的是100%的数据)。
1)这是考虑交叉验证的正确方法吗?
2)我一直在查看Pipeline
中的sklearn.pipeline
类,这对于进行一系列转换然后最终将模型拟合到结果数据似乎很有用。但是,我正在做一些类似于"在float64
列中使用平均值","使用模式"等来归咎所有其他数据的错误数据
对于这种插补,没有明显的变压器。如何将此步骤添加到Pipeline
?我会创建自己的BaseEstimator
的子类吗?
这里的任何指导都会很棒!
答案 0 :(得分:2)
1)是的,你应该使用80%的训练数据来估算20%的测试数据。
2)我写了a blog post来回答你的第二个问题,但我会在这里包含核心部分。
使用sklearn.pipeline
,您可以将不同的预处理规则应用于不同的要素类型(例如,数字,分类)。在下面的示例代码中,我在缩放它们之前估算了数字特征的中位数。分类和布尔特征用模式估算 - 分类特征是单热编码。
您可以在管道末尾添加估算器以进行回归,分类等。
import numpy as np
from sklearn.pipeline import make_pipeline, FeatureUnion
from sklearn.preprocessing import OneHotEncoder, Imputer, StandardScaler
preprocess_pipeline = make_pipeline(
FeatureUnion(transformer_list=[
("numeric_features", make_pipeline(
TypeSelector(np.number),
Imputer(strategy="median"),
StandardScaler()
)),
("categorical_features", make_pipeline(
TypeSelector("category"),
Imputer(strategy="most_frequent"),
OneHotEncoder()
)),
("boolean_features", make_pipeline(
TypeSelector("bool"),
Imputer(strategy="most_frequent")
))
])
)
管道的TypeSelector
部分假定对象X
是pandas DataFrame
。使用TypeSelector.transform
选择具有给定数据类型的列子集。
from sklearn.base import BaseEstimator, TransformerMixin
import pandas as pd
class TypeSelector(BaseEstimator, TransformerMixin):
def __init__(self, dtype):
self.dtype = dtype
def fit(self, X, y=None):
return self
def transform(self, X):
assert isinstance(X, pd.DataFrame)
return X.select_dtypes(include=[self.dtype])
答案 1 :(得分:0)
我建议将5倍交叉验证视为简单地将数据分成5个部分(或折叠)。您可以支持一次测试,并将其他4个一起用于训练集。我们再重复这个过程4次,直到每次折叠都有机会进行测试。
为了使您的估算工作正确并且不受污染,您需要确定用于测试的4倍的平均值,并使用它来在训练集和测试集中估算该值。
我喜欢用StratifiedKFold实现CV拆分。这将确保您在折叠中的每个类具有相同数量的样本。
要回答关于使用Pipelines的问题,我想你应该用你的自定义Imputation变换器将BaseEstimator子类化。在CV-split的循环内部,您应该从训练集计算平均值,然后将此平均值设置为变换器中的参数。然后你可以调用fit或transform。