我可以使用带有熊猫的正则表达式在两个数据帧之间执行左联接/合并吗?

时间:2020-06-22 18:58:15

标签: python pandas python-regex

我正在尝试使用Python中的正则表达式执行左合并,该正则表达式可以处理多对多关系。 示例:

    df1 = pd.DataFrame(['a','b','c','d'], columns = ['col1'])
    df1['regex'] = '.*' + df1['col1'] + '.*'

    col1    regex
  0 a   .*a.*
  1 b   .*b.*
  2 c   .*c.*
  3 d   .*d.*

    df2 = pd.DataFrame(['ab','a','cd'], columns = ['col2'])

    col2
  0 ab
  1 a
  2 cd

    # Merge on regex column to col2

    out = pd.DataFrame([['a','ab'],['a','a'],['b','ab'],['c','cd'], 
    ['d','cd']],columns = ['col1','col2'])


    col1    col2
  0 a   ab
  1 a   a
  2 b   ab
  3 c   cd
  4 d   cd

2 个答案:

答案 0 :(得分:1)

我将查看每个col1值,并在df2的col2中找到该模式匹配的所有值,并创建一个列表并将其放入称为“ matches”的列中。完成后,您可以将col1设置为索引,展开matchs列以使其每行变成一个,然后摆脱regex模式列。

import re
import pandas as pd

df1 = pd.DataFrame(['a','b','c','d'], columns = ['col1'])
df1['regex'] = '.*' + df1['col1'] + '.*'
df2 = pd.DataFrame(['ab','a','cd'], columns = ['col2'])


df1['matches'] = df1.apply(lambda r: [x for x in df2['col2'].values if re.findall(r['regex'], x)], axis=1)

df1.set_index('col1').explode('matches').reset_index().drop(columns=['regex'])



        col1    matches
    0   a       ab
    1   a       a
    2   b       ab
    3   c       cd
    4   d       cd

答案 1 :(得分:1)

您可以使用创建自定义函数来找到两个数据帧的所有匹配索引,然后提取这些索引并使用pd.concat

import re
def merge_regex(df1, df2):
    idx = [(i,j) for i,r in enumerate(df1.regex) for j,v in enumerate(df2.col2) if re.match(r,v)]
    df1_idx, df2_idx = zip(*idx)
    t = df1.iloc[list(df1_idx),0].reset_index(drop=True)
    t1 = df2.iloc[list(df2_idx),0].reset_index(drop=True)
    return pd.concat([t,t1],axis=1)

merge_regex(df1, df2)
  col1 col2
0    a   ab
1    a    a
2    b   ab
3    c   cd
4    d   cd

时间结果

# My solution
In [292]: %timeit merge_regex(df1,df2)
1.21 ms ± 22.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

#Chris's solution
In [293]: %%timeit
     ...: df1['matches'] = df1.apply(lambda r: [x for x in df2['col2'].values if re.findall(r['regex'], x)], axis=1)
     ...: 
     ...: df1.set_index('col1').explode('matches').reset_index().drop(columns=['regex'])
     ...:
     ...:
4.62 ms ± 25.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)