【问题标题】:NLP - speed up word similarity matchinNLP - 加快单词相似度匹配
【发布时间】:2017-05-13 00:29:56
【问题描述】:

我试图在 pandas 数据框中找到两个单词之间的最大相似度。这是我的日常

import pandas as pd
from nltk.corpus import wordnet
import itertools

df = pd.DataFrame({'word_1':['desk', 'lamp', 'read'], 'word_2':['call','game','cook']})

def max_similarity(row):
    word_1 = row['word_1']
    word_2 = row['word_2']

    ret_val = max([(wordnet.wup_similarity(syn_1, syn_2) or 0) for 
       syn_1, syn_2 in itertools.product(wordnet.synsets(word_1), wordnet.synsets(word_2))])

    return ret_val

df['result'] = df.apply(lambda x: max_similarity(x), axis= 1)

它工作正常,但速度太慢。我正在寻找一种方法来加快它。 wordnet 花费大部分时间有什么建议吗?赛通?我愿意使用其他软件包,例如spacy

【问题讨论】:

  • lolz...那段代码看起来很眼熟;P
  • @alvas,是的,我从 stackoverflow.com 的其他帖子中借用了 if ;-)。我猜是你的。

标签: python pandas nlp nltk


【解决方案1】:

既然你说你愿意使用spacy 作为 NLP 库,让我们考虑一个简单的基准。我们将使用棕色新闻语料库通过将其分成两半来创建一些随意的词对。

from nltk.corpus import brown

brown_corpus = list(brown.words(categories='news'))
brown_df = pd.DataFrame({
    'word_1':brown_corpus[:len(brown_corpus)//2],
    'word_2': brown_corpus[len(brown_corpus)//2:]
})

len(brown_df)
50277

可以使用Doc.similarity 方法计算两个标记/文档的余弦相似度。

import spacy
nlp = spacy.load('en')

def spacy_max_similarity(row):
    word_1 = nlp(row['word_1'])
    word_2 = nlp(row['word_2'])
    
    return word_1.similarity(word_2)

最后,将这两种方法应用于数据框:

nltk_similarity = %timeit -o brown_df.apply(nltk_max_similarity, axis=1)
1 loop, best of 3: 59 s per loop

spacy_similarity = %timeit -o brown_df.apply(spacy_max_similarity, axis=1)
1 loop, best of 3: 8.88 s per loop

请注意,在衡量相似度时,NLTK 和 spacy 使用不同的技术。 spacy 使用经过 word2vec 算法预训练的词向量。来自docs

使用词向量和语义相似度

[...]

默认的英语模型为一百万个词汇安装向量 条目,使用在 Common Crawl 上训练的 300 维向量 语料库使用GloVe 算法。 GloVe 常见的爬行向量有 成为实际 NLP 的事实标准。

【讨论】:

  • 有趣! spacy 中的单词相似度和nltk 中的 Synset 相似度理论上是非常不同的 =)
【解决方案2】:

加快速度的一种方法是存储词对相似度。然后在重复的情况下,避免在循环中运行搜索功能。

import pandas as pd
from nltk.corpus import wordnet
import itertools

df = pd.DataFrame({'word_1':['desk', 'lamp', 'read'], 'word_2':['call','game','cook']})

word_similarities = dict()
def max_similarity(row):
    word_1 = row['word_1']
    word_2 = row['word_2']

    key = tuple(sorted([word_1, word_2])) # symmetric measure :)

    if key not in word_similarities:
        word_similarities[key] = max([
            (wordnet.wup_similarity(syn_1, syn_2) or 0)
            for syn_1, syn_2 in itertools.product(wordnet.synsets(word_1), wordnet.synsets(word_2))
        ])

    return word_similarities[key]

df['result'] = df.apply(lambda x: max_similarity(x), axis= 1)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-27
    • 2011-02-28
    • 1970-01-01
    • 1970-01-01
    • 2012-12-02
    • 1970-01-01
    • 2017-06-07
    • 1970-01-01
    相关资源
    最近更新 更多