【问题标题】:W2VTransformer: Only works with one word as input?W2VTransformer:只使用一个单词作为输入?
【发布时间】:2019-05-28 15:14:42
【问题描述】:

以下可重现的脚本用于计算带有 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)

【问题讨论】:

  • 在哪里脚本返回ValueError? (如果您可以显示完整的错误堆栈,则更容易查看问题所在,因此您应该编辑问题以包含额外的详细信息。)
  • re: your update 是的,W2VTransformer 不会将可变长度的单词列表折叠成单个向量,因为这不是自动需要的功能包装的Word2Vec 模型。相反,它将可变长度的单词列表转换为相同长度的向量列表。如果您需要将它们折叠为单个向量以供后续步骤使用,您可以将其实现为以下转换器,也许是一个将所有向量平均在一起的转换器。 (这通常是一种简单的基线方法,但根据您的数据和目标,其他权重或算法可能效果更好。)

标签: scikit-learn gensim word2vec


【解决方案1】:

这在技术上不是一个答案,但不能用 cmets 写,所以在这里。这里有多个问题:

  • LogisticRegression 类(和大多数其他 scikit-learn 模型)使用二维数据 (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 (iterable of iterables of str) – 输入语料库。

      X 可以只是一个标记列表的列表,但对于更大的语料库,考虑一个可迭代的直接从 磁盘/网络。请参阅 word2vec 中的 BrownCorpus、Text8Corpus 或 LineSentence 此类示例的模块。

    • fit_transform():

      X (numpy array of shape [n_samples, n_features]) – 训练集。

如果你想使用 scikit-learn,那么你需要有二维形状。您将需要“以某种方式合并”单个句子的词向量以形成该句子的一维数组。这意味着您需要通过以下方式形成一种句子向量:

  • 单个单词的总和
  • 单个单词的平均值
  • 根据频率、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() 会自动执行此操作。

【讨论】:

  • 是的,显然 D2V 版本似乎可以工作。我还在上面添加了一个工作版本。感谢您的回答!
  • @Christopher 我已经用那个问题中的错误更新了答案。
  • 具体在哪里?它似乎工作。我想model.transform(X_train)解决了?
  • @Christopher 关于"ufunc 'add' did not contain a loop with ..." 的错误。当您结合两个活动代码(D2V Example - Without PipelineD2V Example - With Pipeline)时,就会发生这种情况。在这种情况下,传递给管道的X_train 已经是文档向量。如果您删除无管道示例及其代码,则 X_train 是一系列单词。
  • @Christopher 是的,它是正确的。我已经稍微更新了它以获得更好的代码。
猜你喜欢
  • 1970-01-01
  • 2021-10-30
  • 2021-06-18
  • 2018-01-13
  • 2015-08-15
  • 1970-01-01
  • 2014-04-04
  • 2021-01-13
  • 1970-01-01
相关资源
最近更新 更多