我有两个pandas数据框架。这些行需要由两个值(X,Y)坐标匹配,它们不是精确匹配,但在一个公差范围内。我需要将df2中的'VAL'项添加到df1中的'VAL'项,其中(X,Y)匹配。
我试过使用merge_asof,但运气不好。我想如果我能得到merge_asof工作的方式,我期待我可以做加法和重新分配到df2,但到目前为止,我无法得到匹配的工作。
下面是我尝试过的代码示例。
d1 = [ ['wp1',0.0,0.0,10],['wp2',10.0,10.0,5],['wp3',7.0,7.0,5]]
d2 = [ ['wp4',0.1,0.1,5],['wp5',10.2,10.2,8]]
headers = ['Name','X','Y','VAL']
df1 = pd.DataFrame(d1,columns = headers)
df2 = pd.DataFrame(d2,columns = headers)
#attempt at solution just to find matching values
df3 = pd.merge_asof(df1.sort_values('VAL'), df2.sort_values('VAL'),on=['VAL'],by=['X','Y'],direction='nearest',tolerance=1)
#desired solution is to sum 'VAL' from df2 into df1
d1_final = [ ['wp1',0.0,0.0,10+5],['wp2',10.0,10.0,5+8]]
df1_final = pd.DataFrame(d1_final,columns = headers)
如前所述,您在X,Y
上的匹配要求在公差范围内。对于merge_asof()
,公差匹配发生在on=
参数上。(by=
参数提供在on=
容忍匹配之前发生的精确匹配——想想grouby
)。但是on=
只能在单个键上容忍匹配。所以你不能用on=['X','Y']
把你带到你想去的地方。merge_asof
不能在多个键上进行公差匹配。
快速思考。真希望我现在有更多的时间。只是X
上的公差匹配。dropna()
。然后对Y
值进行二次容差过滤。这些信息会成为合并的一部分。如果Y
小于公差-那么只需添加VAL
s作为最终答案。
df4 = pd.merge_asof(df1.sort_values(['X','Y']), df2.sort_values(['X','Y']), on='X', direction='nearest', tolerance=1)
df4
Name_x X Y_x VAL_x Name_y Y_y VAL_y
0 wp1 0.0 0.0 10 wp4 0.1 5.0
1 wp3 7.0 7.0 5 NaN NaN NaN
2 wp2 10.0 10.0 5 wp5 10.2 8.0
然后执行上面列出的过程:
df5 = df4.assign(VAL=np.where((df4['Y_x']-df4['Y_y']).abs()<1, df4['VAL_x']+df4['VAL_y'], np.nan) )
.rename(columns={'Name_x':'Name','Y_x':'Y'}).dropna()[['Name','X','Y','VAL']]
df5
Name X Y VAL
0 wp1 0.0 0.0 15.0
2 wp2 10.0 10.0 13.0
jch解决方案可以使用更新df1所需的name和val设置一个新的df。
如下
import pandas as pd
import numpy as np
d1 = [ ['wp1',0.0,0.0,10],['wp2',10.0,10.0,5],['wp3',7.0,7.0,5]]
d2 = [ ['wp4',0.1,0.1,5],['wp5',10.2,10.2,8]]
headers = ['Name','X','Y','VAL']
df1 = pd.DataFrame(d1,columns = headers)
df2 = pd.DataFrame(d2,columns = headers)
df4 = pd.merge_asof(df1.sort_values(['X','Y']), df2.sort_values(['X','Y']), on='X', direction='nearest', tolerance=1)
print(df4.head())
df5 = df4.assign(VAL=np.where((df4['Y_x']-df4['Y_y']).abs()<1, df4['VAL_x']+df4['VAL_y'], np.nan)).rename(columns={'Name_x':'Name','Y_x':'Y'}).dropna()[['Name','X','Y','VAL']]
print(df5.head())
print('df1')
print(df1.head())
现在我正在尝试(不成功)更新原始df1并保留原始值,那里没有匹配。
d = df5.set_index('Name')['VAL'].to_dict()
v = df5.filter(like='VAL')
df1[v.columns] = v.replace(d)
print(df1.head())
我现在知道这个映射方案不是一个好方法,下面的值不能正确对应原来的df。
Name X Y VAL
0 wp1 0.0 0.0 15.0
1 wp2 10.0 10.0 NaN
2 wp3 7.0 7.0 13.0
我希望df1像这样更新,但不是NaN为wp2,它应该只是显示df1中wp2的原始VAL。
df5 = df5.set_index(['Name'])
df1 = df1.set_index(['Name'])
df1.update(df5)
print('df1')
print(df1.head())
^工作很好,只要我可以使用'Name'作为索引。