python:在另一个字符串中查找名称的最佳方法

时间:2017-09-23 04:56:32

标签: python text fuzzy-logic

我正在处理来自多个来源的一些汇总会员数据。我在一列中有名字,在另一列中有一个长成员备忘录字符串。我希望有最好的方法将名称与会员单备忘录相匹配。

例如,

我想找到最好的方法:

'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,这仍然是我在开始时提出的挑战,也就是说我想要某种逻辑将两者更明确地分开。

思考?

非常感谢你!

2 个答案:

答案 0 :(得分: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

这应该允许您将较长文本中匹配的模糊分数与较短文本进行比较。一旦你想开始将搜索项与目标字符串中不同大小的切片进行匹配,它会变得有点复杂,但你应该在那时查看正则表达式(我只是想提供一些更可能的解决方案)。

答案 1 :(得分:0)

使用findall或从re模块中搜索。 Findall返回匹配字符串列表。如果找到匹配,则搜索返回true。 例如: 进口重新 pattern ='Barack Obama' matches = re.findall(pattern,string)