【问题标题】:What's a better way to clean data before a merge?在合并之前清理数据的更好方法是什么?
【发布时间】:2017-03-21 09:56:58
【问题描述】:

我有两个不同的数据框需要合并,合并列(“标题”)需要在合并发生之前进行清理。示例数据示例如下所示;

data1 = pd.DataFrame({'id': ['a12bcde0','b20bcde9'], 'title': ['a.b. company','company_b']})

data2 = pd.DataFrame({'serial_number': ['01a2b345','10ab2030','40ab4060'],'title':['ab company','company_b (123)','company_f']})

正如预期的那样,第一个标题的合并不会成功。我一直在使用replace() 方法,但它很快就变得难以管理,因为由于拼写、区分大小写等原因,我有 100 多个标题需要更正。

关于如何最好地清理和合并数据还有其他建议吗?

完整示例:

import pandas as pd
import numpy as np

data1 = pd.DataFrame({'id': ['a12bcde0','b20bcde9'], 'title': ['a.b. company','company_b']})

data2 = pd.DataFrame({'serial_number': ['01a2b345','10ab2030','40ab4060'],'title':['ab company','company_b (123)','company_f']}) 

data2['title'].replace(regex=True,inplace=True,to_replace=r"\s\(.*\)",value=r'')

replacements = {
   'title': {
        r'a.b. company *.*': 'ab company'
    }
}
data1.replace(replacements, regex=True, inplace=True)

pd.merge(data1, data2, on='title') 

【问题讨论】:

  • 我想不出比这更好的方法了……你在想什么?
  • 你可以使用fuzzywuzzy包,例如使用ratio函数。

标签: python pandas replace merge


【解决方案1】:

首先,这个问题没有完美的解决方案,但我建议做两件事:

  • 事先做好任何您可以做的简单清洁工作,包括删除任何您不希望出现的字符。
  • 应用一些模糊匹配逻辑

您会发现这并不完美,因为即使这个示例也不能 100% 工作。


首先,让我们先让您的示例稍微复杂一点,引入一个常规拼写错误(coampany_b 而不是company_b,下面的简单清理无法识别的内容)

data1 = pd.DataFrame({'id': ['a12bcde0','b20bcde9', 'csdfsjkbku'], 'title': ['a.b. company','company_b', 'coampany_b']})
data2 = pd.DataFrame({'serial_number': ['01a2b345','10ab2030','40ab4060'],'title':['ab company','company_b (123)','company_f']})

然后让我们假设您只期望@Maarten Fabré 提到的 [a-z] 字符。因此,让我们将所有内容小写并删除其他所有内容。

data1['cleaned_title'] = data1['title'].str.lower().replace(regex=True,inplace=False,to_replace=r"[^a-z]", value=r'')
data2['cleaned_title'] = data2['title'].str.lower().replace(regex=True,inplace=False,to_replace=r"[^a-z]", value=r'')

现在,让我们使用difflib's get_close_matches(阅读更多和其他选项here

import difflib
data1['closestmatch'] = data1.cleaned_title.apply(lambda x: difflib.get_close_matches(x, data2.cleaned_title)[0])
data2['closestmatch'] = data1.cleaned_title.apply(lambda x: difflib.get_close_matches(x, data2.cleaned_title)[0])

这是生成的数据1,看起来不错!

    id          title           cleaned_title   closestmatch
0   a12bcde0    a.b. company    abcompany       abcompany
1   b20bcde9    company_b       companyb        companyb
2   csdfsjkbku  coampany_b      coampanyb       companyb

现在,这里是 data2,看起来有点不太好...我们要求它找到最接近的匹配,所以它为 company_f 找到了一个,而你显然不想要它。

    serial_number   title           cleaned_title   closestmatch
0   01a2b345        ab company      abcompany       abcompany
1   10ab2030        company_b (123) companyb        companyb
2   40ab4060        company_f       companyf        companyb

理想的情况是,如果您有一份清晰的公司名称列表,在这种情况下,您应该根据该列表找到最接近的匹配项。如果不这样做,您将不得不发挥创意或手动清理命中和未命中。

总结一下,您现在可以对 'closestmatch' 执行常规合并。

【讨论】:

    【解决方案2】:

    您可以尝试通过将所有字符设置为小写并删除所有非 [a-z] 字符并在这不会导致冲突的情况下加入此列,从而在 2 个数据帧中的每一个中创建一个简化名称列

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-04-17
      • 2011-04-08
      • 2019-06-17
      • 1970-01-01
      • 1970-01-01
      • 2011-09-06
      • 1970-01-01
      相关资源
      最近更新 更多