1

所以我知道有几种方法可以在文档语料库中找到最相似或说三个最相似的文档。我知道可能存在扩展问题,目前我有大约一万个文档,并且已经在大约 30 个子集上运行测试。这是我现在所拥有的,但如果这被证明是不可能或效率低下,我正在考虑研究 elasticsearch 或 doc2vec。

到目前为止,这些脚本运行良好,它们使用 spaCy 对文本进行标记,并使用 Sklearn TfidfVectorizer 来适应所有文档,并且发现了非常相似的文档。我注意到从管道中出来的 NumPy 对象的形状是 (33, 104354),这可能意味着 104354 词汇不包括所有 33 个文档中的停用词。这一步需要运行 20 分钟,但下一步是计算所有余弦相似度的矩阵乘法非常快,但我知道它可能会减慢,因为该矩阵得到数千行而不是 30 行。

如果您可以有效地将新文档添加到矩阵中,那么如果您保存了该计算的结果,那么初始计算是否需要十个小时甚至几天都没有关系。

  1. 当我在 . 矢量化器上似乎有一种方法称为vectorizer.fixed_vocabulary_. 我在谷歌或 SKlearn 中找不到这种方法。无论如何,当我运行该方法时,它会返回False. 有谁知道这是什么?我认为如果可能的话修复词汇表可能很有用,否则将新文档添加到术语文档矩阵可能会很麻烦,尽管我不确定如何做到这一点。

有人在这里问了一个类似的问题,该问题得到了投票,但没有人回答。

他写了:

对于新文档,当我获得新文档 doc(k) 时我该怎么办?好吧,我必须计算这个文档与之前所有文档的相似度,这不需要构建整个矩阵。我可以对所有先前的 j 取 doc(k) dot doc(j) 的内积,得到 S(k, j),这很好。

  1. 有没有人完全理解他在这里的意思,或者有任何好的链接来解释这个相当晦涩的话题?他是对的吗?我不知何故认为,如果他是对的,那么用这个内积添加新文档的能力将取决于修复上面提到的词汇表。
4

3 回答 3

2

作为我对另一个答案的评论的续集:是的,缺少词汇会导致问题,至少对我来说是这样。问题是在计算 tf-idf 值(或其他值)时,不考虑不在词汇表中的单词。想象一下,当我们有一个句子“This is karamba”时。并且只有前两个词在词汇表中,然后他们得到更高的分数,因为“karamba”是一个未知词,根本没有得分。因此,“this”和“is”在句子中比“karamba”在词汇表中更重要(请记住,karamba 是我们在这个句子中真正想要查看的唯一词)。

好的,如果语料库中根本没有“karamba”,为什么会有问题呢?因为我们在“this”和“is”非常重要的基础上得到了很多误报,即使它们有点meh
我是怎么解决的?不方便,但可行。

首先,我按照另一个答案中的建议创建我的语料库词汇。

import copy
from sklearn.feature_extraction.text import TfidfVectorizer
from collections import defaultdict

corpus = []

# Populate the corpus with some data that I have
for d in sorted(os.listdir('d'), key=lambda x: int(x.split('.')[0])):
    with open(os.path.join('d', d)) as f:
        corpus.append(f.read())

corpus_tfidf_vectorizer = TfidfVectorizer()
corpus_tfidf_matrix = corpus_tfidf_vectorizer.fit_transform(corpus)

corpus_vocabulary = defaultdict(None, copy.deepcopy(corpus_tfidf_vectorizer.vocabulary_))
corpus_vocabulary.default_factory = corpus_vocabulary.__len__

为什么defaultdict?这是我从里面的词汇创建实现中偷来的一个巧妙的技巧TfidfVectorizer。如果您想查看它,请检查sklearn.feature_extraction.text.CountVectorizer._count_vocab. 从本质上讲,它只是一种将单词添加到词汇表中的方法,而无需过多担心正确的索引。

Anywhoo,现在我们开始处理要添加到语料库中的查询。

 # Let's say I got a query value from somewhere
 query = f.read()

 query_vocabulary_vectorizer = TfidfVectorizer()
 query_vocabulary_vectorizer.fit_transform([query])
 for word in query_vocabulary_vectorizer.vocabulary_.keys():
     # Added with proper index if not in vocabulary
     corpus_vocabulary[word]

 # Nice, everything in the vocabulary now!

 query_tfidf_matrix = TfidfVectorizer(vocabulary=corpus_vocabulary).fit_transform([query])

