【问题标题】:python: best way to find name inside another stringpython:在另一个字符串中查找名称的最佳方法
【发布时间】:2017-09-23 04:56:31
【问题描述】:

我正在处理来自多个来源的一些聚合会员数据。我在一列中有名字,在另一列中有一个长的会员备忘录字符串。我想要将姓名与会员备忘录相匹配的最佳方式。

例如,

我想找到最好的方法:

'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),但后两个似乎并没有那么不同,因此这不是最好的方法。

有人对如何最好地实现这种类型的字符串搜索有任何想法吗?

非常感谢!

更新1:

我试过了:

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

想法?

非常感谢!

【问题讨论】:

    标签: python text fuzzy-logic


    【解决方案1】:

    最简单的方法就是检查名字和姓氏。在您的示例中,您可以这样做:

    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
    

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

    【讨论】:

    • 谢谢拉赫·萨普。超级有帮助。我添加到原帖中。请看我的评论。谢谢。
    【解决方案2】:

    使用 findall 或从 re 模块搜索。 Findall 返回匹配字符串的列表。如果找到匹配项,则搜索返回 true。 前任: 重新进口 模式='巴拉克奥巴马' 匹配= re.findall(模式,字符串)

    【讨论】:

    • 谢谢我这样做但没有工作:import re pattern='Barack Obama' matches = re.findall(pattern, "Member Data REWNEW:EX PAID ID:234242 Barack Hussein Obama WASHINGTON DC LAST CO 2834298:EEXE:00WIE")
    • 您传入的字符串中间有 Hussein,这就是找不到匹配项的原因。您可以搜索每个单词并检查您是否同时拥有这两个单词。例如:如果 re.search('Barack, string) 和 research('Obama', string): 做某事
    • 你的字符串中有侯赛因在巴拉克和奥巴马之间,所以没有匹配。试试这个:如果 re.search('Barack', string) 和 re.search('Obama', string): 做点什么
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-19
    • 1970-01-01
    • 2015-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多