我使用scikit-learn监督学习方法进行文本分类。我有一个训练数据集,输入文本字段和它们所属的类别。我使用tf-idf, SVM分类器管道来创建模型。该解决方案在正常的测试用例中运行良好。但是,如果输入的新文本与训练集中的同义词相同,则解决方案无法正确分类。例如:单词"run"可能存在于训练数据中,但如果我使用单词"sprint"进行测试,则解决方案无法正确分类。
这里最好的方法是什么?在我看来,为训练数据集中的所有单词添加所有同义词并不是一种可扩展的方法
您应该研究单词向量和密集文档嵌入。现在,您正在传递scikit-learn矩阵X
,其中每一行都是数据集中文档的数字表示。您使用tf-idf得到了这个表示,但是正如您注意到的,这并没有捕获单词的相似性,并且您还遇到了词汇表外的单词的问题。
一个可能的改进是用一个密度为300维的向量来表示每个单词,这样具有相似含义的单词在这个300维空间中是接近的。幸运的是,您不需要从头构建这些向量(查找gensim word2vec和space)。另一个好处是,通过在像维基百科这样的大型语料库上使用预训练的词嵌入,你可以将大量关于世界的语言信息整合到你的算法中,否则你无法从语料库中推断出这些信息(比如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)