【问题标题】:Searching one Python dataframe / dictionary for fuzzy matches in another dataframe在一个 Python 数据帧/字典中搜索另一个数据帧中的模糊匹配
【发布时间】:2017-05-18 05:29:42
【问题描述】:

我有以下 pandas 数据框,其中包含 50,000 行和 20 列(包括相关列的 sn-p):

df1

            PRODUCT_ID           PRODUCT_DESCRIPTION
0           165985858958         "Fish Burger with Lettuce"
1           185965653252         "Chicken Salad with Dressing"
2           165958565556         "Pork and Honey Rissoles"
3           655262522233         "Cheese, Ham and Tomato Sandwich"
4           857485966653         "Coleslaw with Yoghurt Dressing"
5           524156285551         "Lemon and Raspberry Cheesecake"

我还有以下数据框(我也以字典形式保存),它有 2 列和 20,000 个唯一行:

df2(也保存为 dict_2)

       PROD_ID   PROD_DESCRIPTION
0      548576    "Fish Burger"
1      156956    "Chckn Salad w/Ranch Dressing"
2      257848    "Rissoles - Lamb & Rosemary"
3      298770    "Lemn C-cake"
4      651452    "Potato Salad with Bacon"
5      100256    "Cheese Cake - Lemon Raspberry Coulis"

我想要做的是将 df1 中的“PRODUCT_DESCRIPTION”字段与 df2 中的“PROD_DESCRIPTION”字段进行比较,并找到最接近的匹配项以帮助完成繁重的工作。然后我需要手动检查匹配,但它会快得多理想的结果看起来像这样,例如注明一个或多个部分匹配:

     PRODUCT_ID      PRODUCT_DESCRIPTION               PROD_ID   PROD_DESCRIPTION
0    165985858958    "Fish Burger with Lettuce"        548576    "Fish Burger"
1    185965653252    "Chicken Salad with Dressing"     156956    "Chckn Salad w/Ranch Dressing"
2    165958565556    "Pork and Honey Rissoles"         257848    "Rissoles - Lamb & Rosemary"     
3    655262522233    "Cheese, Ham and Tomato Sandwich" NaN       NaN
4    857485966653    "Coleslaw with Yoghurt Dressing"  NaN       NaN
5    524156285551    "Lemon and Raspberry Cheesecake"  298770    "Lemn C-cake"
6    524156285551    "Lemon and Raspberry Cheesecake"  100256    "Cheese Cake - Lemon Raspberry Coulis"

我已经完成了一个确定完全匹配的连接。保留索引并不重要,因为每个 df 中的产品 ID 都是唯一的。结果也可以保存到一个新的数据帧中,因为这将被应用到具有大约 1400 万行的第三个数据帧。

我使用了以下问题和答案(除其他外):

Is it possible to do fuzzy match merge with python pandas
Fuzzy merge match with duplicates 包括按照答案之一的建议尝试 jellyfish 模块
Python fuzzy matching fuzzywuzzy keep only the best match
Fuzzy match items in a column of an array

还有各种循环/函数/映射等,但都没有成功,要么获得第一个得分低的“模糊匹配”,要么没有检测到匹配。

我喜欢按照here 生成匹配/距离分数列的想法,因为这样可以加快手动检查过程。

我正在使用 Python 2.7、pandas 并安装了fuzzywuzzy。

【问题讨论】:

    标签: python python-2.7 pandas string-matching fuzzywuzzy


    【解决方案1】:

    您应该能够遍历两个数据帧并使用您想要的信息填充第三个数据帧的字典:

    d = {
        'df1_id': [],
        'df1_prod_desc': [],
        'df2_id': [],
        'df2_prod_desc': [],
        'fuzzywuzzy_sim': []
    }
    for _, df1_row in df1.iterrows():
        for _, df2_row in df2.iterrows():
            d['df1_id'] = df1_row['PRODUCT_ID']
            ...
    df3 = pd.DataFrame.from_dict(d)
    

    【讨论】:

      【解决方案2】:

      使用fuzz.ratio 作为我的距离度量,像这样计算我的距离矩阵

      df3 = pd.DataFrame(index=df.index, columns=df2.index)
      
      for i in df3.index:
          for j in df3.columns:
              vi = df.get_value(i, 'PRODUCT_DESCRIPTION')
              vj = df2.get_value(j, 'PROD_DESCRIPTION')
              df3.set_value(
                  i, j, fuzz.ratio(vi, vj))
      
      print(df3)
      
          0   1   2   3   4   5
      0  63  15  24  23  34  27
      1  26  84  19  21  52  32
      2  18  31  33  12  35  34
      3  10  31  35  10  41  42
      4  29  52  32  10  42  12
      5  15  28  21  49   8  55
      

      设置可接受距离的阈值。我设置50
      找出每一行都有最大值的索引值(df2)。

      threshold = df3.max(1) > 50
      idxmax = df3.idxmax(1)
      

      分配任务

      df['PROD_ID'] = np.where(threshold, df2.loc[idxmax, 'PROD_ID'].values, np.nan)
      df['PROD_DESCRIPTION'] = np.where(threshold, df2.loc[idxmax, 'PROD_DESCRIPTION'].values, np.nan)
      df
      

      【讨论】:

      • 我已经在一小部分数据上使用了它,它看起来运行良好。我刚刚将它设置为在具有四个不同迭代的较大块上运行以测试各种模糊用法(即 fuzz.ratio、fuzz.partial_ratio 等),以便我可以看到哪个给出了最好的结果。感谢您对我论文繁重工作的帮助。
      • 补充一下 - fuzz.token_sort_ratio 产生了最准确的结果,匹配成功率约为 70%。
      • @gincard 有多少数据以及它有多快......大约
      • 我将其分为 30 个类别。一个 6300 x 4500 大约需要 15 分钟。 2000 x 2000 需要几秒钟。最大的(23000 x 10000)大约需要 4.5 小时。那个很乱,匹配不太明确。电脑配备 32GB DDR3 RAM 和超频 i5 处理器。
      • 这并不可怕。我害怕更糟
      【解决方案3】:

      我没有足够的声誉来评论 @piRSquared 的回答。因此有这个答案。

      • vi”和“vj”的定义没有通过错误 (AttributeError: 'DataFrame' object has no attribute 'get_value')。当我插入“下划线”时它起作用了。例如。 vi = df._get_value(i, 'PRODUCT_DESCRIPTION')
      • 'set_value' 仍然存在类似问题,并且同样的解决方案在那里也有效。例如。 df3._set_value(i, j, fuzz.ratio(vi, vj))
      • 生成 idxmax 会引发另一个错误 (TypeError: reduction operation 'argmax' not allowed for this dtype),这是因为 df3(模糊比率)的内容属于“对象”类型。在定义threshold 之前,我将它们全部转换为数字,它起作用了。例如。 df3 = df3.apply(pd.to_numeric)

      感谢 @piRSquared 的解决方案一百万。对于像我这样的 Python 新手来说,它就像一种魅力。我发布这个答案是为了方便像我这样的其他新手。

      【讨论】:

        猜你喜欢
        • 2018-12-25
        • 1970-01-01
        • 1970-01-01
        • 2021-05-12
        • 2023-03-25
        • 1970-01-01
        • 2021-08-02
        • 2018-03-30
        • 1970-01-01
        相关资源
        最近更新 更多