Sklearn:异构特征的FeatureUnion在管道中为分类器提供了不兼容的行维度错误

时间:2017-07-19 14:49:25

标签: python pandas scikit-learn classification feature-extraction

我想根据我拥有的不同功能(包括文本和数字)进行二进制分类。训练数据是熊猫数据帧的形式。我的管道看起来像这样:

final_pipeline = Pipeline([('union', FeatureUnion(
                transformer_list=[('body_trans', Pipeline([('selector', ItemSelector(key='body')),
                                                          ('count_vect', CountVectorizer())])),
                                  ('body_trans2', Pipeline([('selector', ItemSelector(key='body2')),
                                                          ('count_vect', TfidfVectorizer())])),
                                 ('length_trans', Pipeline([('selector', ItemSelector(key='length')),
                                                           ('min_max_scaler',  MinMaxScaler())]))],
                transformer_weights={'body_trans': 1.0,'body_trans2': 1.0,'length_trans': 1.0})),
                          ('svc', SVC())])

ItemSelector如下所示:

class ItemSelector(BaseEstimator, TransformerMixin):
    def __init__(self, key):
        self.key = key

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

    def transform(self, data_frame):
        return data_frame[[self.key]]

现在,当我尝试final_pipeline.fit(X_train, y_train)时,它会给我ValueError: blocks[0,:] has incompatible row dimensions例外。

X_train, X_test, y_train, y_test = train_test_split(train_set, target_set)

是我获取训练数据的方式。 train_set是一个包含字段bodybody2length等的数据框。target_set是一个只有一个名为label的字段的数据框,我的实际标签要分类。

编辑:

我认为我对管道的输入数据格式不正确。

train_set是我的训练数据,其中包含以下功能:

   body           length  body2
0  blah-blah      193     blah-blah-2
1  blah-blah-blah 153     blah-blah-blah-2 

target_set,它是具有分类标签

的DataFrame
  label
0  True
1  False

如果有关于使用DataFrames的Pipeline拟合参数的输入格式的任何教程,请提供链接!我找不到关于如何将多个列作为单独的功能加载DataFrames作为管道输入的适当文档。

感谢任何帮助!

1 个答案:

答案 0 :(得分:3)

问题出在您的ItemSelector中。它输出一个2-d数据帧,但CountVectorizer和TfidfVectorizer需要一个1-d的字符串数组。

显示ItemSelector输出的代码: -

import numpy as np
from pandas import DataFrame
df = DataFrame(columns = ['body','length','body2'],data=np.array([['blah-blah', 193, 'blah-blah-2'],['blah-blah-2', 153, 'blah-blah-blah-2'] ]))

body_selector = ItemSelector(key='body')
df_body = body_selector.fit_transform(df)

df_body.shape
# (2,1)

您可以定义另一个类,它可以将数据以正确的形式提供给下一步。

将此类添加到您的代码中:

class Converter(BaseEstimator, TransformerMixin):
    def fit(self, x, y=None):
        return self

    def transform(self, data_frame):
        return data_frame.values.ravel()

然后像这样定义你的管道:

final_pipeline = Pipeline([('union', FeatureUnion(
                transformer_list=[('body_trans', Pipeline([('selector', ItemSelector(key='body')),
                                                           ('converter', Converter()),
                                                          ('count_vect', CountVectorizer())])),
                                  ('body_trans2', Pipeline([('selector', ItemSelector(key='body2')),
                                                            ('converter', Converter()),
                                                          ('count_vect', TfidfVectorizer())])),
                                 ('length_trans', Pipeline([('selector', ItemSelector(key='length')),
                                                           ('min_max_scaler',  MinMaxScaler())]))],
                transformer_weights={'body_trans': 1.0,'body_trans2': 1.0,'length_trans': 1.0})),
                          ('svc', SVC())])

无需将其添加到第三部分,因为MinMaxScalar需要二维输入数据。

随意询问是否有任何问题。