W2VTransformer:只能使用一个单词作为输入吗?

时间:2019-01-01 19:47:37

标签: scikit-learn gensim word2vec

以下可重复使用的脚本用于通过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)

1 个答案:

答案 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()的输入参数要求是不同的。

    • fit()

        

      X(str的可迭代量) –输入语料库。

           

      X可以只是令牌列表的列表,但是对于较大的语料库,请考虑将其直接从句子流式传输的可迭代对象   磁盘/网络。请参阅word2vec中的BrownCorpus,Text8Corpus或LineSentence   此类示例的模块。

    • fit_transform()

        

      X(形状[n_samples,n_features]的数字数组) –训练集。

如果要使用scikit-learn,则需要具有2维形状。您将需要“以某种方式合并”单个句子的单词向量,以形成该句子的一维数组。这意味着您需要通过执行以下操作来形成一种句子向量:

  • 单个单词的总和
  • 单个单词的平均值
  • 基于频率,tf-idf等对单个单词进行加权平均。
  • 使用send2vec,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()会自动进行拟合和变换,因此无需分别拟合和变形。