【问题标题】:Python Pandas - SequenceMatch columns for each value and return closet matchPython Pandas - 每个值的 SequenceMatch 列并返回壁橱匹配
【发布时间】:2017-10-10 12:09:50
【问题描述】:

我有两个 DataFrame 对象,每个对象包含 2 列字符串数据。我需要将a 和b 列与c 和d 进行比较,然后根据最高匹配率合并两个DataFrame 对象。

   DF1                                DF2
a       b                          c       d
apple  paster                      doser   ankle
bac    bur                         are     bun
sit    sign                        and     lake
car    bun                         ape     mason
alli   makeup                      noodle  paster

示例输出

          RESULT                               
a       b       c       d       comparison_ratio
apple  paster  noodle  paster   1
bac    bur     are     bun      0.95
sit    sign    and     lake     random number based on match
car    bun     are     bun      1
alli   makeup  noodle  paster   random number based on match

显然,除了完美匹配1之外,这些比率都是由比例组成的。

我可以遍历每个 DataFrame 对象的每一行并应用 difflib.SequenceMatcher 函数来返回比率,然后将最大比率与相应的数据一起设置该行上的值,但考虑到有多大数据是这将需要很长时间。我很好奇是否可以以某种方式使用apply 将此函数应用于两个DataFrame 对象

【问题讨论】:

    标签: python string pandas string-comparison


    【解决方案1】:

    (您的某些输出在原始df2 和示例输出之间是否发生了变化?我假设示例输出具有正确的df2。)看起来您正在将a 与c 配对和b 到d 逐行,所以首先,让我们将数据帧连接在一起。

    import pandas as pd
    from difflib import SequenceMatcher
    
    df1 = pd.DataFrame({'a': ['apple', 'bac', 'sit', 'car', 'alli'],
                        'b': ['paster', 'bur', 'sign', 'bun', 'makeup']})
    
    df2 = pd.DataFrame({'c': ['noodle', 'are', 'and', 'ape', 'noodle'],
                        'd': ['paster', 'bun', 'lake', 'bun', 'paster']})
    
    df = pd.concat([df1, df2], axis=1)
    

    我们必须做一个包含两列的apply。我们应该创建一个可以将两个列名作为参数的函数。

    def sim_metric(df, col1, col2):
        return SequenceMatcher(None, df[col1], df[col2]).ratio()
    

    我必须查看SequenceMatcher 的工作原理。需要注意的一点是它可以接收数组,所以你必须小心:你对 string 序列匹配、元素到元素特别感兴趣——这就是为什么你需要apply 并且可以' t 直接插入列。

    现在您可以将此sim_metric 应用于a 和c 以及b 和d。

    df['a_c_comp'] = df.apply(sim_metric,
                              args=('a', 'c'),
                              axis=1)
    
    df['b_d_comp'] = df.apply(sim_metric,
                              args=('b', 'd'),
                              axis=1)
    

    注意我是如何使用apply 的args arg 来指定通用sim_metric 的列名的。

    最后,我们可以为最后的comparison_ratio 列添加max。

    df['comparison_ratio'] = df[['a_c_comp', 'b_d_comp']].max(axis=1)
    print(df)
    

    这是结果。

           a       b       c       d  a_c_comp  b_d_comp  comparison_ratio
    0  apple  paster  noodle  paster  0.363636  1.000000          1.000000
    1    bac     bur     are     bun  0.333333  0.666667          0.666667
    2    sit    sign     and    lake  0.000000  0.000000          0.000000
    3    car     bun     ape     bun  0.333333  1.000000          1.000000
    4   alli  makeup  noodle  paster  0.200000  0.333333          0.333333
    

    【讨论】:

    • 这似乎只是数据框列之间的检查。我需要针对 c 列和 d 列中的所有项目检查索引 1 列,然后找到最大匹配率并将 c 和 d 的最大匹配率值连接到该行。这就是结果df在结果df中发生变化的原因
    • @AranFreel 啊,好吧......不过,仍然不能完全确定所有的比较。举个例子,你能不能把df1中的apple和paster告诉我你想要什么成对比较?
    • DF1 带有 paste 和 apple 将在 DF2 中与持有面条 paste 的行匹配,因为 DF1 中的 b 是 paste 而 DF2 中的 d 是 paste。索引 0 列 a 和 b(apple 和 paster)中的两个值都将与列 c 和 d 中的所有值进行比较。 Apple 将与 c 列和 d 列中的每个值进行比较。帕斯特也会这样做。在比较所有值之后,最大比率匹配将从 DF2 行中获取并连接到进行比较的 DF1(苹果和粘贴)
    • @AranFreel 酷,感谢您的澄清。好吧,您似乎可以 (1) 退出循环,因为您将每个元素 (apple) 与列中的每个条目(c 中的所有内容)进行比较,而 apply 似乎并没有适合——除非 (2) 你笛卡尔加入df1 和df2,然后你想做的所有比较都在干净的行中,此时你可以继续使用apply。但是,对于大型数据集,这可能是错误的方法。也许您可以编辑您的问题以澄清我们谈到的比较,然后其他人可以插话!
    猜你喜欢
    • 2021-06-27
    • 1970-01-01
    • 2018-07-14
    • 1970-01-01
    • 2020-04-11
    • 2012-05-09
    • 1970-01-01
    • 2019-02-08
    • 2021-08-28
    相关资源
    最近更新 更多