如何在 scikit-learn 管道中的 CountVectorizer 之前包含 SimpleImputer?
How to include SimpleImputer before CountVectorizer in a scikit-learn Pipeline?
我有一个包含一列文本的 pandas DataFrame
,我想 使用 scikit-learn 的 [=13] 向量化文本 =].但是,文本包含缺失值,因此我想 在矢量化之前估算一个常数值。
我最初的想法是创建一个 Pipeline
的 SimpleImputer
和 CountVectorizer
:
import pandas as pd
import numpy as np
df = pd.DataFrame({'text':['abc def', 'abc ghi', np.nan]})
from sklearn.impute import SimpleImputer
imp = SimpleImputer(strategy='constant')
from sklearn.feature_extraction.text import CountVectorizer
vect = CountVectorizer()
from sklearn.pipeline import make_pipeline
pipe = make_pipeline(imp, vect)
pipe.fit_transform(df[['text']]).toarray()
然而,fit_transform
错误是因为 SimpleImputer
输出一个 2D 数组 而 CountVectorizer
需要 1D 输入。这是错误消息:
AttributeError: 'numpy.ndarray' object has no attribute 'lower'
问题:我如何修改这个 Pipeline
才能正常工作?
注意: 我知道我可以在 pandas 中估算缺失值。但是,我想在 scikit-learn 中完成所有预处理,以便可以使用 Pipeline
.
将相同的预处理应用于新数据
我找到的最佳解决方案是 将自定义转换器 插入 Pipeline
中,将 SimpleImputer
的输出从 2D 重塑为 1D 之前传递给 CountVectorizer
.
完整代码如下:
import pandas as pd
import numpy as np
df = pd.DataFrame({'text':['abc def', 'abc ghi', np.nan]})
from sklearn.impute import SimpleImputer
imp = SimpleImputer(strategy='constant')
from sklearn.feature_extraction.text import CountVectorizer
vect = CountVectorizer()
# CREATE TRANSFORMER
from sklearn.preprocessing import FunctionTransformer
one_dim = FunctionTransformer(np.reshape, kw_args={'newshape':-1})
# INCLUDE TRANSFORMER IN PIPELINE
from sklearn.pipeline import make_pipeline
pipe = make_pipeline(imp, one_dim, vect)
pipe.fit_transform(df[['text']]).toarray()
proposed on GitHub CountVectorizer
应该允许二维输入,只要第二维为 1(意思是:单列数据)。对 CountVectorizer
的修改将是解决此问题的好方法!
一个解决方案是创建一个 class 关闭 SimpleImputer 并覆盖其 transform()
方法:
import pandas as pd
import numpy as np
from sklearn.impute import SimpleImputer
class ModifiedSimpleImputer(SimpleImputer):
def transform(self, X):
return super().transform(X).flatten()
df = pd.DataFrame({'text':['abc def', 'abc ghi', np.nan]})
imp = ModifiedSimpleImputer(strategy='constant')
from sklearn.feature_extraction.text import CountVectorizer
vect = CountVectorizer()
from sklearn.pipeline import make_pipeline
pipe = make_pipeline(imp, vect)
pipe.fit_transform(df[['text']]).toarray()
当我有一维数据时,我将这个一维包装器用于 sklearn Transformer。我认为,在您的情况下,此包装器可用于包装一维数据(具有字符串值的 pandas 系列)的 simpleImputer。
class OneDWrapper:
"""One dimensional wrapper for sklearn Transformers"""
def __init__(self, transformer):
self.transformer = transformer
def fit(self, X, y=None):
self.transformer.fit(np.array(X).reshape(-1, 1))
return self
def transform(self, X, y=None):
return self.transformer.transform(
np.array(X).reshape(-1, 1)).ravel()
def inverse_transform(self, X, y=None):
return self.transformer.inverse_transform(
np.expand_dims(X, axis=1)).ravel()
现在,您不需要管道中的额外步骤。
one_d_imputer = OneDWrapper(SimpleImputer(strategy='constant'))
pipe = make_pipeline(one_d_imputer, vect)
pipe.fit_transform(df['text']).toarray()
# note we are feeding a pd.Series here!
我有一个包含一列文本的 pandas DataFrame
,我想 使用 scikit-learn 的 [=13] 向量化文本 =].但是,文本包含缺失值,因此我想 在矢量化之前估算一个常数值。
我最初的想法是创建一个 Pipeline
的 SimpleImputer
和 CountVectorizer
:
import pandas as pd
import numpy as np
df = pd.DataFrame({'text':['abc def', 'abc ghi', np.nan]})
from sklearn.impute import SimpleImputer
imp = SimpleImputer(strategy='constant')
from sklearn.feature_extraction.text import CountVectorizer
vect = CountVectorizer()
from sklearn.pipeline import make_pipeline
pipe = make_pipeline(imp, vect)
pipe.fit_transform(df[['text']]).toarray()
然而,fit_transform
错误是因为 SimpleImputer
输出一个 2D 数组 而 CountVectorizer
需要 1D 输入。这是错误消息:
AttributeError: 'numpy.ndarray' object has no attribute 'lower'
问题:我如何修改这个 Pipeline
才能正常工作?
注意: 我知道我可以在 pandas 中估算缺失值。但是,我想在 scikit-learn 中完成所有预处理,以便可以使用 Pipeline
.
我找到的最佳解决方案是 将自定义转换器 插入 Pipeline
中,将 SimpleImputer
的输出从 2D 重塑为 1D 之前传递给 CountVectorizer
.
完整代码如下:
import pandas as pd
import numpy as np
df = pd.DataFrame({'text':['abc def', 'abc ghi', np.nan]})
from sklearn.impute import SimpleImputer
imp = SimpleImputer(strategy='constant')
from sklearn.feature_extraction.text import CountVectorizer
vect = CountVectorizer()
# CREATE TRANSFORMER
from sklearn.preprocessing import FunctionTransformer
one_dim = FunctionTransformer(np.reshape, kw_args={'newshape':-1})
# INCLUDE TRANSFORMER IN PIPELINE
from sklearn.pipeline import make_pipeline
pipe = make_pipeline(imp, one_dim, vect)
pipe.fit_transform(df[['text']]).toarray()
proposed on GitHub CountVectorizer
应该允许二维输入,只要第二维为 1(意思是:单列数据)。对 CountVectorizer
的修改将是解决此问题的好方法!
一个解决方案是创建一个 class 关闭 SimpleImputer 并覆盖其 transform()
方法:
import pandas as pd
import numpy as np
from sklearn.impute import SimpleImputer
class ModifiedSimpleImputer(SimpleImputer):
def transform(self, X):
return super().transform(X).flatten()
df = pd.DataFrame({'text':['abc def', 'abc ghi', np.nan]})
imp = ModifiedSimpleImputer(strategy='constant')
from sklearn.feature_extraction.text import CountVectorizer
vect = CountVectorizer()
from sklearn.pipeline import make_pipeline
pipe = make_pipeline(imp, vect)
pipe.fit_transform(df[['text']]).toarray()
当我有一维数据时,我将这个一维包装器用于 sklearn Transformer。我认为,在您的情况下,此包装器可用于包装一维数据(具有字符串值的 pandas 系列)的 simpleImputer。
class OneDWrapper:
"""One dimensional wrapper for sklearn Transformers"""
def __init__(self, transformer):
self.transformer = transformer
def fit(self, X, y=None):
self.transformer.fit(np.array(X).reshape(-1, 1))
return self
def transform(self, X, y=None):
return self.transformer.transform(
np.array(X).reshape(-1, 1)).ravel()
def inverse_transform(self, X, y=None):
return self.transformer.inverse_transform(
np.expand_dims(X, axis=1)).ravel()
现在,您不需要管道中的额外步骤。
one_d_imputer = OneDWrapper(SimpleImputer(strategy='constant'))
pipe = make_pipeline(one_d_imputer, vect)
pipe.fit_transform(df['text']).toarray()
# note we are feeding a pd.Series here!