以下可重复使用的脚本用于通过gensim中的W2VTransformer
包装器来计算Word2Vec分类器的准确性:
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
),脚本将返回:
ValueError:无法将大小为10的数组重塑为形状(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)
答案 0 :(得分:1)
从技术上讲,这不是一个答案,但是不能在注释中写出来,所以在这里。这里有多个问题:
LogisticRegression
类(和大多数其他scikit学习模型)可用于二维数据(n_samples, n_features)
。
这意味着它需要一个一维数组的集合(每一行(样本)一个,数组中的元素包含特征值)。
在您的数据中,单个单词将是一维数组,这意味着单个句子(样本)将是二维数组。这意味着完整的数据(此处是句子的集合)将是二维数组的集合。即使这样,由于每个句子可以具有不同数量的单词,因此无法将其组合为单个3-d数组。
其次,gensim中的W2VTransformer
看起来像是scikit-learn兼容的类,但不是。它尝试遵循“ scikit-learn API约定”来定义方法fit()
,fit_transform()
和transform()
。它们与scikit-learn Pipeline
不兼容。
您可以看到fit()
和fit_transform()
的输入参数要求是不同的。
X(str的可迭代量) –输入语料库。
X可以只是令牌列表的列表,但是对于较大的语料库,请考虑将其直接从句子流式传输的可迭代对象 磁盘/网络。请参阅word2vec中的BrownCorpus,Text8Corpus或LineSentence 此类示例的模块。
X(形状[n_samples,n_features]的数字数组) –训练集。
如果要使用scikit-learn,则需要具有2维形状。您将需要“以某种方式合并”单个句子的单词向量,以形成该句子的一维数组。这意味着您需要通过执行以下操作来形成一种句子向量:
注意:-我现在注意到了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()
会自动进行拟合和变换,因此无需分别拟合和变形。