如何使用difflib和pandas模糊匹配电影标题?

时间:2016-07-13 13:47:36

标签: python pandas fuzzy-search difflib fuzzywuzzy

我有两个可能重叠的电影片名列表,但可能以不同的形式书写 它们与熊猫有两种不同的数据帧。所以我尝试将map()函数与fuzzywuzzy库一起使用,如下所示:

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

这给出了一些高质量的结果。但是时间复杂度使得我只能在两个数据帧的非常小的子集上运行它。当我尝试递增数据帧的大小时,它会很快变得无法使用。

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

起初我试过了:

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

这很快但结果的质量很差。甚至错过了一些简单的大写/小写更改。使用cutoff并没有帮助。

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

SequenceMatcher是更好的选择吗?

如果是,那么我如何将其纳入map()所以它与前面提到的函数相同:只返回最佳结果,并且仅当结果高于某个比率时?

2 个答案:

答案 0 :(得分:1)

为了消除因案例差异导致的低分匹配的可能性,我建议将.upper().lower()应用于您匹配的列。调整案例后,您可以将所有标题的列表编译为ThisList并应用以下函数(依照您的建议,依赖于SequenceMatcher)给定tolerance

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)

答案 1 :(得分:0)

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

您可以使用pip install fuzzymatcher

进行安装

您可以找到回购here和文档here

基本用法:

给定两个要模糊连接的数据框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)