web-dev-qa-db-fra.com

Comment calculer la similarité Jaccard de deux listes contenant des chaînes en Python?

J'ai deux listes avec les noms d'utilisateur et je veux calculer la similarité de Jaccard. C'est possible? 

This thread montre comment calculer la similarité Jaccard entre deux chaînes, mais je souhaite l’appliquer à deux listes, où chaque élément est un mot (par exemple, un nom d’utilisateur). 

7
Aventinus

J'ai fini par écrire ma propre solution après tout: 

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

@aventinus Je n'ai pas assez de réputation pour ajouter un commentaire à votre réponse, mais pour clarifier les choses, votre solution mesure le jaccard_similarity mais la fonction porte à tort le nom jaccard_distance, qui est en fait 1 - jaccard_similarity.

8
iamlcc

En supposant que vos noms d'utilisateur ne se répètent pas, vous pouvez utiliser la même idée:

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
3
klaus
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
2
w4bo

Si vous souhaitez inclure des éléments répétés, vous pouvez utiliser Counter, ce qui, je suppose, est relativement rapide puisqu'il ne s'agit que d'une dict étendue:

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 1 - n/(len(a) + len(b) - n)

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

jaccard_repeats(list1, list3)      
>>> 0.25

jaccard_repeats(list1, list2) 
>>> 0.8333333333333334

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

Vous pouvez utiliser le Distance library 

#pip install Distance

import distance

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

# Returns
0.7142857142857143
0
LaSul