pandas 数据框上的自定义 word2vec 转换器并在 FeatureUnion 中使用它
Custom word2vec Transformer on pandas dataframe and using it in FeatureUnion
对于下面的 pandas DataFrame df
,我想将 type
列转换为 OneHotEncoding,并使用字典将 word
列转换为其矢量表示word2vec
。然后我想将两个转换后的向量与 count
列连接起来,形成 classification 的最终特征。
>>> df
word type count
0 apple A 4
1 cat B 3
2 mountain C 1
>>> df.dtypes
word object
type category
count int64
>>> word2vec
{'apple': [0.1, -0.2, 0.3], 'cat': [0.2, 0.2, 0.3], 'mountain': [0.4, -0.2, 0.3]}
我定义了自定义的 Transformer
,并使用 FeatureUnion
连接特征。
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.pipeline import Pipeline, FeatureUnion
from sklearn.preprocessing import OneHotEncoder
class w2vTransformer(TransformerMixin):
def __init__(self,word2vec):
self.word2vec = word2vec
def fit(self,x, y=None):
return self
def wv(self, w):
return self.word2vec[w] if w in self.word2vec else [0, 0, 0]
def transform(self, X, y=None):
return df['word'].apply(self.wv)
pipeline = Pipeline([
('features', FeatureUnion(transformer_list=[
# Part 1: get integer column
('numericals', Pipeline([
('selector', TypeSelector(np.number)),
])),
# Part 2: get category column and its onehotencoding
('categoricals', Pipeline([
('selector', TypeSelector('category')),
('labeler', StringIndexer()),
('encoder', OneHotEncoder(handle_unknown='ignore')),
])),
# Part 3: transform word to its embedding
('word2vec', Pipeline([
('w2v', w2vTransformer(word2vec)),
]))
])),
])
当我运行pipeline.fit_transform(df)
时,我得到了错误:blocks[0,:] has incompatible row dimensions. Got blocks[0,2].shape[0] == 1, expected 3.
但是,如果我从管道中删除 word2vec 转换器(第 3 部分),则管道(第 1 部分 1 + 第 2 部分)工作正常。
>>> pipeline_no_word2vec.fit_transform(df).todense()
matrix([[4., 1., 0., 0.],
[3., 0., 1., 0.],
[1., 0., 0., 1.]])
如果我 只保留 管道中的 w2v 转换器,它也可以工作。
>>> pipeline_only_word2vec.fit_transform(df)
array([list([0.1, -0.2, 0.3]), list([0.2, 0.2, 0.3]),
list([0.4, -0.2, 0.3])], dtype=object)
我的猜测是我的 w2vTransformer
class 有问题,但不知道如何修复。请帮忙。
此错误是由于 FeatureUnion 需要其每个部分的二维数组。
现在您的 FeatureUnion 的前两部分:- 'numericals'
和 'categoricals'
正确发送形状为 (n_samples、n_features) 的二维数据。
n_samples
= 3 在您的示例数据中。 n_features
将取决于各个部分(例如 OneHotEncoder 将在第二部分更改它们,但在第一部分将更改为 1)。
但是第三部分 'word2vec'
returns 一个 pandas.Series 具有一维形状的对象 (3,)
。 FeatureUnion 默认采用形状 (1, 3),因此抱怨它与其他块不匹配。
所以你需要修正那个形状。
现在即使你简单地在最后做一个reshape()
并将它变成形状(3,1),你的代码也不会运行,因为那个数组的内部内容是列表来自您的 word2vec dict,它们未正确转换为二维数组。相反,它会变成一个列表数组。
更改w2vTransformer以更正错误:
class w2vTransformer(TransformerMixin):
...
...
def transform(self, X, y=None):
return np.array([np.array(vv) for vv in X['word'].apply(self.wv)])
然后管道将工作。
对于下面的 pandas DataFrame df
,我想将 type
列转换为 OneHotEncoding,并使用字典将 word
列转换为其矢量表示word2vec
。然后我想将两个转换后的向量与 count
列连接起来,形成 classification 的最终特征。
>>> df
word type count
0 apple A 4
1 cat B 3
2 mountain C 1
>>> df.dtypes
word object
type category
count int64
>>> word2vec
{'apple': [0.1, -0.2, 0.3], 'cat': [0.2, 0.2, 0.3], 'mountain': [0.4, -0.2, 0.3]}
我定义了自定义的 Transformer
,并使用 FeatureUnion
连接特征。
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.pipeline import Pipeline, FeatureUnion
from sklearn.preprocessing import OneHotEncoder
class w2vTransformer(TransformerMixin):
def __init__(self,word2vec):
self.word2vec = word2vec
def fit(self,x, y=None):
return self
def wv(self, w):
return self.word2vec[w] if w in self.word2vec else [0, 0, 0]
def transform(self, X, y=None):
return df['word'].apply(self.wv)
pipeline = Pipeline([
('features', FeatureUnion(transformer_list=[
# Part 1: get integer column
('numericals', Pipeline([
('selector', TypeSelector(np.number)),
])),
# Part 2: get category column and its onehotencoding
('categoricals', Pipeline([
('selector', TypeSelector('category')),
('labeler', StringIndexer()),
('encoder', OneHotEncoder(handle_unknown='ignore')),
])),
# Part 3: transform word to its embedding
('word2vec', Pipeline([
('w2v', w2vTransformer(word2vec)),
]))
])),
])
当我运行pipeline.fit_transform(df)
时,我得到了错误:blocks[0,:] has incompatible row dimensions. Got blocks[0,2].shape[0] == 1, expected 3.
但是,如果我从管道中删除 word2vec 转换器(第 3 部分),则管道(第 1 部分 1 + 第 2 部分)工作正常。
>>> pipeline_no_word2vec.fit_transform(df).todense()
matrix([[4., 1., 0., 0.],
[3., 0., 1., 0.],
[1., 0., 0., 1.]])
如果我 只保留 管道中的 w2v 转换器,它也可以工作。
>>> pipeline_only_word2vec.fit_transform(df)
array([list([0.1, -0.2, 0.3]), list([0.2, 0.2, 0.3]),
list([0.4, -0.2, 0.3])], dtype=object)
我的猜测是我的 w2vTransformer
class 有问题,但不知道如何修复。请帮忙。
此错误是由于 FeatureUnion 需要其每个部分的二维数组。
现在您的 FeatureUnion 的前两部分:- 'numericals'
和 'categoricals'
正确发送形状为 (n_samples、n_features) 的二维数据。
n_samples
= 3 在您的示例数据中。 n_features
将取决于各个部分(例如 OneHotEncoder 将在第二部分更改它们,但在第一部分将更改为 1)。
但是第三部分 'word2vec'
returns 一个 pandas.Series 具有一维形状的对象 (3,)
。 FeatureUnion 默认采用形状 (1, 3),因此抱怨它与其他块不匹配。
所以你需要修正那个形状。
现在即使你简单地在最后做一个reshape()
并将它变成形状(3,1),你的代码也不会运行,因为那个数组的内部内容是列表来自您的 word2vec dict,它们未正确转换为二维数组。相反,它会变成一个列表数组。
更改w2vTransformer以更正错误:
class w2vTransformer(TransformerMixin):
...
...
def transform(self, X, y=None):
return np.array([np.array(vv) for vv in X['word'].apply(self.wv)])
然后管道将工作。