您应该研究词向量和密集文档嵌入。现在,您正在向 scikit-learn 传递一个矩阵 X,其中每一行都是数据集中文档的数字表示。您正在使用 tf-idf 获得这种表示,但正如您所注意到的,这并没有捕捉到单词的相似性,而且您还遇到了词汇量不足的问题。
一个可能的改进是用一个维数为 300 的密集向量来表示每个单词,这样具有相似含义的单词在这个 300 维空间中是接近的。幸运的是,您不需要从头开始构建这些向量(查找 gensim word2vec 和 spacy)。另一个好处是,通过使用在 Wikipedia 等非常大的语料库上预训练的词嵌入,您可以将很多关于世界的语言信息整合到您的算法中,否则您无法从语料库中推断出这些信息(例如 sprint 和 run是同义词)。
一旦您获得了单词的良好语义数字表示,您就需要为每个文档获得一个向量表示。最简单的方法是平均句子中每个单词的词向量。
帮助您入门的示例伪代码:
>>> import spacy
>>> nlp = spacy.load('en')
>>> doc1 = nlp('I had a good run')
>>> doc1.vector
array([ 6.17495403e-02, 2.07064897e-02, -1.56451517e-03,
1.02607915e-02, -1.30429687e-02, 1.60102192e-02, ...
现在让我们尝试不同的文档:
>>> doc2 = nlp('I had a great sprint')
>>> doc2.vector
array([ 0.02453461, -0.00261007, 0.01455955, -0.01595449, -0.01795897,
-0.02184369, -0.01654281, 0.01735667, 0.00054854, ...
>>> doc2.similarity(doc1)
0.8820845113100807
请注意向量是如何相似的(在余弦相似度的意义上),即使单词不同。因为向量相似,scikit-learn 分类器将学习将它们分配到同一类别。对于 tf-idf 表示,情况并非如此。
这是在 scikit-learn 中使用这些向量的方法:
X = [nlp(text).vector for text in corpus]
clf.fit(X, y)