我已经审查了pandas documentation on merge,但对于在“左”合并中有效地覆盖值存在疑问。我可以仅对一对值(如here所示)执行此操作,但是在尝试执行多个对时,会变得很混乱。
如果我采用以下数据框:
a = pd.DataFrame({
'id': [0,1,2,3,4,5,6,7,8,9],
'val': [100,100,100,100,100,100,100,100,100,100]
})
b = pd.DataFrame({
'id':[0,2,7],
'val': [500, 500, 500]
})
我可以合并它们:
df = a.merge(b, on=['id'], how='left', suffixes=('','_y'))
获得
id val val_y
0 0 100 500.0
1 1 100 NaN
2 2 100 500.0
3 3 100 NaN
4 4 100 NaN
5 5 100 NaN
6 6 100 NaN
7 7 100 500.0
8 8 100 NaN
9 9 100 NaN
我想保留不存在右值的左值,但在可能的情况下用右值覆盖。
我的期望结果是:
id val
0 0 500.0
1 1 100.0
2 2 500.0
3 3 100.0
4 4 100.0
5 5 100.0
6 6 100.0
7 7 500.0
8 8 100.0
9 9 100.0
我知道我可以用几行代码来做到这一点:
df.loc[df.val_y.notnull(), 'val'] = df[df.val_y.notnull()].val_y
df = df.drop(['val_y'], axis = 1)
或者我可以使用logic from this question。
但是当有多个列配对要应用此逻辑时,这变得很混乱。
例如,使用下面的a
和b
:
a = pd.DataFrame({
'id': [0,1,2,3,4,5,6,7,8,9],
'val': [100,100,100,100,100,100,100,100,100,100],
'val_2':[200, 200, 200, 200, 200, 200, 200, 200, 200, 200]
})
b = pd.DataFrame({
'id':[0,2,7],
'val': [500, 500, 500],
'val_2': [500,500,500]
})
是否有更快,更清洁的方法来获得所需的结果?
答案 0 :(得分:5)
我将使用set_index
和update
进行此操作:
u = a.set_index('id')
u.update(b.set_index('id')) # Update a's values with b's values
u.reset_index()
id val
0 0 500.0
1 1 100.0
2 2 500.0
3 3 100.0
4 4 100.0
5 5 100.0
6 6 100.0
7 7 500.0
8 8 100.0
9 9 100.0
更新在索引上对齐。因此,在执行更新步骤之前,我将“ id”设置为两个DataFrame中的索引。
请注意,“ id”列必须是唯一的。
另一个选择是使用concat
和drop_duplicates
:
pd.concat([b, a]).drop_duplicates('id').sort_values('id')
id val
0 0 500
1 1 100
1 2 500
3 3 100
4 4 100
5 5 100
6 6 100
2 7 500
8 8 100
9 9 100
由于b
会覆盖a
,因此b
必须在concat
步骤中排在第一位。
答案 1 :(得分:3)
numpy
searchsorted
并分配
a.iloc[np.searchsorted(a.id,b.id),1]=b.val.values
a
Out[1382]:
id val
0 0 500
1 1 100
2 2 500
3 3 100
4 4 100
5 5 100
6 6 100
7 7 500
8 8 100
9 9 100
答案 2 :(得分:2)
dict
乱搞d = dict(a.values)
d.update(dict(b.values))
pd.DataFrame(dict(zip(a, zip(*d.items()))))
id val
0 0 500
1 1 100
2 2 500
3 3 100
4 4 100
5 5 100
6 6 100
7 7 500
8 8 100
9 9 100
答案 3 :(得分:0)
另一种选择是在进行合并的同时进行合并,然后在右侧填充NaN
值
df
id val val_y
0 0 100 500.0
1 1 100 NaN
2 2 100 500.0
3 3 100 NaN
4 4 100 NaN
5 5 100 NaN
6 6 100 NaN
7 7 100 500.0
8 8 100 NaN
9 9 100 NaN
df.fillna(method='ffill', axis=1)
id val val_y
0 0.0 100.0 500.0
1 1.0 100.0 100.0
2 2.0 100.0 500.0
3 3.0 100.0 100.0
4 4.0 100.0 100.0
5 5.0 100.0 100.0
6 6.0 100.0 100.0
7 7.0 100.0 500.0
8 8.0 100.0 100.0
9 9.0 100.0 100.0
然后仅用iloc[:,-1]
切最后一列