2017-09-23 66 views
1

我正在處理來自多個來源的一些聚合成員資格數據。我在一列中有名字,在另一列中有長成員資格備忘錄字符串。我想最好的方式來匹配名稱成員資格備忘錄。python:在另一個字符串中查找名稱的最佳方法

例如,

我想最好的方式找到:

'Barack Obama' 
在下列字符串

,由於該數據彙總和格式可能會有所不同。這裏有幾個例子:

"Member Data REWNEW:EX PAID ID:234242 Barack Obama WASHINGTON DC LAST CO 2834298:EEXE:00WIE" 
"Member Data REWNEW:EX PAID ID:234242 Barack Hussein Obama WASHINGTON DC LAST CO 2834298:EEXE:00WIE" 
"Member Data REWNEW:EX PAID ID:234242 Obama Barack WASHINGTON DC LAST CO 2834298:EEXE:00WIE" 
"Member Data REWNEW:EX PAID ID:234242 Barack H Obama WASHINGTON DC LAST CO 2834298:EEXE:00WIE" 

在過去,我用fuzzywuzzy做模糊邏輯匹配。如果我正在比較兩個字符串,但這並不試圖在另一個較長的字符串中找到一個字符串,這往往會工作得很好。例如:

from fuzzywuzzy import fuzz 
from fuzzywuzzy import fuzz 

print(fuzz.ratio("Barack Obama", "Barack Obama")) 
print(fuzz.ratio("Michelle Obama", "Barack Obama")) 
print(fuzz.ratio("Barack Obama", "Member Data REWNEW:EX PAID ID:234242 Barack Hussein Obama WASHINGTON DC LAST CO 2834298:EEXE:00WIE")) 
print(fuzz.ratio("Michelle Obama", "Member Data REWNEW:EX PAID ID:234242 Barack Hussein Obama WASHINGTON DC LAST CO 2834298:EEXE:00WIE")) 

100 
54 
22 
16 

這是非常清楚的是,前兩個是非常不同的(100:54),然而在第二兩不似乎是所有不同的,因此這不是最佳方法。

有沒有人有關於如何最好地實現這種類型的字符串搜索的任何想法?

非常感謝!

UPDATE1:

我想:

memo_string="Member Data REWNEW:EX PAID ID:234242 Barack Hussein Obama WASHINGTON DC LAST CO 2834298:EEXE:00WIE" 
search_terms = "Barack Obama" 

memo_words = memo_string.split(" ") 
search_term_count = len(search_terms.split(" ")) 
memo_slices = [] 
for i in range(len(memo_words) - search_term_count): 
    memo_slices.append(" ".join(memo_words[i:i+search_term_count])) 
max_for_memo = 0 
best_match_in_memo = None 
for memo_slice in memo_slices: 
    fuzz_score = fuzz.ratio(search_terms, memo_slice) 
    if fuzz_score > max_for_memo: 
     max_for_memo = fuzz_score 
     best_match_in_memo = memo_slice 

print(max_for_memo) 

I also tried with search_terms = 'Michelle Obama' 

兩個評分分別爲52和50,這仍然存在,我在開頭所述的挑戰,這是我想某種的邏輯將兩者更明確地區分開來。

想法?

非常感謝!

回答

0

使用findall或從re模塊搜索。 Findall返回匹配字符串的列表。如果找到匹配,搜索返回true。 例如: 進口重新 模式=「奧巴馬」 匹配= re.findall(模式,字符串)

+0

謝謝你,我這樣做,並沒有工作:進口重新 模式=「奧巴馬」 匹配= re.findall(模式,「會員數據REWNEW:EX支付ID:234242巴拉克·侯賽因·奧巴馬華盛頓特區LAST CO 2834298:EExe類似:00WIE「) –

+0

你傳入的字符串之間有侯賽因,所以這就是爲什麼沒有找到匹配。你可以對每個單詞進行搜索,並檢查是否有兩個單詞。 例如: 如果re.search(「巴拉克,字符串),並重新 搜索(」奧巴馬」,字符串): 做一些 – user8659364

+0

你的字符串中有侯賽因在美國總統奧巴馬因此&放大器之間;#39; S不匹配。試試這個: if re.search('Barack',string)和re.search('Obama',string): 做些什麼 – user8659364

2

最簡單的方法將只是檢查的名字及姓氏。在你的例子中,你可以這樣做:

search_terms = "Barack Obama" 
matches = [] 
for memo_string in memos_list: 
    for word in search_terms.split(" "): 
     if word not in memo_string: 
      break 
    else: 
     matches.append(memo_string) # triggers when the for loop doesn't break 

這將匹配包含您的確切搜索條件的所有備忘錄。儘管如此,這並不檢查術語是否彼此相鄰並要求它們完全匹配。

對於較模糊的匹配,您可以將您的搜索條件與備忘錄字符串的切片進行比較(爲簡潔起見,某些前導碼被省略)。

memo_words = memo_string.split(" ") 
search_term_count = len(search_terms.split(" ")) 
memo_slices = [] 
for i in range(memo_words - search_term_count): 
    memo_slices.append(" ".join(memo_words[i:i+search_term_count])) 
max_for_memo = 0 
best_match_in_memo = None 
for memo_slice in memo_slices: 
    fuzz_score = fuzz.ratio(search_terms, memo_slice) 
    if fuzz_score > max_for_memo: 
     max_for_memo = fuzz_score 
     best_match_in_memo = memo_slice 

這應該允許您比較較長文本與較短文本匹配的模糊分數。一旦你想開始將搜索條件與目標字符串中不同大小的片段進行匹配,它會變得更加複雜,但是你應該在那個時候查看正則表達式(我想我會提供更多可能的解決方案)。

+0

謝謝Rach Sarp。超級有用。我加入了原文。請看我的評論。謝謝。 –

相關問題