使用Pipeline sklearn(Python)的多个自定义类

时间:2017-04-19 14:57:56

标签: python pandas machine-learning scikit-learn pipeline

我尝试为学生做一个关于Pipeline的教程,但我阻止了。我不是专家,但我正努力改进。谢谢你的放纵。 实际上,我尝试在管道中执行几个步骤来为分类器准备数据帧:

  • 步骤1:数据帧描述
  • 第2步:填写NaN值
  • 第3步:将分类值转换为数字

这是我的代码:

class Descr_df(object):

    def transform (self, X):
        print ("Structure of the data: \n {}".format(X.head(5)))
        print ("Features names: \n {}".format(X.columns))
        print ("Target: \n {}".format(X.columns[0]))
        print ("Shape of the data: \n {}".format(X.shape))

    def fit(self, X, y=None):
        return self

class Fillna(object):

    def transform(self, X):
        non_numerics_columns = X.columns.difference(X._get_numeric_data().columns)
        for column in X.columns:
            if column in non_numerics_columns:
                X[column] = X[column].fillna(df[column].value_counts().idxmax())
            else:
                 X[column] = X[column].fillna(X[column].mean())            
        return X

    def fit(self, X,y=None):
        return self

class Categorical_to_numerical(object):

    def transform(self, X):
        non_numerics_columns = X.columns.difference(X._get_numeric_data().columns)
        le = LabelEncoder()
        for column in non_numerics_columns:
            X[column] = X[column].fillna(X[column].value_counts().idxmax())
            le.fit(X[column])
            X[column] = le.transform(X[column]).astype(int)
        return X

    def fit(self, X, y=None):
        return self

如果我执行步骤1和2或步骤1和3,它可以工作,但如果我同时执行步骤1,2和3。我有这个错误:

pipeline = Pipeline([('df_intropesction', Descr_df()), ('fillna',Fillna()), ('Categorical_to_numerical', Categorical_to_numerical())])
pipeline.fit(X, y)
AttributeError: 'NoneType' object has no attribute 'columns'

1 个答案:

答案 0 :(得分:3)

出现此错误是因为在管道中,第一个估算器的输出转到第二个估算器,然后第二个估算器的输出转到第三个,依此类推......

来自documentation of Pipeline

  

一个接一个地适应所有变换并转换数据,   然后使用最终估算器拟合转换后的数据。

因此,对于您的管道,执行步骤如下:

  1. Descr_df.fit(X) - >没有做任何事情并且自我回报
  2. newX = Descr_df.transform(X) - >应该返回一些值来分配给应该传递给下一个估算器的newX,但是你的定义不返回任何东西(只打印)。所以没有隐含地返回
  3. Fillna.fit(newX) - >没有做任何事情并且自我回报
  4. Fillna.transform(newX) - >调用newX.columns。但是步骤2中的newX = None。因此错误。
  5. 解决方案:更改Descr_df的转换方法以按原样返回数据框:

    def transform (self, X):
        print ("Structure of the data: \n {}".format(X.head(5)))
        print ("Features names: \n {}".format(X.columns))
        print ("Target: \n {}".format(X.columns[0]))
        print ("Shape of the data: \n {}".format(X.shape))
        return X
    

    建议:让您的类继承自scikit中的Base Estimator和Transformer类,以确认良好做法。

    即将class Descr_df(object)更改为class Descr_df(BaseEstimator, TransformerMixin),将Fillna(object)更改为Fillna(BaseEstimator, TransformerMixin),依此类推。

    有关Pipeline中自定义类的更多详细信息,请参阅此示例: