我正在尝试使用带有通配符的多个列合并两个pandas数据帧。
考虑数据集,其中result是所需合并的结果:
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 :(得分:4)
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
此DataFrame为right
中的每一行显示left['ID']
中的哪些值与模式匹配。例如,在最后一行中,模式为2.
,与22
中的23
,21
和left['ID']
匹配。
如果我们stack
这个DataFrame,我们会看到一个系列列出了通配符的所有可能扩展:
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
也可以这样做。将两个结果连接在一起以获取DataFrame,其中列出了通配符的每个有效扩展:
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
现在可以通过left
和expanded
的左合并获得所需的结果:
result = pd.merge(left, expanded, how='left')
PS:我将right
改为index=list('ABCD')
而不是通常的[0,1,2,3]
left
,以便right
和let this : Bool? = nil
this != nil
上的索引值不会发生
与我们希望行匹配的方式一致。我这样做是为了防止开发错误地利用这个的解决方案
巧合。