带有SkLearn Pipeline的GridSearch无法正常工作

时间:2018-07-02 22:10:03

标签: python-3.x dataframe scikit-learn pipeline grid-search

我为列名称以数字开头的部分功能实现了自定义PCA,并在PCA之后将其与其余功能结合在一起。然后在网格搜索中实现GBRT模型作为sklearn管道。管道本身可以很好地工作,但是使用GridSearch时,每次给出错误似乎都占用了一部分数据。定制的PCA是:

class PartialPCA(BaseEstimator, TransformerMixin):

def __init__(self, n_components=0.9995, svd_solver='full', mask=None):
    # mask should contain selected cols. Suppose it is boolean to avoid code overhead
    self.n_components = n_components
    self.svd_solver = svd_solver
    self.mask = mask

def fit(self, X, y=None):
    print(X.shape)
    print(type(X))
    X.to_csv('InitialX.csv')
    print(X.isnull().values.any())
    X.reset_index(inplace=True, drop=True)
    self.remaining_cols = X[[i for i in X.columns if i[0].isdigit() is False]].copy()
    self.pca = PCA(n_components=self.n_components, svd_solver=self.svd_solver)
    mask = self.mask if self.mask is not None else slice(None)
    self.pca.fit(X[mask])
    return self

def transform(self, X, y=None):
    mask = self.mask if self.mask is not None else slice(None)
    pca_transformed = self.pca.transform(X[mask])
    if self.mask is not None:
        print(pca_transformed.shape)
        col_no = pca_transformed.shape[1]
        pca_transformed = pd.DataFrame(data=pca_transformed, columns=range(1, col_no + 1))
        X = pd.concat(objs=(self.remaining_cols, pca_transformed), axis=1)
        X.to_csv('X.csv')
        print(X.isnull().values.any())
        print(pca_transformed.isnull().values.any())
        print(self.remaining_cols.isnull().values.any())
        return X
    else:
        return pca_transformed

然后由

调用
mask = [i for i in trainPredTrans.columns if i[0].isdigit() is True]
pca = PartialPCA(n_components=0.9995, svd_solver='full', mask=mask)
print(pca)
gbrt = GradientBoostingRegressor(n_estimators=100, random_state=10)
pipe = Pipeline(steps=[('pca', pca), ('gbrt', gbrt)])
estimator = model_selection.GridSearchCV(pipe,param_grid=[dict(pca__svd_solver=['auto','full','arpack']),
                                               dict(gbrt__learning_rate=[0.1,  0.2,  0.3, 0.4,  0.5],
                                                                    gbrt__loss=["ls", "lad", "huber", "quantile"],
                                                                    gbrt__max_depth=[3, 4, 5],
                                                                    gbrt__min_samples_split=[2, 3, 4])])
print(estimator)
trainPredTrans.to_csv('trainPredTrans.csv')
estimator.fit(trainPredTrans, trainTarget.values.ravel())

输入火车数据框的形状为(1198,1248),但是在函数内部,当我打印X.shape时,它的形状为(798,1248),拟合后变为(798,97),似乎再次迭代,给出一个错误,指出输入具有nan值,该值是由于连接两个不同大小的数据帧而发生的(但应该具有相同大小)。 我花了很多时间,但无法弄清楚这个问题,以及为什么不使用gridsearch就能解决这个问题。似乎Gridsearch正在使用gbrt参数对pca进行迭代,这是不应该发生的

1 个答案:

答案 0 :(得分:0)

那是因为训练和测试数据的长度。 GridSearcCV将根据cv参数将数据拆分为训练和测试。因此,火车数据的长度将更多,并保存到self.remaining_cols中,当测试数据到达transform()时,您尝试将具有更多样本的原始self.remaining_cols附加到新数据中因此,新数据会附加Nans以匹配长度。

要解决此问题,建议您将self.remaining_cols逻辑移至transform()而不是fit()。像这样:

...
...
def fit(self, X, y=None):
    X.reset_index(inplace=True, drop=True)
    self.pca = PCA(n_components=self.n_components, svd_solver=self.svd_solver)
    mask = self.mask if self.mask is not None else slice(None)
    self.pca.fit(X[mask])
    return self

def transform(self, X, y=None):
    mask = self.mask if self.mask is not None else slice(None)
    X.reset_index(inplace=True, drop=True)
    pca_transformed = self.pca.transform(X[mask])
    if self.mask is not None:
        col_no = pca_transformed.shape[1]
        pca_transformed = pd.DataFrame(data=pca_transformed, columns=range(1, col_no + 1))
        self.remaining_cols = X[[i for i in X.columns if i[0].isdigit() is False]].copy()
        X = pd.concat(objs=(self.remaining_cols, pca_transformed), axis=1)
        return X
    else:
        return pca_transformed

此外,要执行此类操作,其中只选择一部分列进行某些处理,我建议您按照本示例中的说明研究FeatureUnion和ItemSelector:

注意::我观察到您将参数空间定义为两个字典。您不应该将字典的列表发送到GridSearchCV会使它们排他。这意味着它们将被单独计算,而不是相互组合。