W2VTransformer:仅适用于一个词作为输入?
W2VTransformer: Only works with one word as input?
以下可重现脚本用于计算 Word2Vec 分类器在 gensim 中使用 W2VTransformer
包装器的准确性:
import numpy as np
import pandas as pd
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipeline
from gensim.sklearn_api import W2VTransformer
from gensim.utils import simple_preprocess
# Load synthetic data
data = pd.read_csv('https://pastebin.com/raw/EPCmabvN')
data = data.head(10)
# Set random seed
np.random.seed(0)
# Tokenize text
X_train = data.apply(lambda r: simple_preprocess(r['text'], min_len=2), axis=1)
# Get labels
y_train = data.label
train_input = [x[0] for x in X_train]
# Train W2V Model
model = W2VTransformer(size=10, min_count=1)
model.fit(X_train)
clf = LogisticRegression(penalty='l2', C=0.1)
clf.fit(model.transform(train_input), y_train)
text_w2v = Pipeline(
[('features', model),
('classifier', clf)])
score = text_w2v.score(train_input, y_train)
score
0.80000000000000004
此脚本的问题在于它 仅 在 train_input = [x[0] for x in X_train]
时有效,这基本上始终只有第一个单词。
一旦更改为 train_input = X_train
(或 train_input
简单地替换为 X_train
),脚本 returns:
ValueError: cannot reshape array of size 10 into shape (10,10)
我该如何解决这个问题,即分类器如何处理多个输入词?
编辑:
显然,与 D2V 相比,W2V 包装器无法处理可变长度的火车输入。这是一个有效的 D2V 版本:
import numpy as np
import pandas as pd
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score
from sklearn.metrics import accuracy_score, classification_report
from sklearn.pipeline import Pipeline
from gensim.utils import simple_preprocess, lemmatize
from gensim.sklearn_api import D2VTransformer
data = pd.read_csv('https://pastebin.com/raw/bSGWiBfs')
np.random.seed(0)
X_train = data.apply(lambda r: simple_preprocess(r['text'], min_len=2), axis=1)
y_train = data.label
model = D2VTransformer(dm=1, size=50, min_count=2, iter=10, seed=0)
model.fit(X_train)
clf = LogisticRegression(penalty='l2', C=0.1, random_state=0)
clf.fit(model.transform(X_train), y_train)
pipeline = Pipeline([
('vec', model),
('clf', clf)
])
y_pred = pipeline.predict(X_train)
score = accuracy_score(y_train,y_pred)
print(score)
这在技术上不是答案,但不能写在评论中,所以在这里。这里有多个问题:
LogisticRegression
class(以及大多数其他 scikit-learn 模型)使用二维数据 (n_samples, n_features)
。
这意味着它需要一组一维数组(每行一个(样本),其中数组的元素包含特征值)。
在您的数据中,单个单词将是一个一维数组,这意味着单个句子(样本)将是一个二维数组。这意味着完整的数据(这里是句子的集合)将是二维数组的集合。即使这样,由于每个句子可以有不同数量的单词,它也不能组合成一个 3-d 数组。
其次,gensim 中的 W2VTransformer
看起来像一个 scikit-learn 兼容的 class,但它不是。它试图遵循 "scikit-learn API conventions" 来定义方法 fit()
、fit_transform()
和 transform()
。它们与 scikit-learn 不兼容 Pipeline
。
可以看到fit()
和fit_transform()
的输入参数要求是不一样的。
-
X (iterable of iterables of str) – The input corpus.
X can be simply a list of lists of tokens, but for larger corpora, consider an iterable that streams the sentences directly from
disk/network. See BrownCorpus, Text8Corpus or LineSentence in word2vec
module for such examples.
-
X (numpy array of shape [n_samples, n_features]) – Training set.
如果你想使用 scikit-learn,那么你需要有二维形状。您将需要 "somehow merge" 单个句子的词向量来为该句子形成一维数组。这意味着您需要通过执行以下操作来形成一种句子向量:
- 单个词的总和
- 单个单词的平均值
- 基于频率、tf-idf 等对单个词进行加权平均
- 使用其他技术,如 sent2vec、paragraph2vec、doc2vec 等
注意:- 我现在注意到 you were doing this thing based on D2VTransformer
。如果你想使用 sklearn,这应该是正确的方法。
该问题中的问题是这一行(因为该问题现已删除):
X_train = vectorizer.fit_transform(X_train)
在这里,你用已经计算出的词向量覆盖了原来的X_train
(词列表),因此出现了错误。
否则,您可以使用其他允许顺序输入可变大小的工具/库(keras、tensorflow)。例如,可以在此处配置 LSTM 以采用变量输入和结束标记来标记句子的结尾(示例)。
更新:
在上面给出的解决方案中,您可以替换以下行:
model = D2VTransformer(dm=1, size=50, min_count=2, iter=10, seed=0)
model.fit(X_train)
clf = LogisticRegression(penalty='l2', C=0.1, random_state=0)
clf.fit(model.transform(X_train), y_train)
pipeline = Pipeline([
('vec', model),
('clf', clf)
])
y_pred = pipeline.predict(X_train)
和
pipeline = Pipeline([
('vec', model),
('clf', clf)
])
pipeline.fit(X_train, y_train)
y_pred = pipeline.predict(X_train)
无需分别适应和变换,因为 pipeline.fit()
会自动完成。
以下可重现脚本用于计算 Word2Vec 分类器在 gensim 中使用 W2VTransformer
包装器的准确性:
import numpy as np
import pandas as pd
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipeline
from gensim.sklearn_api import W2VTransformer
from gensim.utils import simple_preprocess
# Load synthetic data
data = pd.read_csv('https://pastebin.com/raw/EPCmabvN')
data = data.head(10)
# Set random seed
np.random.seed(0)
# Tokenize text
X_train = data.apply(lambda r: simple_preprocess(r['text'], min_len=2), axis=1)
# Get labels
y_train = data.label
train_input = [x[0] for x in X_train]
# Train W2V Model
model = W2VTransformer(size=10, min_count=1)
model.fit(X_train)
clf = LogisticRegression(penalty='l2', C=0.1)
clf.fit(model.transform(train_input), y_train)
text_w2v = Pipeline(
[('features', model),
('classifier', clf)])
score = text_w2v.score(train_input, y_train)
score
0.80000000000000004
此脚本的问题在于它 仅 在 train_input = [x[0] for x in X_train]
时有效,这基本上始终只有第一个单词。
一旦更改为 train_input = X_train
(或 train_input
简单地替换为 X_train
),脚本 returns:
ValueError: cannot reshape array of size 10 into shape (10,10)
我该如何解决这个问题,即分类器如何处理多个输入词?
编辑:
显然,与 D2V 相比,W2V 包装器无法处理可变长度的火车输入。这是一个有效的 D2V 版本:
import numpy as np
import pandas as pd
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score
from sklearn.metrics import accuracy_score, classification_report
from sklearn.pipeline import Pipeline
from gensim.utils import simple_preprocess, lemmatize
from gensim.sklearn_api import D2VTransformer
data = pd.read_csv('https://pastebin.com/raw/bSGWiBfs')
np.random.seed(0)
X_train = data.apply(lambda r: simple_preprocess(r['text'], min_len=2), axis=1)
y_train = data.label
model = D2VTransformer(dm=1, size=50, min_count=2, iter=10, seed=0)
model.fit(X_train)
clf = LogisticRegression(penalty='l2', C=0.1, random_state=0)
clf.fit(model.transform(X_train), y_train)
pipeline = Pipeline([
('vec', model),
('clf', clf)
])
y_pred = pipeline.predict(X_train)
score = accuracy_score(y_train,y_pred)
print(score)
这在技术上不是答案,但不能写在评论中,所以在这里。这里有多个问题:
LogisticRegression
class(以及大多数其他 scikit-learn 模型)使用二维数据(n_samples, n_features)
。这意味着它需要一组一维数组(每行一个(样本),其中数组的元素包含特征值)。
在您的数据中,单个单词将是一个一维数组,这意味着单个句子(样本)将是一个二维数组。这意味着完整的数据(这里是句子的集合)将是二维数组的集合。即使这样,由于每个句子可以有不同数量的单词,它也不能组合成一个 3-d 数组。
其次,gensim 中的
W2VTransformer
看起来像一个 scikit-learn 兼容的 class,但它不是。它试图遵循 "scikit-learn API conventions" 来定义方法fit()
、fit_transform()
和transform()
。它们与 scikit-learn 不兼容Pipeline
。可以看到
fit()
和fit_transform()
的输入参数要求是不一样的。-
X (iterable of iterables of str) – The input corpus.
X can be simply a list of lists of tokens, but for larger corpora, consider an iterable that streams the sentences directly from disk/network. See BrownCorpus, Text8Corpus or LineSentence in word2vec module for such examples.
-
X (numpy array of shape [n_samples, n_features]) – Training set.
-
如果你想使用 scikit-learn,那么你需要有二维形状。您将需要 "somehow merge" 单个句子的词向量来为该句子形成一维数组。这意味着您需要通过执行以下操作来形成一种句子向量:
- 单个词的总和
- 单个单词的平均值
- 基于频率、tf-idf 等对单个词进行加权平均
- 使用其他技术,如 sent2vec、paragraph2vec、doc2vec 等
注意:- 我现在注意到 you were doing this thing based on D2VTransformer
。如果你想使用 sklearn,这应该是正确的方法。
该问题中的问题是这一行(因为该问题现已删除):
X_train = vectorizer.fit_transform(X_train)
在这里,你用已经计算出的词向量覆盖了原来的X_train
(词列表),因此出现了错误。
否则,您可以使用其他允许顺序输入可变大小的工具/库(keras、tensorflow)。例如,可以在此处配置 LSTM 以采用变量输入和结束标记来标记句子的结尾(示例)。
更新:
在上面给出的解决方案中,您可以替换以下行:
model = D2VTransformer(dm=1, size=50, min_count=2, iter=10, seed=0)
model.fit(X_train)
clf = LogisticRegression(penalty='l2', C=0.1, random_state=0)
clf.fit(model.transform(X_train), y_train)
pipeline = Pipeline([
('vec', model),
('clf', clf)
])
y_pred = pipeline.predict(X_train)
和
pipeline = Pipeline([
('vec', model),
('clf', clf)
])
pipeline.fit(X_train, y_train)
y_pred = pipeline.predict(X_train)
无需分别适应和变换,因为 pipeline.fit()
会自动完成。