4

我有两个列表:一、用户的利益;第二,关于一本书的关键词。我想根据用户给定的兴趣列表向用户推荐这本书。我正在使用SequenceMatcherPython 库的类difflib来匹配类似的单词,如“game”、“games”、“gaming”、“gamer”等。该ratio函数给了我一个介于 [0,1] 之间的数字,说明 2 个字符串的相似程度. 但是我遇到了一个例子,我计算了“循环”和“射击”之间的相似性。结果是0.6667

for interest in self.interests:
    for keyword in keywords:
       s = SequenceMatcher(None,interest,keyword)
       match_freq = s.ratio()
       if match_freq >= self.limit:
            #print interest, keyword, match_freq
            final_score += 1
            break 

有没有其他方法可以在 Python 中执行这种匹配?

4

3 回答 3

10

首先,一个词可以有多种含义,当您尝试找到相似的词时,您可能需要一些词义消歧http://en.wikipedia.org/wiki/Word-sense_disambiguation

给定一对词,如果我们以最相似的一对词义作为衡量两个词是否相似的标准,我们可以试试这个:

from nltk.corpus import wordnet as wn
from itertools import product

wordx, wordy = "cat","dog"
sem1, sem2 = wn.synsets(wordx), wn.synsets(wordy)

maxscore = 0
for i,j in list(product(*[sem1,sem2])):
  score = i.wup_similarity(j) # Wu-Palmer Similarity
  maxscore = score if maxscore < score else maxscore

您还可以使用其他相似性函数。http://nltk.googlecode.com/svn/trunk/doc/howto/wordnet.html。唯一的问题是当您遇到不在 wordnet 中的单词时。那我建议你回退difflib

于 2013-09-18T12:52:01.447 回答
5

起初,我想用正则表达式来执行额外的测试来区分低比率的匹配。它可以是一种解决特定问题的解决方案,例如以ing结尾的单词发生的问题。但这只是一个有限的案例,可能还有许多其他案例需要为每个案例添加特定的治疗。

然后我认为我们可以尝试找到额外的标准来消除语义上不匹配的单词,这些单词的字母相似度足以被检测为匹配在一起,尽管该比率很低,
同时捕获具有低比率的真正语义匹配的术语,因为它们很短。

这里有一个可能

from difflib import SequenceMatcher

interests = ('shooting','gaming','looping')
keywords = ('loop','looping','game')

s = SequenceMatcher(None)

limit = 0.50

for interest in interests:
    s.set_seq2(interest)
    for keyword in keywords:
        s.set_seq1(keyword)
        b = s.ratio()>=limit and len(s.get_matching_blocks())==2
        print '%10s %-10s  %f  %s' % (interest, keyword,
                                      s.ratio(),
                                      '** MATCH **' if b else '')
    print

  shooting loop        0.333333  
  shooting looping     0.666667  
  shooting game        0.166667  

    gaming loop        0.000000  
    gaming looping     0.461538  
    gaming game        0.600000  ** MATCH **

   looping loop        0.727273  ** MATCH **
   looping looping     1.000000  ** MATCH **
   looping game        0.181818  

请注意文档中的这一点:

SequenceMatcher 计算并缓存有关第二个序列的详细信息,因此如果要将一个序列与多个序列进行比较,请使用 set_seq2() 设置常用序列一次,然后重复调用 set_seq1() ,对其他每个序列执行一次。

于 2013-09-18T13:07:25.417 回答
3

那是因为 SequenceMatcher 基于编辑距离或类似的东西。语义相似性更适合您的情况或两者的混合。

在您使用 python 时查看 NLTK 包(代码示例),也许还有这篇论文

使用 c++ 的人可以查看这个开源项目以供参考

于 2013-09-18T12:27:42.660 回答