重复数据删除具有拼写错误的Pandas数据帧的最有效方法是什么?

时间:2018-01-01 23:04:30

标签: python pandas nlp python-dedupe

我有一个名称和地址的数据框,我需要重复数据删除。问题是,其中一些字段可能存在拼写错误,即使它们仍然是重复的。例如,假设我有这个数据帧:

  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 package中两个字符串之间的距离,当数据帧较小时,它可以很好地工作,我可以通过它迭代它:

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

显然,这不是一种可以很好地扩展的方法,不幸的是我需要重复数据删除大约7M行的数据帧。显然,如果我还需要重复删除邮政编码中的潜在拼写错误,情况会变得更糟。是的,我可以用.itertuples()做到这一点,这会给我一个速度提高约100倍的因素,但是我错过了比这个笨重的O(n^2)解决方案更明显的东西吗?

我是否可以采用更有效的方法来推断这些嘈杂的数据?我已查看了dedupe package,但这需要标记数据用于监督学习,而且我没有任何也不会认为此程序包将处理无监督学习。我可以滚动我自己的无监督文本聚类算法,但如果有一个现有的,更好的方法,我宁愿不必走那么远。

3 个答案:

答案 0 :(得分:1)

软件包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”完成。 然后,它将在整个数据帧上执行重复数据删除。

答案 1 :(得分:0)

对于zipcodes,我可以相当自信地声明,如果没有某种字段验证机制,你就无法检测到拼写错误(两个zipcodes看起来非常接近并且都是有效的zipcodes)

如果对数据进行排序,并对输入拼写错误的位置进行了一些假设(除了常见的替换外,第一个字母极不可能),您可以利用它并将它们作为不同的每个字母的块进行搜索。如果您对姓氏假设相同,则可以将它们划分为26 ^ 2个不同的子组,并且只在它们的字段中进行搜索。

你也可以尝试一种方法,只看一下ORIG​​INAL的名字和姓氏。如果您正在搜索700万件物品,并且您有6万件物品,那么您只需要将它们与“#J; Jhon"找到错误,然后搜索" Jhon"并删除或修复它。但是,这再次假设您将其分解为框架内的名字和姓氏系列(使用熊猫" str.extract(),使用"([\ w] + )([\ w] +)"或者像你的正则表达式那样,如数据所要求的那样)

答案 2 :(得分:0)

string-grouper软件包是完美的选择。它使用TF-IDF和下方的N-Grams,并且比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