如何在存在错别字的Pandas数据框中最有效地去重?

3
我是一位有用的助手,可以为您翻译文本。
我有一个包含姓名和地址的数据框需要去重。但问题在于,这些字段中可能存在拼写错误,尽管它们仍然是重复的。例如,假设我有以下数据框:
  index  name          zipcode
-------  ----------  ---------
      0  john doe        12345
      1  jane smith      54321
      2  john dooe       12345
      3  jane smtih      54321

这些错别字可能出现在姓名或邮政编码中,但是针对这个问题,我们只需要担心姓名。显然,0和2是重复的,1和3也是如此。但是,最有效的计算方法是什么呢?
我一直在使用Levenshtein距离来计算两个字符串之间的距离,从fuzzywuzzy包中计算,当数据框很小且可以通过迭代进行时,这种方法非常有效:
from fuzzywuzzy import fuzz

for index, row in df.iterrows():
    for index2, row2 in df.iterrows():
        ratio = fuzz.partial_ratio(row['name'], row2['name'])

        if ratio > 90:  # A good threshold for single character typos on names
            # Do something to declare a match and throw out the duplicate

显然,这不是一种可扩展的方法,不幸的是我需要去重一个大约有700万行的数据框。如果我还需要去重邮政编码中的潜在错误,那么情况会更糟。是的,我可以使用.itertuples()来执行此操作,这将使我获得约100倍的速度提升,但除了这种笨拙的O(n^2)解决方案之外,我是否错过了更明显的东西?
有更有效的方法可以处理这些嘈杂的数据吗?我已经研究了dedupe package,但那需要有标记的数据进行监督学习,而我既没有也没有印象这个软件包可以处理无监督学习。我可以制作自己的无监督文本聚类算法,但如果已经有现成的更好的方法,我宁愿不去那么远。

1
dedupe软件包将帮助您创建一些带标签的数据(我是该软件包的作者)。 - fgregg
3个回答

3

软件包pandas-dedupe可以帮助您完成任务。

pandas-dedupe的工作原理如下:首先,它要求您标记一堆记录,它最困惑的是哪些。然后,它使用此知识解决重复实体。就这样 :)

您可以尝试以下操作:

import pandas as pd
from pandas_dedupe import dedupe_dataframe

df = pd.DataFrame.from_dict({'name':['john', 'mark', 'frank', 'jon', 'john'], 'zip':['11', '22', '33', '11', '11']})

dd = dedupe_dataframe(df, ['name', 'zip'], canonicalize=True, sample_size=1)

控制台会要求您对一些示例进行标记。 如果有重复项,请点击“y”,否则点击“n”。完成后点击“f”。 然后它将在整个数据框上执行去重操作。

2

string-grouper 这个包非常适合这种情况。它使用了N-Grams的TF-IDF算法,比levenshtein算法快得多。

from string_grouper import group_similar_strings

def group_strings(strings: List[str]) -> Dict[str, str]:
    series = group_similar_strings(pd.Series(strings))

    name_to_canonical = {}
    for i, s in enumerate(strings):
        deduped = series[i]
        if (s != deduped):
            name_to_canonical[s] = deduped

    return name_to_canonical

0
对于邮政编码,我可以相当自信地说,如果没有一些字段验证机制的话,是无法检测出错别字的(两个邮政编码可能看起来非常相似,但都是有效的邮政编码)。
如果数据已经排序,并假设在哪里发生了错误别字(第一个字母很不可能出错,除非是常见的替换情况),你也许可以利用这一点,将它们作为单独的字母块进行搜索。如果你对姓氏也有同样的假设,那么你可以将它们分成26^2个不同的子组,并且只在它们各自的字段内进行搜索。
你还可以尝试另一种方法,只关注原始的名字和姓氏集合。如果你要搜索700万个项目,并且有6万个"约翰",你只需要将它们与"Jhon"进行一次比较,就能找到错误,然后搜索并删除或修复"Jhon"。但是这仍然是基于将其分解为名字和姓氏系列(使用pandas的str.extract(),正则表达式可使用"([\w]+) ([\w]+)"之类的形式,根据数据需求进行调整)的前提下。

我决定不在原问题中包含名称解析,因为它与问题并不直接相关。但是为了记录,我正在使用nameparser包来处理实际的名称解析,它对于这个任务做得相当不错。 - CJ Sullivan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接