Scikit-Learn的管道:传递了一个稀疏矩阵,但需要密集的数据



我发现很难理解如何修复我创建的管道(阅读:主要是从教程中粘贴的)。这是python 3.4.2:

df = pd.DataFrame
df = DataFrame.from_records(train)
test = [blah1, blah2, blah3]
pipeline = Pipeline([('vectorizer', CountVectorizer()), ('classifier', RandomForestClassifier())])
pipeline.fit(numpy.asarray(df[0]), numpy.asarray(df[1]))
predicted = pipeline.predict(test)

当我运行它时,我得到:

TypeError: A sparse matrix was passed, but dense data is required. Use X.toarray() to convert to a dense numpy array.

这是针对线路pipeline.fit(numpy.asarray(df[0]), numpy.asarray(df[1]))的。

我已经通过numpy、scipy等尝试了很多解决方案,但我仍然不知道如何解决它。是的,以前也出现过类似的问题,但不是在管道内。我必须在哪里应用toarraytodense

不幸的是,这两者不兼容。CountVectorizer产生稀疏矩阵,而RandomForest分类器需要密集矩阵。可以使用X.todense()进行转换。这样做将大大增加您的内存占用。

以下是基于http://zacstewart.com/2014/08/05/pipelines-of-featureunions-of-pipelines.html它允许您在流水线阶段调用CCD_ 6。

class DenseTransformer(TransformerMixin):
    def fit(self, X, y=None, **fit_params):
        return self
    def transform(self, X, y=None, **fit_params):
        return X.todense()

一旦有了DenseTransformer,就可以将其添加为管道步骤。

pipeline = Pipeline([
     ('vectorizer', CountVectorizer()), 
     ('to_dense', DenseTransformer()), 
     ('classifier', RandomForestClassifier())
])

另一种选择是使用像LinearSVC这样的用于稀疏数据的分类器。

from sklearn.svm import LinearSVC
pipeline = Pipeline([('vectorizer', CountVectorizer()), ('classifier', LinearSVC())])

最简洁的解决方案是使用FunctionTransformer转换为密集:这将自动实现fittransformfit_transform方法,如David的回答所示。此外,如果我的管道步骤不需要特殊的名称,我喜欢使用sklearn.pipeline.make_pipeline便利函数来启用一种更简单的语言来描述模型:

from sklearn.preprocessing import FunctionTransformer
pipeline = make_pipeline(
     CountVectorizer(), 
     FunctionTransformer(lambda x: x.todense(), accept_sparse=True), 
     RandomForestClassifier()
)

0.16-dev中的随机森林现在接受稀疏数据。

您可以使用.values方法将pandas Series更改为数组。

pipeline.fit(df[0].values, df[1].values)

然而,我认为这里发生的问题是因为CountVectorizer()默认返回稀疏矩阵,并且不能通过管道传输到RF分类器。CountVectorizer()确实有一个dtype参数来指定返回的数组类型。也就是说,通常你需要进行某种降维,才能使用随机森林进行文本分类,因为单词袋特征向量很长

我发现FunctionTransformer和使用x.toarray()而不是x.todense()对我有效。

'pipeline': Pipeline(
        [
            ('vect', TfidfVectorizer()),
            ('dense', FunctionTransformer(lambda x: x.toarray(), accept_sparse=True)),
            ('clf', GaussianProcessClassifier())
        ]
    )

使用此管道添加TfidTransformer和

        pipelinEx = Pipeline([('bow',vectorizer),
                           ('tfidf',TfidfTransformer()),
                           ('to_dense', DenseTransformer()), 
                           ('classifier',classifier)])

上面的第一行,以稀疏矩阵的形式获取文档的字数。然而,在实践中,您可能会使用TfidfTransformer在一组新的看不见的文档上计算tfidf分数。然后,通过调用tfidf-transformer.transform(矢量器),您将最终计算文档的tf-idf分数。在内部,这是计算tf*idf乘法,其中项频率由其idf值加权。

相关内容

  • 没有找到相关文章

最新更新