这是一个有趣的问题。
TL;DR:
对不起,这个问题没有简短的答案 =(
太长了,想看:
查看wup_similarity() 的代码,问题不在于相似度计算,而在于NLTK 遍历WordNet 层次结构以获取lowest_common_hypernym() 的方式(参见https://github.com/nltk/nltk/blob/develop/nltk/corpus/reader/wordnet.py#L805)。
通常,同义词集与其自身之间的最低共同上位词必须是自身:
>>> from nltk.corpus import wordnet as wn
>>> y = wn.synsets('car')[0]
>>> y.lowest_common_hypernyms(y, use_min_depth=True)
[Synset('car.n.01')]
但在orange 的情况下,它也给出fruit:
>>> from nltk.corpus import wordnet as wn
>>> x = wn.synsets('orange')[0]
>>> x.lowest_common_hypernyms(x, use_min_depth=True)
[Synset('fruit.n.01'), Synset('orange.n.01')]
我们必须从https://github.com/nltk/nltk/blob/develop/nltk/corpus/reader/wordnet.py#L805 的文档字符串中查看lowest_common_hypernym() 的代码
获取两个同义词集作为上位词的最低同义词集列表。
当use_min_depth == False 这意味着同义词集显示为
返回具有最小最大深度的 self 和 other 的上位词
或者如果在同一深度有多个这样的同义词集,它们都会被返回
但是,如果 use_min_depth == True 则具有/具有最低的同义词集
返回两个路径中的最小深度和出现
所以让我们试试lowest_common_hypernym() 和use_min_depth=False:
>>> x.lowest_common_hypernyms(x, use_min_depth=False)
[Synset('orange.n.01')]
似乎这样解决了绑定路径的歧义。但是wup_similarity() API 没有use_min_depth 参数:
>>> x.wup_similarity(x, use_min_depth=False)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: wup_similarity() got an unexpected keyword argument 'use_min_depth'
注意区别在于use_min_depth==False 时,lowest_common_hypernym 在遍历同义词集时检查最大深度。但是当use_min_depth==True 时,它会检查最小深度,请参阅https://github.com/nltk/nltk/blob/develop/nltk/corpus/reader/wordnet.py#L602
因此,如果我们追踪最低通用的超词代码:
>>> synsets_to_search = x.common_hypernyms(x)
>>> synsets_to_search
[Synset('citrus.n.01'), Synset('natural_object.n.01'), Synset('orange.n.01'), Synset('object.n.01'), Synset('plant_organ.n.01'), Synset('edible_fruit.n.01'), Synset('produce.n.01'), Synset('food.n.02'), Synset('physical_entity.n.01'), Synset('entity.n.01'), Synset('reproductive_structure.n.01'), Synset('solid.n.01'), Synset('matter.n.03'), Synset('plant_part.n.01'), Synset('fruit.n.01'), Synset('whole.n.02')]
# if use_min_depth==True
>>> max_depth = max(x.min_depth() for x in synsets_to_search)
>>> max_depth
8
>>> unsorted_lowest_common_hypernym = [s for s in synsets_to_search if s.min_depth() == max_depth]
>>> unsorted_lowest_common_hypernym
[Synset('orange.n.01'), Synset('fruit.n.01')]
>>>
# if use_min_depth==False
>>> max_depth = max(x.max_depth() for x in synsets_to_search)
>>> max_depth
11
>>> unsorted_lowest_common_hypernym = [s for s in synsets_to_search if s.max_depth() == max_depth]
>>> unsorted_lowest_common_hypernym
[Synset('orange.n.01')]
这种带有wup_similarity的奇怪现象实际上在代码cmets中突出显示,https://github.com/nltk/nltk/blob/develop/nltk/corpus/reader/wordnet.py#L843
# Note that to preserve behavior from NLTK2 we set use_min_depth=True
# It is possible that more accurate results could be obtained by
# removing this setting and it should be tested later on
subsumers = self.lowest_common_hypernyms(other, simulate_root=simulate_root and need_root, use_min_depth=True)
当列表中的第一个 subsumer 在https://github.com/nltk/nltk/blob/develop/nltk/corpus/reader/wordnet.py#L843被选中时:
subsumer = subsumers[0]
当然,在橙色同义词的情况下,首先选择水果,因为它是列表中与最低常用上位词相关的第一个。
总而言之,默认参数是一种功能,而不是像 NLTK v2.x 那样保持可重复性的错误。
因此解决方案可能是手动更改 NLTK 源以强制 use_min_depth=False:
https://github.com/nltk/nltk/blob/develop/nltk/corpus/reader/wordnet.py#L845
已编辑
要解决此问题,您可能可以对相同的同义词进行临时检查:
def wup_similarity_hacked(synset1, synset2):
if synset1 == synset2:
return 1.0
else:
return synset1.wup_similarity(synset2)