2017-08-01 40 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和索引值不會發生在 與我們希望行匹配的方式一致。我這樣做是爲了防範開發一種錯誤地利用這種巧合的解決方案。