1
votes

Optimiser la correspondance floue élément par élément entre deux listes

J'ai deux listes d'entreprises (> 2k entrées dans la liste plus longue) dans différents formats que je dois unifier. Je sais que les deux formats partagent un stub environ 80% du temps, donc j'utilise la correspondance floue pour comparer les deux listes:

def get_fuzz_score(str1, str2):

    from fuzzywuzzy import fuzz
    partial_ratio = fuzz.partial_ratio(str1, str2)
    return partial_ratio


a = ['Express Scripts', 'Catamaran Corp', 'Banmedica SA (96.7892%)', 'WebMD', 'ODC', 'Caremerge LLC (Stake%)']
b = ['Doctor on Demand', 'Catamaran', 'Express Scripts Holding Corp', 'ODC, Inc.', 'WebMD Health Services', 'Banmedica']

for i in b:
    for j in a:
        if get_fuzz_score(i, j) > 80:
            # process

J'apprécierais des réflexions sur la façon d'optimiser cette tâche pour performances (par exemple, pas besoin d'utiliser 2 boucles for).


0 commentaires

3 Réponses :


1
votes

Je suppose que vous avez installé à la fois fuzzywuzzy ET python-Levenshtein. L'installation du deuxième package a échoué et j'ai donc reçu un message:

warnings.warn ('Utilisation lente de SequenceMatcher pur-python. Installez python-Levenshtein pour supprimer cet avertissement')

Vous pouvez utiliser itertools. produit pour créer le produit cartésien:

from itertools import product
from fuzzywuzzy import fuzz  # 

a = ['Express Scripts', 'Catamaran Corp', 'Banmedica SA (96.7892%)', 'WebMD', 'ODC', 'Caremerge LLC (Stake%)']
b = ['Doctor on Demand', 'Catamaran', 'Express Scripts Holding Corp', 'ODC, Inc.', 'WebMD Health Services', 'Banmedica']

for first, second in product(a, b):
    if fuzz.partial_ratio(first, second) > 80:
        pass  # process

Si votre fonction get_fuzz_score ne grandit pas, vous pouvez la rendre obsolète:

from itertools import product
from fuzzywuzzy import fuzz

def get_fuzz_score(str1, str2):
    partial_ratio = fuzz.partial_ratio(str1, str2)
    return partial_ratio


a = ['Express Scripts', 'Catamaran Corp', 'Banmedica SA (96.7892%)', 'WebMD', 'ODC', 'Caremerge LLC (Stake%)']
b = ['Doctor on Demand', 'Catamaran', 'Express Scripts Holding Corp', 'ODC, Inc.', 'WebMD Health Services', 'Banmedica']

for first, second in product(a, b):
    if get_fuzz_score(first, second) > 80:
        # process


2 commentaires

itertools.product pourrait être exactement ce dont j'ai besoin - je vais l'essayer et faire un rapport


re: avertissement python-Levenshtein, je me suis battu avec ça pendant longtemps et j'ai fini par devoir passer à un environnement Conda pour réparer



3
votes

Premièrement, je déplacerais l'importation de fuzzywuzzy import fuzz de la fonction au début du fichier.

Ensuite, il semble que vous vouliez vérifier chaque élément, donc vous comparez de toute façon all2all et je ne vois pas de solution de contournement simple.

Si les données sont `` belles '', vous pouvez faire une heuristique simple, par exemple sur une première lettre (d'après les exemples que vous avez publiés - mais cela dépend des données).

Meilleures salutations

P.s. Je ferais un commentaire si mon score était suffisamment élevé.


1 commentaires

On dirait que votre score de réputation est en effet assez élevé pour les commentaires :)



2
votes

fuzzywuzzy fournit une famille de fonctions process.extract * pour vous aider, par exemple:

from fuzzywuzzy import process

a = ['Express Scripts', 'Catamaran Corp', 'Banmedica SA (96.7892%)', 'WebMD', 'ODC', 'Caremerge LLC (Stake%)']
b = ['Doctor on Demand', 'Catamaran', 'Express Scripts Holding Corp', 'ODC, Inc.', 'WebMD Health Services', 'Banmedica']

for name in a:
    print(name, process.extract(name, b, limit=3))

affichera chaque nom dans a et les trois premières correspondances de b.

c'est toujours O (n ** 2) mais parce que cette bibliothèque est du code open source, vous obtenez pour voir comment extract est défini et peut-être simplement faire le prétraitement une fois plutôt qu'à chaque fois, ce qui, espérons-le, accélérerait beaucoup les choses


0 commentaires