2020 年的注意事项:如果您与 2018 年相比处于相对的未来并且您拥有更新版本的 scipy,则可能不需要此部分。

哦,好吧,现在我们必须合并语料库矩阵。这是有问题的,因为矩阵的大小不再相同。我们必须调整语料库矩阵的大小,因为现在我们(可能)里面有更多的词,如果不使它们大小相同,我们就无法合​​并它们。有趣和可悲的是,它scipy.sparse支持调整矩阵大小,但scipy. 因此,我 从任意提交安装了master分支: . PS!您需要安装以在您自己的机器中构建(只需)。 scipypip install git+git://github.com/scipy/scipy.git@b8bf38c555223cca0bcc1e0407587c74ff4b3f2e#egg=scipycythonscipypip install cython

——2018年的我

所以这很麻烦,但现在我们可以愉快地声明:

from scipy import sparse as sp

corpus_tfidf_matrix.resize((corpus_tfidf_matrix.shape[0], query_tfidf_matrix.shape[1]))
# And voilà, we can merge now!
tfidf_matrix = sp.vstack([corpus_tfidf_matrix, query_tfidf_matrix])

巴姆,完成。另一个答案仍然是正确的,我只是在详细说明该解决方案。

于 2018-04-08T22:36:44.253 回答
1

好的,我解决了它,花了好几个小时,围绕这个主题的另一篇文章让我对它描述线性代数的方式感到困惑,并且没有提到它的一个方面,这对于编写它的人来说可能是显而易见的。

所以感谢有关词汇的信息..

所以矢量化器是sklearn.feature_extraction.text.vectorizer. 我用这个vocabulary_方法把现有33篇文本的词汇拉出来了:

v = vectorizer.vocabulary_
print (type(v))
>> dict
print (len(v))
>> 104354

腌制这本字典以备将来使用,只是为了测试它是否有效,fit_transform在包含 TfidfVectorizer 的管道对象上重新运行vocabulary=v它的参数。

原始的成对相似度矩阵是通过 pairwise_similarity = (p * p.T).A其中 p 是一个拟合的管道对象,也是术语文档矩阵找到的。

添加了一个小的新文档:

new_document= """

Remove the lamb from the fridge 1 hour before you want to cook it, to let it come up to room temperature. Preheat the oven to 200ºC/400ºC/gas 6 and place a roasting dish for the potatoes on the bottom. Break the garlic bulb up into cloves, then peel 3, leaving the rest whole.
"""

使用现在固定的词汇表将管道安装到一个文档中:

p_new = pipe.fit_transform([new_document]) 
print (p_new.shape)
> (1, 104354)

然后像这样把它们放在一起:

from scipy.sparse import vstack as vstack_sparse_matrices
p_combined = vstack_sparse_matrices([p, p_new])
print (p_combined.shape)
>> (34, 104354)

并重新运行成对相似度方程:

pairwise_similarity = (p_combined * p_combined.T).A

对代码或理论并不完全有信心,但我相信这是正确的并且有效 - 布丁的证据在于吃东西,我后来的代码发现最相似的文件也与烹饪相关。将原始文档更改为其他几个主题并重新运行,它们的相似之处完全符合您的预期。

于 2017-06-12T15:33:30.953 回答
0

我们将适合,然后将新消息添加到经过训练的模型中

tf_one = TfidfVectorizer(analyzer='word', stop_words = "english", lowercase = True)
X_train_one = tf_one.fit_transform(X_train)
nb_one = MultinomialNB()
nb_one.fit(X_train_one , Y_train)

# When you receive a new document
X = tf_one.transform([mymessage_X])
prediction = nb_one.predict(X)
print(prediction)


 # New document 
mymessage_X ="This message will be added to the existing model"
label_Y=" your label"



 tf_two = TfidfVectorizer(analyzer='word', stop_words = "english", lowercase = True ,vocabulary = tf_one.vocabulary_)

X_train_two = tf_two.fit_transform([mymessage_X])
nb = MultinomialNB()
nb.fit(X_train_two, [label_Y])

#print the length of the tf_two vocabulary
len(tf_two.vocabulary_)    

from scipy.sparse import vstack as vstack_sparse_matrices
p_combined = vstack_sparse_matrices([X_train_one, X_train_two])
print (p_combined.shape) 

pairwise_similarity = (p_combined * p_combined.T).A
pairwise_similarity
于 2019-07-23T16:01:47.707 回答