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).
3 Réponses :
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
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
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é.
On dirait que votre score de réputation est en effet assez élevé pour les commentaires :)
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