python - 自定义 sklearn 变压器类中矩阵 (X) 的维数(行)减少

标签 python class scikit-learn

给出下面的代码,我正在尝试构建的自定义转换器类 - 旨在添加几列并通过网格搜索来运行它 - 本身运行良好,但通过管道执行时行中的维度会下降。也许有人可以解释出了什么问题,我显然在这里遗漏了一些东西。搜索评论“这里发生了什么,维数按行减少?”我在哪里打印了问题。完整的执行代码可以在下面找到!

import pandas as pd
import numpy as np

from sklearn.datasets import load_breast_cancer
from sklearn import linear_model
from sklearn.base import BaseEstimator
from sklearn.base import ClassifierMixin
from sklearn.base import clone
from sklearn.base import TransformerMixin
from sklearn.model_selection import GridSearchCV

from sklearn.pipeline import Pipeline
from sklearn.pipeline import make_pipeline

dict_breast_c = load_breast_cancer()
X = pd.DataFrame(dict_breast_c.data, columns=dict_breast_c.feature_names)
X.columns = [col.replace(" ", "_").replace("mean", "avg") for col in X.columns]
X_sub = X[[col for col in X.columns if col.find("avg") >= 0]]
X_feat_hldr = X[[col for col in X.columns if col not in (X_sub.columns)]]

y = pd.Series(dict_breast_c.target)

print ("Full X matrix shape: {}".format(X_sub.shape))
print ("Full feature holder shape: {}".format(X_feat_hldr.shape))
print ("Target vector: {}".format(y.shape))

class c_FeatureAdder(BaseEstimator, TransformerMixin):

    def __init__(self, X_feat_hldr, add_error_feat = True, add_worst_feat = True): # no *args or **kargs
        self.add_error_feat = add_error_feat
        self.add_worst_feat = add_worst_feat
        self.list_col_error = list_col_error
        self.list_col_wrst = list_col_wrst
        self.X_feat_hldr = X_feat_hldr

    def fit(self, X, y=None):
        return self  # nothing else to do

    def transform(self, X, y=None):

        if self.add_error_feat and not self.add_worst_feat:
            print ("Adding error (std) features:")
            return np.c_([X, self.X_feat_hldr[self.list_col_error]])

        elif not self.add_error_feat and self.add_worst_feat:
            print ("Adding worst features:")
            return np.c_([X, self.X_feat_hldr[self.list_col_wrst]])

        elif self.add_error_feat and self.add_worst_feat:
            # What happends here, dimensionality reduced in rows?
            print ("Adding error (std) features and worst features")
            print ("Feature: {}".format(self.list_col_error))
            print ("Feature: {}".format(self.list_col_wrst))
            print ("Something happends to number of rows! {}".format(X.shape))
            print (self.X_feat_hldr.shape)
            print (np.c_[X, self.X_feat_hldr[self.list_col_wrst].values, self.X_feat_hldr[self.list_col_error].values])
            return np.c_[X, self.X_feat_hldr[self.list_col_wrst].values, self.X_feat_hldr[self.list_col_error].values]

        else:
            print ("Adding no new features, passing indata:")
            return X




# Set a classifier, start with base form of logistic regression
clf_log_reg = linear_model.LogisticRegression(random_state=1234)

# Input into pipeline for doing feature adding to main data
list_col_error = [col for col in X_feat_hldr[0:2] if col.find("error") >= 0][0:1]
list_col_wrst = [col for col in X_feat_hldr[0:2] if col.find("worst") >= 0][0:2]

print (list_col_error)
print (list_col_wrst)

# Generate a pipeline of wanted transformers on data. End with classifier
pipe_log_reg = Pipeline(
    [('add_feat', c_FeatureAdder(X_feat_hldr))
    ,('clf', clf_log_reg)]
)




# Set the parameter grid to be checked for pipe above. Only thing being changed is the adding of features through c_FeatureAdder() class
param_grid = {
    'add_feat__add_error_feat' : [True, False]
    ,'add_feat__add_worst_feat' : [True, False]
    ,'clf__penalty' : ['l2', 'l1']
    ,'clf__C' : [1]
}



# Initialize GridSearch over parameter spacea
gs_lg_reg = GridSearchCV(
    estimator = pipe_log_reg
    ,param_grid = param_grid
    ,scoring = 'accuracy'
    ,n_jobs = 1
)


# Assign names
X_train = X_sub.values
y_train = y.values

print (X_train.shape)

# Fit data
gs_lg_reg_fit = gs_lg_reg.fit(X_train
                              ,y_train)

# Best estimator from GridSearch
gs_optimal_mdl_lg_reg = gs_lg_reg_fit.best_estimator_

最佳答案

你有一些错误。

您在转换器中使用全局变量:

    self.list_col_error = list_col_error
    self.list_col_wrst = list_col_wrst

如果你的转换器需要输入,它应该将其作为构造函数的参数(__init__)。避免依赖类中的全局变量。

您的转换器应该能够转换任意数量的给定样本。

transform 函数的思想是转换任何给定的样本或样本集。在实践中,您可以保留您的转换器,然后使用它来转换任意数量的新给定样本。您应该使用 fit 函数来获取您需要的任何内容作为输入,并相应地适合您的变压器。我们的想法是,一旦您适合整个管道,您应该能够为其提供一个样本,并从管道中获取该样本的输出。

GridSearchCV 默认进行 3 倍交叉验证。

docs 中所述:

cv : int, cross-validation generator or an iterable, optional

Determines the cross-validation splitting strategy. Possible inputs for cv are:

None, to use the default 3-fold cross validation,

这意味着它使用 2/3 的输入数据来适应每个阶段的管道。如果检查输出,您会发现代码提示新数据有 379 行,而旧数据有 569 行。 379/569 = 0.666080844。这就是更改后的行数的来源。

关于python - 自定义 sklearn 变压器类中矩阵 (X) 的维数(行)减少,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49657524/

相关文章:

python - 属性错误: vocabulary not found

scikit-learn - 如何使用 scikit-learn 从线性判别分析中获取特征向量

python - 来自 statsmodels 的自定义估算器 WLS 的 sklearn check_estimator 错误

python - 产量仅与发电机所需的一样多

python - 如何使用 px.bar() 在堆积条形图中显示百分比值?

python - PyQt4:如何暂停线程直到发出信号?

javascript - 超出最大调用堆栈大小 - 没有明显的递归

asp.net - 在 asp.net 中使用像公共(public)变量这样的类

Python绘制极坐标方程

Javascript - 在函数中传递 THIS 不起作用