Scikit-Learn 的 Pipeline:传递了稀疏矩阵,但需要密集数据
Scikit-Learn's Pipeline: A sparse matrix was passed, but dense data is required
我发现很难理解如何修复我创建的管道(阅读:主要从教程中粘贴)。这是 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 等尝试了很多解决方案,但我仍然不知道如何修复它。是的,以前也出现过类似的问题,但不是在管道内。
我必须在哪里申请 toarray
或 todense
?
您可以使用 .values
方法将 pandas Series
更改为数组。
pipeline.fit(df[0].values, df[1].values)
不过我认为这里的问题是因为 CountVectorizer()
returns 默认情况下是一个稀疏矩阵,无法通过管道传输到 RF 分类器。 CountVectorizer()
确实有一个 dtype
参数来指定返回的数组类型。也就是说,通常你需要进行某种降维才能使用随机森林进行文本分类,因为词袋特征向量非常长
不幸的是,这两者不兼容。 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()
获得 DenseTransformer
后,您可以将其添加为管道步骤。
pipeline = Pipeline([
('vectorizer', CountVectorizer()),
('to_dense', DenseTransformer()),
('classifier', RandomForestClassifier())
])
另一种选择是使用用于 LinearSVC
等稀疏数据的分类器。
from sklearn.svm import LinearSVC
pipeline = Pipeline([('vectorizer', CountVectorizer()), ('classifier', LinearSVC())])
0.16-dev 中的随机森林现在接受稀疏数据。
最简洁的解决方案是使用 FunctionTransformer
转换为密集:这将自动实现 David 的回答中的 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()
)
使用此管道添加 TfidTransformer plus
pipelinEx = Pipeline([('bow',vectorizer),
('tfidf',TfidfTransformer()),
('to_dense', DenseTransformer()),
('classifier',classifier)])
上面的第一行,以稀疏矩阵形式获取文档的字数。但是,在实践中,您可能会使用 TfidfTransformer 在一组新的未见过的文档上计算 tfidf 分数。
然后,通过调用 tfidf transformer.transform(vectorizer),您最终将计算文档的 tf-idf 分数。在内部这是计算 tf * idf 乘法,其中术语频率由其 idf 值加权。
我发现很难理解如何修复我创建的管道(阅读:主要从教程中粘贴)。这是 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 等尝试了很多解决方案,但我仍然不知道如何修复它。是的,以前也出现过类似的问题,但不是在管道内。
我必须在哪里申请 toarray
或 todense
?
您可以使用 .values
方法将 pandas Series
更改为数组。
pipeline.fit(df[0].values, df[1].values)
不过我认为这里的问题是因为 CountVectorizer()
returns 默认情况下是一个稀疏矩阵,无法通过管道传输到 RF 分类器。 CountVectorizer()
确实有一个 dtype
参数来指定返回的数组类型。也就是说,通常你需要进行某种降维才能使用随机森林进行文本分类,因为词袋特征向量非常长
不幸的是,这两者不兼容。 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()
获得 DenseTransformer
后,您可以将其添加为管道步骤。
pipeline = Pipeline([
('vectorizer', CountVectorizer()),
('to_dense', DenseTransformer()),
('classifier', RandomForestClassifier())
])
另一种选择是使用用于 LinearSVC
等稀疏数据的分类器。
from sklearn.svm import LinearSVC
pipeline = Pipeline([('vectorizer', CountVectorizer()), ('classifier', LinearSVC())])
0.16-dev 中的随机森林现在接受稀疏数据。
最简洁的解决方案是使用 FunctionTransformer
转换为密集:这将自动实现 David 的回答中的 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()
)
使用此管道添加 TfidTransformer plus
pipelinEx = Pipeline([('bow',vectorizer),
('tfidf',TfidfTransformer()),
('to_dense', DenseTransformer()),
('classifier',classifier)])
上面的第一行,以稀疏矩阵形式获取文档的字数。但是,在实践中,您可能会使用 TfidfTransformer 在一组新的未见过的文档上计算 tfidf 分数。 然后,通过调用 tfidf transformer.transform(vectorizer),您最终将计算文档的 tf-idf 分数。在内部这是计算 tf * idf 乘法,其中术语频率由其 idf 值加权。