如何模糊匹配电影标题与difflib和熊猫



我有 2 个可能重叠的电影标题列表,但可能以不同的形式编写。
它们与熊猫位于 2 个不同的数据帧中。所以我尝试将 map() 函数与 fuzzywuzzy 库一起使用,如下所示:

df1.title.map(lambda x: process.extractOne(x, choices=df2.title, score_cutoff=95))

这给出了一些高质量的结果。但是时间复杂度如此之大,以至于我只能在两个数据帧的很小的子集上运行它。当我尝试增加数据框的大小时,它很快就会变得不可用。

然后我试图用difflib替换fuzzywuzzy.而且速度要快得多。但我无法得到我想要的结果。

起初我尝试过:

df1.title.map(lambda x: difflib.get_close_matches(x, df2.title, n=1)

这很快,但结果的质量很差。甚至缺少一些简单的大写/小写更改。玩cutoff没有帮助。

所以我认为我用错了工具。在文档和示例中,我看到get_close_matches用于单个单词。在标题中有各种各样的词。

SequenceMatcher是更好的选择吗?

如果是,那么我如何将其放入map()中,使其与上述函数相同:仅返回最佳结果,并且仅在结果高于某个比率时才返回?

为了消除由于大小写差异而导致低分匹配的可能性,我建议将.upper().lower()应用于要匹配的列。 调整大小写后,您可以将所有标题的列表编译成ThisList,并使用给定的tolerance应用以下功能(如您所建议的,依赖于SequenceMatcher)。

def fuzzy_group_list_elements(ThisList,Tolerance):
    from difflib import SequenceMatcher
    Groups = {}
    TempList = ThisList.copy()
    for Elmt in TempList:
        if Elmt not in Groups.keys():
            Groups[Elmt] = []
        for OtherElmt in TempList:
            if SequenceMatcher(None,Elmt,OtherElmt).quick_ratio() > Tolerance:
                Groups[Elmt] = Groups[Elmt] + [OtherElmt]
                TempList.remove(OtherElmt)
    Groups[Elmt] = list(set(Groups[Elmt]))
    return dict((v,k) for k in Groups for v in Groups[k])

然后,可以将上述函数应用于包含电影标题的数据帧列:

Mapping = fuzzy_group_list_elements(ThisList,0.85)
df['Matched Title'] = df['Title'].replace(Mapping)

我写了一个Python包来解决这个问题。 除此之外,它还解决了问题的 n^2 复杂性(例如,对于两个长度为 100 的数据集,您的代码需要 10,000 次比较)。

您可以使用pip install fuzzymatcher安装它

您可以在此处找到存储库,在此处找到文档。

基本用法:

给定要模糊连接的 df_leftdf_right 两个数据帧,可以编写以下内容:

from fuzzymatcher import link_table, left join
# Columns to match on from df_left
left_on = ["fname", "mname", "lname",  "dob"]
# Columns to match on from df_right
right_on = ["name", "middlename", "surname", "date"]
# The link table potentially contains several matches for each record
fuzzymatcher.link_table(df_left, df_right, left_on, right_on)

或者,如果您只想链接最接近的匹配项:

fuzzymatcher.fuzzy_left_join(df_left, df_right, left_on, right_on)

最新更新