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

Ada*_*tra 27 python numpy pandas scikit-learn

我发现很难理解如何修复我创建的Pipeline(阅读:主要是从教程中粘贴).这是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)
Run Code Online (Sandbox Code Playgroud)

当我运行它时,我得到:

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

这是为了线pipeline.fit(numpy.asarray(df[0]), numpy.asarray(df[1])).

我已经通过numpy,scipy等方式尝试了很多解决方案,但我仍然不知道如何修复它.是的,之前出现过类似的问题,但不是在管道内.我必须在哪里申请toarraytodense

Dav*_*ust 50

不幸的是,这两者是不相容的.A CountVectorizer产生稀疏矩阵,RandomForestClassifier需要密集矩阵.可以使用转换X.todense().这样做会大大增加您的内存占用.

下面是基于http://zacstewart.com/2014/08/05/pipelines-of-featureunions-of-pipelines.html执行此操作的示例代码,它允许您.todense()在管道阶段进行调用.

class DenseTransformer(TransformerMixin):

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

    def transform(self, X, y=None, **fit_params):
        return X.todense()
Run Code Online (Sandbox Code Playgroud)

拥有后DenseTransformer,您可以将其添加为管道步骤.

pipeline = Pipeline([
     ('vectorizer', CountVectorizer()), 
     ('to_dense', DenseTransformer()), 
     ('classifier', RandomForestClassifier())
])
Run Code Online (Sandbox Code Playgroud)

另一个选择是使用一个用于稀疏数据的分类器LinearSVC.

from sklearn.svm import LinearSVC
pipeline = Pipeline([('vectorizer', CountVectorizer()), ('classifier', LinearSVC())])
Run Code Online (Sandbox Code Playgroud)


max*_*moo 18

最简洁的解决办法是使用FunctionTransformer转换为密:这会自动执行fit,transform并且fit_transform方法在大卫的回答.另外,如果我的管道步骤不需要特殊名称,我喜欢使用sklearn.pipeline.make_pipeline便利功能来使用更简约的语言来描述模型:

from sklearn.preprocessing import FunctionTransformer

pipeline = make_pipeline(
     CountVectorizer(), 
     FunctionTransformer(lambda x: x.todense(), accept_sparse=True), 
     RandomForestClassifier()
)
Run Code Online (Sandbox Code Playgroud)


Gil*_*ppe 16

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


JAB*_*JAB 5

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

pipeline.fit(df[0].values, df[1].values)
Run Code Online (Sandbox Code Playgroud)

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

  • 我明白了,非常感谢,现在明白了。我尝试给你点赞,但我的声誉不够? (2认同)