根据子字符串匹配执行合并?

时间:2018-05-25 23:40:06

标签: python string performance pandas merge

虽然这个问题与Fuzzy Match Merge with Pandas密切相关,但这个问题特别是当一个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之类的匹配分隔为{{1 }},这应该不会发生,并且应该合并E282O008之类的匹配。

预期输出应为

O0080

我可以用

来达到这个结果
   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()])] 长42M行而df1包含~4000个代码,因此此方法速度令人难以置信。这是我要做的最好的事情吗?这看起来很不幸,当内部合并一个21M行df和一个7M行df精确键时,< 1分钟。

2 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:1)

那:

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

的启发