【问题标题】:Perform a merge based on a substring match?基于子字符串匹配执行合并?
【发布时间】:2018-11-05 09:01:08
【问题描述】:

虽然此问题与 Fuzzy Match Merge with Pandas 密切相关,但此问题专门关于合并 only(或在本例中为子集)当一个 DataFrame 中的键是完全匹配时,或另一个DataFrame 中的键的子字符串。为了说明我的观点,这里有 2 个DataFrames

df1
   id   code
0   1   E282
1   2  O0080
2   3    R52
3   4  J0100
4   5    F99

df2
    code  val
0   V282   11
1   O008   12
2  J0101   13
3    F99   14
4    R55   15

使用difflib 的问题在于我真的不想匹配最接近的字符串,而且我不确定我是否能够将V282 之类的匹配项分开到E282,这应该' t 发生并且像 O008O0080 这样的匹配应该合并。

预期的输出应该是

   code1  id
0  O0080   2
1    F99   5

我可以得到这个结果

import numpy as np
df1[np.logical_or.reduce([df1['code'].str.contains(code) for code in df2.code.tolist()])]

但由于 df1 的行长为 42M 行,而 df2 包含约 4000 个代码,因此这种方法速度慢得令人难以置信。这是我要做的最好的吗?这似乎很不幸,当内部合并一个 21M 行 df 和一个 7M 行 df 在精确键上需要

【问题讨论】:

  • df1 代码是否总是以 df2 代码开头 - 多余的字符总是在末尾?
  • 是的,多余的字符总是在末尾。
  • 哦,答案有用吗?花了多长时间?我很好奇。
  • @coldspeed 是的,它确实加快了速度。现在只需要 15% 的时间,这是可控的。

标签: python string performance pandas merge


【解决方案1】:

这是一个难题。也许考虑使用python方法? any 会在这里短路,所以你应该节省一些周期。另外,contains 不一定从头检查,所以使用startswith 应该更有效。

df1[
    any(
         i.startswith(j) for j in df2.codes.tolist()
    ) for i in df1.codes.tolist()
]

【讨论】:

  • 如果您遇到内存问题,请删除 .tolist 调用,但这会导致一些性能下降。
【解决方案2】:

怎么样:

import pandas as pd

df1 = pd.DataFrame({'id':[1,2,3,4,5], 'code':['E282', 'O0080', 'R52', 'J0100', 'F99']})
df2 = pd.DataFrame({'code':['V282','O008','J0101','F99','R55'], 'val':[11,12, 13, 14, 15]})

pat = "|".join(df2['code'])
df1.insert(0, 'part_code', df1['code'].str.extract("(" + pat + ')', expand=False))
pd.merge(df1, df2, how='inner', left_on='part_code', right_on='code')[['code_y', 'id']]

灵感来自https://stackoverflow.com/a/48744202/12256369

【讨论】:

    猜你喜欢
    • 2018-12-17
    • 2018-03-18
    • 2021-01-29
    • 2019-04-29
    • 2018-07-22
    • 2014-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多