web-dev-qa-db-ja.com

Pythonで文字列を含む2つのリストのJaccard Similarityを計算するにはどうすればよいですか?

ユーザー名を含む2つのリストがあり、Jaccardの類似度を計算したいと思います。出来ますか?

This スレッドは、2つの文字列間のJaccardの類似性を計算する方法を示していますが、これを2つのリストに適用します。各要素は1つのWord(例:ユーザー名)です。

10
Aventinus

結局、私は自分のソリューションを書くことになりました:

def jaccard_similarity(list1, list2):
    intersection = len(list(set(list1).intersection(list2)))
    union = (len(list1) + len(list2)) - intersection
    return float(intersection) / union
19
Aventinus

@aventinus回答にコメントを追加するほどの評判はありませんが、わかりやすくするために、ソリューションはjaccard_similarityしかし、関数はjaccard_distance、実際は1 - jaccard_similarity

12
iamlcc

Python 3:

_def jaccard_similarity(list1, list2):
    s1 = set(list1)
    s2 = set(list2)
    return len(s1.intersection(s2)) / len(s1.union(s2))
list1 = ['dog', 'cat', 'cat', 'rat']
list2 = ['dog', 'cat', 'mouse']
jaccard(list1, list2)
>>> 0.5
_

Python2の場合はreturn len(s1.intersection(s2)) / float(len(s1.union(s2)))を使用します

7
w4bo

ユーザー名が繰り返されないと仮定すると、同じ考えを使用できます。

def jaccard(a, b):
    c = a.intersection(b)
    return float(len(c)) / (len(a) + len(b) - len(c))

list1 = ['dog', 'cat', 'rat']
list2 = ['dog', 'cat', 'mouse']
# The intersection is ['dog', 'cat']
# union is ['dog', 'cat', 'rat', 'mouse]
words1 = set(list1)
words2 = set(list2)
jaccard(words1, words2)
>>> 0.5
4
klaus

繰り返される要素を含めたい場合は、Counterを使用できます。これは、内部の拡張されたdictであるため、比較的高速だと思います。

from collections import Counter
def jaccard_repeats(a, b):
    """Jaccard similarity measure between input iterables,
    allowing repeated elements"""
    _a = Counter(a)
    _b = Counter(b)
    c = (_a - _b) + (_b - _a)
    n = sum(c.values())
    return n/(len(a) + len(b) - n)

list1 = ['dog', 'cat', 'rat', 'cat']
list2 = ['dog', 'cat', 'rat']
list3 = ['dog', 'cat', 'mouse']     

jaccard_repeats(list1, list3)      
>>> 0.75

jaccard_repeats(list1, list2) 
>>> 0.16666666666666666

jaccard_repeats(list2, list3)  
>>> 0.5
1
kd88

距離 ライブラリを使用できます

#pip install Distance

import distance

distance.jaccard("decide", "resize")

# Returns
0.7142857142857143
1
LaSul

@Aventinus(私もコメントすることはできません):Jaccard similarityは集合の演算なので、分母の部分では(リストの代わりに)集合も使用する必要があります。たとえば、jaccard_similarity('aa', 'ab')0.5になります。

def jaccard_similarity(list1, list2):
    intersection = len(set(list1).intersection(list2))
    union = len(set(list1)) + len(set(list2)) - intersection

    return intersection / union

交差点では、最初にリストにキャストする必要がないことに注意してください。また、Python 3.ではfloatへのキャストは不要です。

1
Erwin Scholtens