如何创建一个适用于tf-idf向量化器的scikit管道?

3
我正在学习官方sklearn tutorial ,学习如何创建用于文本数据分析的流水线,并将其用于网格搜索。但是,我遇到了一个问题,给出的方法对于这种情况不起作用。
我希望这段代码能够正常工作:
import numpy as np
import pandas as pd
from sklearn.pipeline import Pipeline
from mlxtend.feature_selection import ColumnSelector
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.naive_bayes import BernoulliNB
from sklearn.feature_extraction.text import TfidfVectorizer


df_Xtrain = pd.DataFrame({'tweet': ['This is a tweet']*10,
                          'label': 0})
y_train = df_Xtrain['label'].to_numpy().ravel()

pipe = Pipeline([
    ('col_selector', ColumnSelector(cols=('tweet'))),
    ('tfidf', TfidfTransformer()),
    ('bernoulli', BernoulliNB()),
])


pipe.fit(df_Xtrain,y_train)

这段代码有效:

import numpy as np
import pandas as pd
from sklearn.pipeline import Pipeline
from mlxtend.feature_selection import ColumnSelector
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.naive_bayes import BernoulliNB
from sklearn.feature_extraction.text import TfidfVectorizer

# data
df_Xtrain = pd.DataFrame({'tweet': ['This is a tweet']*10,
                          'label': 0})
y_train = df_Xtrain['label'].to_numpy().ravel()

# modelling
mc = 'tweet'
vec_tfidf = TfidfVectorizer()

vec_tfidf.fit(df_Xtrain[mc])

X_train = vec_tfidf.transform(df_Xtrain[mc]).toarray()


model = BernoulliNB()
model.fit(X_train,y_train)
model.predict(X_train)
model.score(X_train,y_train)

问题

如何制作像上面那样的文本分析流程?

更新

版本

[('numpy', '1.17.5'),
 ('pandas', '1.0.5'),
 ('sklearn', '0.23.1'),
 ('mlxtend', '0.17.0')]

Python 3.7.7

错误日志
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-1-3012ce7245d9> in <module>
     19 
     20 
---> 21 pipe.fit(df_Xtrain,y_train)

~/opt/miniconda3/envs/spk/lib/python3.7/site-packages/sklearn/pipeline.py in fit(self, X, y, **fit_params)
    328         """
    329         fit_params_steps = self._check_fit_params(**fit_params)
--> 330         Xt = self._fit(X, y, **fit_params_steps)
    331         with _print_elapsed_time('Pipeline',
    332                                  self._log_message(len(self.steps) - 1)):

~/opt/miniconda3/envs/spk/lib/python3.7/site-packages/sklearn/pipeline.py in _fit(self, X, y, **fit_params_steps)
    294                 message_clsname='Pipeline',
    295                 message=self._log_message(step_idx),
--> 296                 **fit_params_steps[name])
    297             # Replace the transformer of the step with the fitted
    298             # transformer. This is necessary when loading the transformer

~/opt/miniconda3/envs/spk/lib/python3.7/site-packages/joblib/memory.py in __call__(self, *args, **kwargs)
    350 
    351     def __call__(self, *args, **kwargs):
--> 352         return self.func(*args, **kwargs)
    353 
    354     def call_and_shelve(self, *args, **kwargs):

~/opt/miniconda3/envs/spk/lib/python3.7/site-packages/sklearn/pipeline.py in _fit_transform_one(transformer, X, y, weight, message_clsname, message, **fit_params)
    738     with _print_elapsed_time(message_clsname, message):
    739         if hasattr(transformer, 'fit_transform'):
--> 740             res = transformer.fit_transform(X, y, **fit_params)
    741         else:
    742             res = transformer.fit(X, y, **fit_params).transform(X)

~/opt/miniconda3/envs/spk/lib/python3.7/site-packages/sklearn/base.py in fit_transform(self, X, y, **fit_params)
    691         else:
    692             # fit method of arity 2 (supervised transformation)
--> 693             return self.fit(X, y, **fit_params).transform(X)
    694 
    695 

~/opt/miniconda3/envs/spk/lib/python3.7/site-packages/sklearn/feature_extraction/text.py in fit(self, X, y)
   1429             A matrix of term/token counts.
   1430         """
-> 1431         X = check_array(X, accept_sparse=('csr', 'csc'))
   1432         if not sp.issparse(X):
   1433             X = sp.csr_matrix(X)

