前一篇文章介紹了 Counter
類別,這個類別會對列表或字串中的相同元素做累加。然而有些時候,我們並不在意元素的出現次數,這時可以透過內建類別 set
集合來做統計:
>>> s = "庭院深深深幾許"
>>> set(s)
{'幾', '庭', '深', '許', '院'}
set
是不看順序而且元素必定唯一的,這個性質可以用來評估兩個集合的相似性。我們可以透過 &
運算來取兩個集合的交集:
>>> s1 = set("蘋果真好吃")
>>> s2 = set("好吃的蘋果")
>>>
>>> print(s1)
>>> print(s2)
>>> print(s1 & s2)
{'真', '好', '果', '吃', '蘋'}
{'的', '好', '果', '吃', '蘋'}
{'吃', '好', '蘋', '果'}
用 |
運算則可以取兩個集合的聯集:
>>> print(s1 | s2)
{'的', '真', '好', '果', '吃', '蘋'}
那這兩個字串的相似度,就可以表示為交集除以聯集:
>>> intersection = s1 & s2
>>> union = s1 | s2
>>> len(intersection) / len(union)
0.6666666666666666
當兩個字串不相似時,這個分數就會很低:
>>> def similarity(s1, s2):
>>> s1 = set(s1)
>>> s2 = set(s2)
>>>
>>> intersection = s1 & s2
>>> union = s1 | s2
>>>
>>> return len(intersection) / len(union)
>>>
>>> print(similarity("蘋果真好吃", "好吃的蘋果"))
>>> print(similarity("蘋果真好吃", "香蕉好難吃"))
0.6666666666666666
0.25
其實像這樣的交集與聯集的操作,同樣適用於 Counter
類別:
>>> from collections import Counter
>>>
>>> def similarity2(s1, s2):
>>> s1 = Counter(s1)
>>> s2 = Counter(s2)
>>>
>>> intersection = sum((s1 & s2).values())
>>> union = sum((s1 | s2).values())
>>>
>>> return intersection / union
>>>
>>> print(similarity2("蘋果真好吃", "好吃的蘋果"))
>>> print(similarity2("蘋果真好吃", "好好吃的蘋果"))
>>> print(similarity2("蘋果真好吃", "香蕉好難吃"))
0.6666666666666666
0.5714285714285714
0.25
因為 Counter
做完交集與聯集的操作後,依然是個字典,所以使用 .values()
將所有統計值加總在一起,因此「好好吃的蘋果」會比「好吃的蘋果」更不相似於「蘋果真好吃」。