2017-03-17 4 views
2

J'ai deux grands ensembles de données que j'ai lus dans Pandas DataFrames (~ 20K lignes et ~ 40K rangées respectivement). Lorsque j'essaie de fusionner ces deux DF directement en utilisant pandas.merge dans le champ d'adresse, j'obtiens un nombre dérisoire de correspondance par rapport au nombre de lignes. J'ai donc pensé que j'essaierais de faire correspondre les chaînes floues pour voir si cela améliore le nombre de résultats. J'ai abordé ceci en essayant de créer une nouvelle colonne dans DF1 (lignes 20K) qui était le résultat de l'application de la fonction fuzzywuzzy extractone sur DF1 [addressline] à DF2 [addressline]. Je me suis vite rendu compte que cela prendrait une éternité puisqu'elle ferait près d'un milliard de comparaisons. Ces deux ensembles de données ont des champs "Comté" et ma question est la suivante: existe-t-il un moyen de faire une correspondance fuzzy string sur les champs "addressline" dans les deux champs de saisie, les champs "county" étant les mêmes? Recherche des questions similaires à la mienne, je suis tombé sur cette discussion: Fuzzy logic on big datasets using PythonFuzzy Wuzzy Chaîne correspondant à 2 grands ensembles de données basés sur une condition - python

Cependant, je suis encore flou (sans jeu de mots) sur la façon de regrouper/bloquer les champs en fonction du comté. Tout avis serait grandement apprécié!

import pandas as pd 
from fuzzywuzzy import process 

def fuzzy_match(x, choices, scorer, cutoff): 
    return process.extractOne(x, choices = choices, scorer = scorer, score_cutoff= cutoff)[0] 

test = pd.DataFrame({'Address1':['123 Cheese Way','234 Cookie Place','345 Pizza Drive','456 Pretzel Junction'],'ID':['X','U','X','Y']}) 
test2 = pd.DataFrame({'Address1':['123 chese wy','234 kookie Pl','345 Pizzza DR','456 Pretzel Junktion'],'ID':['X','U','X','Y']}) 
test['Address1'] = test['Address1'].apply(lambda x: x.lower()) 
test2['Address1'] = test2['Address1'].apply(lambda x: x.lower()) 
test['FuzzyAddress1'] = test['Address1'].apply(fuzzy_match, args = (test2['Address1'], fuzz.ratio, 80)) 

J'ai ajouté 2 images qui sont des jeux d'échantillons de 2 DF différents importés dans Excel. Tous les champs n'ont pas été inclus car ils ne sont pas importants pour ma question. Pour réitérer mon objectif final, je veux une nouvelle colonne dans l'un des DFs qui a le meilleur résultat de flou correspondant à une ligne d'adresse avec les autres lignes d'adresse dans le 2e DF mais seulement pour les lignes où les comtés correspondent entre les deux DFs. De là, je prévois de fusionner les deux dfs, l'un sur l'adresse appariée floue et la colonne de la ligne d'adresse dans le 2e DF. J'espère que cela ne semble pas confus.

+0

Ceci est une question intéressante mais il m'a fallu beaucoup de temps pour lire et réaliser ce que vous demandez. pouvez-vous inclure du code pour créer un exemple de base de données runnable minimal? il faudrait seulement 4 ou 5 lignes pour illustrer ce que vous essayez de faire. – maxymoo

+0

@maxymoo Voici un échantillon comme vous avez demandé: test = pd.DataFrame ({'Address1': ['123 Cheese Way', '234 Cookie Place', '345 Pizza Drive', '456 Pretzel Junction'], 'ID': ['X', 'U', 'X', 'Y']}) test2 = pd.DataFrame ({'Adresse1': ['123 chese wy', '234 kookie Pl', '345 Pizzza DR ',' 456 Pretzel Junktion '],' ID ': [' X ',' U ',' X ',' Y ']}) test [' Adresse1 '] = test [' Adresse1 ']. (lambda x: x.lower()) test2 ['Address1'] = test2 ['Adresse1']. apply (lambda x: x.lower()) test ['FuzzyAddress1'] = test ['Adresse1'] .apply (fuzzy_match, args = (test2 ['Address1'], fuzz.ratio, 80)) Ici, les groupes seront 'ID' à fuzzy match sur – Nirav

+0

J'ai édité votre question pour qu'elle ne contienne que le code correspondant votre question, il est plus facile pour les répondeurs potentiels de minimiser la quantité de code eeded dans vos questions – maxymoo

Répondre

2

Vous pouvez adapter votre fonction fuzzy_match prendre l'ID comme une variable et utiliser pour sous-ensemble de vos choix avant de faire la recherche floue (notez que cela nécessite l'application de la fonction sur l'ensemble dataframe plutôt que juste la colonne d'adresse)

def fuzzy_match(x, choices, scorer, cutoff): 
    return process.extractOne(x['Address1'], 
          choices=choices.loc[choices['ID'] == x['ID'], 
               'Address1'], 
          scorer=scorer, 
          score_cutoff=cutoff)[0] 

test['FuzzyAddress1'] = test.apply(fuzzy_match, 
            args=(test2, fuzz.ratio, 80), 
            axis=1) 
+0

Merci pour votre suggestion @maxymoo! Par curiosité, auriez-vous des idées pour aborder le problème de cette façon: «Pour réduire le nombre de comparaisons, vous pouvez d'abord regrouper des enregistrements ayant certaines caractéristiques en commun, comme les cinq premiers caractères d'un champ d'adresse, ou Ensuite, ne comparez que les enregistrements qui partagent une fonctionnalité, cette idée est appelée "blocage" et réduit généralement le nombre de comparaisons totales que vous devez effectuer pour gérer quelque chose. " Tiré du lien ci-dessus j'ai posté.J'ai essayé groupby mais il ne m'a pas donné les résultats que je veux – Nirav

+0

Bien que après avoir essayé votre suggestion, j'obtiens cette erreur: KeyError: ('Address1', 's'est produit à l'index Address1') – Nirav

+0

@Nirav avez-vous include 'axis = 1'? – maxymoo