基于条件的 2 个大型数据集上的模糊模糊字符串匹配 - python

Posted

技术标签:

【中文标题】基于条件的 2 个大型数据集上的模糊模糊字符串匹配 - python【英文标题】:Fuzzy Wuzzy String Matching on 2 Large Data Sets Based on a Condition - python 【发布时间】:2017-08-08 09:55:27 【问题描述】:

我有 2 个已读入 Pandas DataFrames 的大型数据集(分别约为 20K 行和 ~40K 行)。当我尝试在地址字段上使用 pandas.merge 直接合并这两个 DF 时,与行数相比,我得到的匹配数微不足道。所以我想我会尝试模糊字符串匹配,看看它是否提高了输出匹配的数量。

我通过尝试在 DF1(20K 行)中创建一个新列来解决此问题,这是将 DF1[addressline] 上的 blurwuzzy 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 之间匹配的那些行。从那里我计划合并两个 df,一个在模糊匹配地址和第二个 DF 中的地址行列上。希望这听起来不会令人困惑。

【问题讨论】:

这是一个有趣的问题,但我花了很长时间才通读并意识到你在问什么。您可以包含代码来创建可运行的最小示例数据框吗?它只需要 4 或 5 行来说明您要做什么。 @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 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)) 这里的组将是'ID'以进行模糊匹配 我已经编辑了您的问题,使其仅包含您问题的相关代码,这样潜在的回答者可以更轻松地减少您问题中不需要的代码量 【参考方案1】:

您可以调整 fuzzy_match 函数以将 id 作为变量,并在进行模糊搜索之前使用它来对您的选择进行子集化(请注意,这需要将函数应用于整个数据帧而不仅仅是地址列)

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

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

【讨论】:

感谢您的建议@maxymoo!出于好奇,您是否对如何以这种方式解决问题有任何想法:“为了减少比较次数,您可以首先将具有某些共同特征的记录分组,例如地址字段的前五个字符,或者“摘自我发布的上述链接。我一直在尝试 groupby,但它并没有给我想要的结果 虽然在尝试了你的建议之后,我收到了这个错误:KeyError: ('Address1', 'occured at index Address1') @Nirav 你是否包括axis=1 是的,我做到了。在对错误发表评论后,我试图在 google 上找到解决方案并设法弄清楚将轴 = 1。同样感谢您的帮助! @Mitchell 这是因为这些行不匹配(基于截止值),我已经编辑了我的答案顶部对此进行了检查,但您也可以调整截止值

以上是关于基于条件的 2 个大型数据集上的模糊模糊字符串匹配 - python的主要内容,如果未能解决你的问题,请参考以下文章

使用 Python 对大数据集进行模糊逻辑

mysql模糊查询固定某个字符

sql更新怎么根据条件查询到了更新没有匹配到的数据不更新

多值模糊查询报表的制作

java中是如何实现基于文字标题的模糊匹配的,下面的代码是实现这个功能的吗?

字符串模糊匹配