非正规词距离

2024-05-15 07:59:53 发布

您现在位置:Python中文网/ 问答频道 /正文

我尝试使用快速单词移动器的距离库和SpaCy,例如GitHub中的相同示例

import spacy
import wmd
nlp = spacy.load('en_core_web_md')
nlp.add_pipe(wmd.WMD.SpacySimilarityHook(nlp), last=True)

doc1 = nlp("Politician speaks to the media in Illinois.")
doc2 = nlp("The president greets the press in Chicago.")
print(doc1.similarity(doc2))

结果是:

^{pr2}$

我不知道如何解释它,因为通常距离是标准化的(0到1)。在自述文件中,此结果不可用,因此我不确定我的结果是否错误,或者此测量的刻度是否不同。在


Tags: theinimportgithub距离示例nlpspacy
1条回答
网友
1楼 · 发布于 2024-05-15 07:59:53

简短的回答:不要解释它。就这样用:距离越小,句子就越相似。对于几乎所有的实际应用(例如KNN),这已经足够了。在

现在长话短说:单词移动距离(readthe paper)被定义为“不停”单词的最佳匹配对之间距离的加权平均值。所以如果你想把它规范化为(0,1),你需要把这个最佳和除以它的最坏情况。在

问题是spacy中的单词向量没有被规范化(通过打印[sum(t.vector**2) for t in doc1]来检查)。因此,它们之间的最大距离是无限的。如果你真的将它们规范化,新的大规模杀伤性武器将不会等同于原始的大规模杀伤性武器(也就是说,它将对文本进行不同的排序)。因此,没有明显的方法来规范化你所演示的原始空间大规模杀伤性武器的距离。在

现在假设单词向量是单位规范化的。如果是这样的话,那么两个词之间的最大距离就是单位球的直径(即2)。许多2的最大加权平均数仍然是2。所以你需要把文本之间的距离除以2,使之完全标准化。在

通过继承所使用的类,可以将字向量规范化构建到WMD计算中:

import wmd
import numpy
import libwmdrelax

class NormalizedWMDHook(wmd.WMD.SpacySimilarityHook):
    def compute_similarity(self, doc1, doc2):
        """
        Calculates the similarity between two spaCy documents. Extracts the
        nBOW from them and evaluates the WMD.

        :return: The calculated similarity.
        :rtype: float.
        """
        doc1 = self._convert_document(doc1)
        doc2 = self._convert_document(doc2)
        vocabulary = {
            w: i for i, w in enumerate(sorted(set(doc1).union(doc2)))}
        w1 = self._generate_weights(doc1, vocabulary)
        w2 = self._generate_weights(doc2, vocabulary)
        evec = numpy.zeros((len(vocabulary), self.nlp.vocab.vectors_length),
                           dtype=numpy.float32)
        for w, i in vocabulary.items():
            v = self.nlp.vocab[w].vector                                      # MODIFIED
            evec[i] = v / (sum(v**2)**0.5)                                    # MODIFIED
        evec_sqr = (evec * evec).sum(axis=1)
        dists = evec_sqr - 2 * evec.dot(evec.T) + evec_sqr[:, numpy.newaxis]
        dists[dists < 0] = 0
        dists = numpy.sqrt(dists)
        return libwmdrelax.emd(w1, w2, dists) / 2                             # MODIFIED

现在,您可以确保您的距离已正确规格化:

^{pr2}$

现在的结果是

^{3}$

另外,你可以看到,即使在两个非常不相关的文本之间,这个标准化的距离也远远小于1。这是因为在现实中,单词向量并没有覆盖整个单位球体——相反,它们大多聚集在其上的几个“大陆”。因此,即使是非常不同的文本之间的距离也通常小于1。在

相关问题 更多 >