2017-08-01 24 views
1

我试图合并两个熊猫数据框,使用多列使用通配符。与通配符合并

考虑数据集,其中的结果是期望合并的结果:

left=pd.DataFrame({'Type':['ABC','ADEC','OOO','DOG','MOT'], 'ID':[22,44,23,21,55]}) 
right=pd.DataFrame({'Type':['ABC','ADE*','*','DOG'], 'ID':[22,'*','23','2*'], 'Value': [0,1,1,0]}) 
result=pd.DataFrame({'Type':['ABC','ADEC','OOO','DOG','MOT'], 'ID':[22,44,23,21,55],'Value': [0,1,1,0,'NaN']}) 

这给:

left 
    ID Type 
0 22 ABC 
1 44 ADEC 
2 23 OOO 
3 21 DOG 
4 55 MOT 

right 
    ID Type Value 
0 22 ABC  0 
1 * ADE*  1 
2 23  *  1 
3 2* DOG  0 

result 
    ID Type Value 
0 22 ABC  0 
1 44 ADEC  1 
2 23 OOO  1 
3 21 DOG  0 
4 55 MOT NaN 

我试图做到这一点使用:

pd.merge(left=left, right=right, left_on=['Type', 'ID'], right_on ['Type','ID'], how='left') 

但结束于:

pd.merge(left=left, right=right, left_on=['Type', 'ID'], right_on= ['Type','ID'], how='left') 
    ID Type Value 
0 22 ABC 0.0 
1 44 ADEC NaN 
2 23 OOO NaN 
3 21 DOG NaN 
4 55 MOT NaN 

任何帮助,非常感谢。谢谢!

+0

我不认为熊猫有合并,联合等使用通配符的功能...... –

回答

3
import pandas as pd 

left = pd.DataFrame(
    {'Type': ['ABC', 'ADEC', 'OOO', 'DOG', 'MOT'], 'ID': [22, 44, 23, 21, 55]}) 
right = pd.DataFrame({'Type': ['ABC', 'ADE*', '*', 'DOG'], 
         'ID': [22, '*', '23', '2*'], 'Value': [0, 1, 1, 0]}, 
        index=list('ABCD')) 
expected = pd.DataFrame({'Type': ['ABC', 'ADEC', 'OOO', 'DOG', 'MOT'], 'ID': [ 
         22, 44, 23, 21, 55], 'Value': [0, 1, 1, 0, 'NaN']}) 

data = {} 
for col in ['ID', 'Type']: 
    right[col] = right[col].astype(str).str.replace('*','.') 
    left[col] = left[col].astype(str) 
    data[col] = (right[col].apply(lambda pat: left.loc[left[col].str.match(pat), col]) 
       .stack().to_frame(col)) 
    data[col].index = data[col].index.droplevel(level=1) 

expanded = (data['ID'] 
      .join(data['Type']) 
      .join(right['Value'])) 

result = pd.merge(left, expanded, how='left') 


print(result) 

产生

ID Type Value 
0 22 ABC 0.0 
1 44 ADEC 1.0 
2 23 OOO 1.0 
3 21 DOG 0.0 
4 55 MOT NaN 

如果更改*.,你可以把在right的值作为正则表达式模式。 然后,您可以使用str.match(pat)来测试right中的模式是否与left中的字符串匹配。例如,

In [297]: right 
Out[297]: 
    ID Type Value 
A 22 ABC  0 
B . ADE.  1 
C 23  .  1 
D 2. DOG  0 

In [298]: left 
Out[298]: 
    ID Type 
0 22 ABC 
1 44 ADEC 
2 23 OOO 
3 21 DOG 
4 55 MOT 

In [271]: right['ID'].apply(lambda pat: left.loc[left['ID'].str.match(pat), 'ID']) 
Out[271]: 
    0 1 2 3 4 
A 22 NaN NaN NaN NaN 
B 22 44 23 21 55 
C NaN NaN 23 NaN NaN 
D 22 NaN 23 21 NaN 

此数据框显示的right每一行什么left['ID']值相匹配的模式。例如,在最后一行中,模式为2.,其与left['ID']中的22,2321相匹配。

如果我们stack这个数据帧,我们得到了一个系列上市通配符的所有可能的扩展:

In [299]: right['ID'].apply(lambda pat: left.loc[left['ID'].str.match(pat), 'ID']).stack() 
Out[299]: 
A 0 22 
B 0 22 
    1 44 
    2 23 
    3 21 
    4 55 
C 2 23 
D 0 22 
    2 23 
    3 21 
dtype: object 

同样可以为Type来完成。将两个结果结合在一起,以获得一个数据帧,它列出了通配符的每一个有效的扩展:

In [301]: expanded = (data['ID'] 
         .join(data['Type']) 
         .join(right['Value'])) 
Out[301]: 
    ID Type Value 
A 22 ABC  0 
B 22 ADEC  1 
B 44 ADEC  1 
B 23 ADEC  1 
B 21 ADEC  1 
B 55 ADEC  1 
C 23 ABC  1 
C 23 ADEC  1 
C 23 OOO  1 
C 23 DOG  1 
C 23 MOT  1 
D 22 DOG  0 
D 23 DOG  0 
D 21 DOG  0 

现在所希望的结果可以通过leftexpanded左合并来获得:

result = pd.merge(left, expanded, how='left') 

PS:我改变rightindex=list('ABCD')而不是通常的 [0,1,2,3],以便对left和索引值不会发生在 与我们希望行匹配的方式一致。我这样做是为了防范开发一种错误地利用这种巧合的解决方案。