我正试图使用gensim的word2vec将Panda数据帧的一列转换为一个向量,我可以将该向量传递给sklearn
分类器进行预测。
我知道我需要对每一行的向量求平均值。我试着遵循这个指南,但我被卡住了,因为我正在取回模型,但我认为我无法访问底层嵌入来找到平均值。
请参阅下面的一个可重复的最小示例:
import pandas as pd, numpy as np
from gensim.models import Word2Vec
from gensim.models.doc2vec import Doc2Vec, TaggedDocument
from sklearn.feature_extraction.text import CountVectorizer
temp_df = pd.DataFrame.from_dict({'ID': [1,2,3,4,5], 'ContData': [np.random.randint(1, 10 + 1)]*5,
'Text': ['Lorem ipsum dolor sit amet', 'consectetur adipiscing elit.', 'Sed elementum ultricies varius.',
'Nunc vel risus sed ligula ultrices maximus id qui', 'Pellentesque pellentesque sodales purus,'],
'Class': [1,0,1,0,1]})
temp_df['text_lists'] = [x.split(' ') for x in temp_df['Text']]
w2v_model = Word2Vec(temp_df['text_lists'].values, min_count=1)
cv = CountVectorizer()
count_model = pd.DataFrame(data=cv.fit_transform(temp_df['Text']).todense(), columns=list(cv.get_feature_names_out()))
使用sklearn's CountVectorizer
,我能够得到一个简单的频率表示,我可以将其传递给分类器。如何使用Word2vec获得相同的格式?
这个玩具示例产生:
adipiscing amet consectetur dolor elementum elit id ipsum ligula lorem ... purus qui risus sed sit sodales ultrices ultricies varius vel
0 0 1 0 1 0 0 0 1 0 1 ... 0 0 0 0 1 0 0 0 0 0
1 1 0 1 0 0 1 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 0
2 0 0 0 0 1 0 0 0 0 0 ... 0 0 0 1 0 0 0 1 1 0
3 0 0 0 0 0 0 1 0 1 0 ... 0 1 1 1 0 0 1 0 0 1
4 0 0 0 0 0 0 0 0 0 0 ... 1 0 0 0 0 1 0 0 0 0
虽然这运行时没有错误,但我无法访问可以用当前格式传递的嵌入。我想产生相同的格式,除了有计数,它的word2vec
值嵌入
如果您的原始数据来自PandasDataFrame
,您可能无法提供帮助,但Gensim和Scikit Learn都无法原生地使用DataFrame
风格的数据。相反,他们倾向于使用原始的numpy
数组,或基本的Python数据结构,如list
或可迭代序列。
试图将临时原始向量硬塞进Pandas风格的数据结构中往往会增加代码复杂性&浪费的开销。
如果向量是密集向量,那么情况尤其如此,其中基本上所有较小数量的维度都是非零的,就像word2vec类算法一样。但如果向量是稀疏向量的类型,具有大量的维度,但大多数维度为0,则也是如此,这些向量来自CountVectorizer
和各种"0";单词袋-样式文本模型。
因此,首先,我建议不要将Word2Vec
或CountVectorizer
的原始输出放入DataFrame
,它们通常是在完成其他任务的过程中的临时表示。
如果您希望在DataFrame
中有最终分配的标签,以便以Pandas样式进行分析或报告,那么最后只添加这些最终输出。但是,要理解临时向量表示,然后以类期望的格式将它们传递给Scikit-Learn分类器,请将这些向量保持在原始numpy
向量格式中(并亲自检查以确保清晰)。
特别是,在Word2Vec
运行后(使用您显示的参数),每个单词将有一个100维向量。不是每个多字文本。100个维度除了索引0到99之外没有其他名称。
并且不同于CountVectorizer
表示的维度(其是单个单词的计数);密集嵌入";将是一些浮点十进制值,它本身没有明确或具体的解释:它只是整个空间中的方向/邻域,在许多维度上剪切,模糊地与有用或可命名的概念相对应。
如果您想将每个单词的100维向量转换为多单词文本的向量,有很多潜在的方法可以做到这一点,但一个简单的选择是将N个单词向量平均为1个摘要向量。Gensim在Word2Vec
模型中保存单词向量的类KeyedVectors
有一个.get_mean_vector()
方法可以提供帮助。例如:
texts_as_wordlists = [x.split(' ') for x in temp_df['Text']]
text_vectors = [w2v_model.wv.get_mean_vector(wordlist) for wordlist in texts_as_wordlists]
还有许多其他潜在的方法可以使用单词向量来对较长的文本进行建模。例如,你可以在断言之前重新拼写单词。但一个简单的平均值是一个合理的第一基线方法。(其他与word2vec相关的算法,如Doc2Vec
类实现的"段落向量"算法,也可以为多单词文本创建向量,并且这样的向量是而不是,只是其单词向量的平均值。)
关于使用Word2Vec
:的另外两个注意事项
- word2vec向量只有在对大量单词使用数据进行训练时才会变得良好。仅在数百甚至数万个单词上训练的玩具大小的例子很少显示出任何有用的东西,也很少显示出这种算法在更大的数据集上的威力
- CCD_ 21对于该算法本质上总是一个坏主意。与上述观点相关,该算法需要任何单词的多个微妙对比的用法示例,才能有机会将其有意义地放置在共享坐标空间中。只有一个,甚至几个用法的单词往往会得到可怕的向量,无法概括为单词的真实含义,这从更大的用法样本中可以明显看出。而且,在自然语言语料库中,这样少数的示例单词数量非常多,因此它们最终占用了大量的训练时间,而实现其糟糕的表示实际上会恶化周围单词的向量,这可能会更好,因为有足够的训练示例。因此,word2vec的最佳实践通常是忽略最稀有的单词——训练时就好像它们根本不存在一样。(该类的默认值为
min_count=5
是有充分理由的,如果这导致您的模型缺少您认为需要的单词的向量,请获取更多显示这些单词在实际上下文中使用情况的数据,而不是降低min_count
。)