2017-03-17 81 views
2

我有兩個大型數據集,我讀入Pandas DataFrames(分別爲〜20K行和〜40K行)。當我嘗試在地址字段上使用pandas.merge完全合併這兩個DF時,與行數相比,我得到了一個微不足道的匹配數。所以我想我會嘗試模糊字符串匹配,看看它是否改善了輸出匹配的數量。基於條件的兩個大型數據集上的模糊模糊字符串匹配-python

我嘗試在DF1 [20K行]中創建一個新列,這是將DF1 [addressline]上的fuzzywuzzy extractone函數應用於DF2 [addressline]的結果。我很快就意識到這將會持續下去,因爲它將接近10億次比較。

這兩個數據集都有「縣」字段,我的問題是這樣的:有沒有一種方法可以根據「縣」字段在兩個DF中的「地址線」字段中有條件地進行模糊字符串匹配?研究類似於我的問題我偶然發現了這個討論:Fuzzy logic on big datasets using Python

但是,我仍然模糊(沒有雙關語意圖)如何去基於縣的分組/阻止字段。任何建議將不勝感激!

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)) 

我已經添加了2個圖像,這兩個圖像是導入到Excel中的2個不同DF的樣本集。並非所有的字段都被包含在內,因爲它們對我的問題並不重要。爲了重申我的最終目標,我希望在DF之一中有一個新的列,它具有將第二個DF中的地址線與其他地址線進行模糊匹配的最高結果,但僅適用於兩個DF之間的縣匹配的那些行。從那裏我打算合併兩個dfs,一個在模糊匹配地址和第二個DF中的地址線列。希望這聽起來不會令人困惑。

+0

這是一個有趣的問題,但它花了我很長時間來閱讀並意識到你在問什麼。你可以包含代碼來創建一個可運行的最小示例數據框?它只需要4或5行來說明你想要做什麼。 – maxymoo

+0

@maxymoo這裏是你要求的樣品: 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 ['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))這裏的組是'ID'來模糊匹配 – Nirav

+0

我編輯了你的問題,以便它只包含相關的代碼你的問題,它可以讓潛在的回答者更容易地減少註冊量在你的問題中加入代碼 – maxymoo

回答

2

你可以調整你的fuzzy_match功能採取id作爲一個變量,並使用該做模糊搜索前,子集你的選擇(請注意,這需要應用的功能在整個數據框,而不是隻是地址欄)

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

謝謝你的建議@maxymoo!出於好奇,你會碰巧想到如何以這種方式解決問題:「爲了減少比較次數,你可以首先將具有一些共同特徵的記錄分組,如地址字段的前五個字符,或者一個共同的標記,然後只比較共享一個特徵的記錄,這個想法被稱爲「阻塞」,並且通常會減少必須進行的全面比較的數量,以便於管理。從上面的鏈接採取我張貼。我一直在嘗試groupby,但它並沒有給我我想要的結果 – Nirav

+0

雖然在嘗試你的建議後,我得到這個錯誤:KeyError :('Address1','發生在索引地址1') – Nirav

+0

@Nirav did you包括'axis = 1'? – maxymoo