~/opt/miniconda3/envs/spk/lib/python3.7/site-packages/sklearn/utils/validation.py in inner_f(*args, **kwargs)
     71                           FutureWarning)
     72         kwargs.update({k: arg for k, arg in zip(sig.parameters, args)})
---> 73         return f(**kwargs)
     74     return inner_f
     75 

~/opt/miniconda3/envs/spk/lib/python3.7/site-packages/sklearn/utils/validation.py in check_array(array, accept_sparse, accept_large_sparse, dtype, order, copy, force_all_finite, ensure_2d, allow_nd, ensure_min_samples, ensure_min_features, estimator)
    597                     array = array.astype(dtype, casting="unsafe", copy=False)
    598                 else:
--> 599                     array = np.asarray(array, order=order, dtype=dtype)
    600             except ComplexWarning:
    601                 raise ValueError("Complex data not supported\n"

~/opt/miniconda3/envs/spk/lib/python3.7/site-packages/numpy/core/_asarray.py in asarray(a, dtype, order)
     83 
     84     """
---> 85     return array(a, dtype, copy=False, order=order)
     86 
     87 

ValueError: could not convert string to float: 'This is a tweet'


“我遇到了一个问题,但给出的方法对于这种情况并不适用”是非常模糊的描述,我们需要更多细节。在Stack Overflow上提问时必须提供最小可重现示例 [MCVE]。请具体说明错误、追踪和显示哪一行代码导致了它。然后,展示你采取的调试步骤以及你所卡住的具体问题。 - smci
此外,无需多言,请发布您使用的Python版本(3.7?/8?)、numpy、pandas、scikit-learn、mlxtend等软件包的版本。如果您使用Anaconda(哪个版本?)作为软件包管理器,并且操作系统和版本与您的错误有关,请也一并提供。 - smci
请检查我的答案,应该可以解决你的问题。 - Akshay Sehgal
仍然缺少重要信息:请发布具体的错误、追踪以及显示导致错误的代码行。 - smci
好的,谢谢你终于发布了。你仍然应该在问题文本中澄清问题所在,而不仅仅是“这段代码不起作用”(将问题完全依赖于代码的具体细节并不是一个好的做法)。 - smci
1个回答

6
你的代码存在两个主要问题:
  1. 你使用了 tfidftransformer,却没有在它之前使用 countvectorizer。你可以直接使用 tfidfvectorizer 来同时完成这两个步骤。
  2. columnselector 返回的是一个二维数组 (n,1),而 tfidfvectorizer 需要的是一个一维数组 (n,)。你可以通过设置参数 drop_axis = True 来实现。
针对以上问题做出修改后,代码会正常运行:
import numpy as np
import pandas as pd
from sklearn.pipeline import Pipeline
from mlxtend.feature_selection import ColumnSelector
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import BernoulliNB



df_Xtrain = pd.DataFrame({'tweet': ['This is a tweet']*10,
                          'label': 0})
y_train = df_Xtrain['label'].to_numpy().ravel()

pipe = Pipeline([
    ('col_selector', ColumnSelector(cols=('tweet'),drop_axis=True)),
    ('tfidf', TfidfVectorizer()),
    ('bernoulli', BernoulliNB()),
])


pipe.fit(df_Xtrain,y_train)

Pipeline(steps=[('col_selector', ColumnSelector(cols='tweet', drop_axis=True)),
                ('tfidf', TfidfVectorizer()), ('bernoulli', BernoulliNB())])

编辑:回答问题 - “是否可以在不使用mlxtend包的情况下实现?为什么我需要ColumnSelector?是否可以只使用sklearn来解决?”

是的,如我下面所述,您将不得不构建自己的列选择器类(这也是如何构建自己的转换器以添加到管道中的方法)。

class SelectColumnsTransformer():
    def __init__(self, columns=None):
        self.columns = columns

    def transform(self, X, **transform_params):
        cpy_df = X[self.columns].copy()
        return cpy_df

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


# Add it to a pipeline 
pipe = Pipeline([
    ('selector', SelectColumnsTransformer([<input col name here>]))
])

请参考此链接了解如何使用它进行操作。

这是否可以在没有mlxtend包的情况下实现?我为什么需要ColumnSelector?有没有只使用sklearn的解决方案? - fuuman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接