熊猫将数据框与共享列合并,fillna在左与右

时间:2019-07-01 20:36:24

标签: python pandas dataframe merge

我正在尝试合并两个数据帧,并用右df替换左df中的nan,我可以用以下三行代码来做到这一点,但是我想知道是否有更好/更短的方法? / p>

# Example data (my actual df is ~500k rows x 11 cols)
df1 = pd.DataFrame({'a': [1,2,3,4], 'b': [0,1,np.nan, 1], 'e': ['a', 1, 2,'b']})
df2 = pd.DataFrame({'a': [1,2,3,4], 'b': [np.nan, 1, 0, 1]})

# Merge the dataframes...
df = df1.merge(df2, on='a', how='left')

# Fillna in 'b' column of left df with right df...
df['b'] = df['b_x'].fillna(df['b_y'])

# Drop the columns no longer needed
df = df.drop(['b_x', 'b_y'], axis=1)

4 个答案:

答案 0 :(得分:5)

简短版本

df1.b.fillna(df1.a.map(df2.set_index('a').b),inplace=True)
df1
Out[173]: 
   a    b  e
0  1  0.0  a
1  2  1.0  1
2  3  0.0  2
3  4  1.0  b

自从您提到过,将会有多列

df = df1.combine_first(df1[['a']].merge(df2, on='a', how='left'))
df
Out[184]: 
   a    b  e
0  1  0.0  a
1  2  1.0  1
2  3  0.0  2
3  4  1.0  b

我们也可以使用df传递到fillna

df1.fillna(df1[['a']].merge(df2, on='a', how='left'))
Out[185]: 
   a    b  e
0  1  0.0  a
1  2  1.0  1
2  3  0.0  2
3  4  1.0  b

答案 1 :(得分:4)

令人困惑的合并问题是,两个数据帧都有一个'b'列,但是左右版本的NaN在不匹配的位置。您想避免一开始就从merge中获取不必要的多个“ b”列“ b_x”,“ b_y”

  • 从df1切片非共享列'a','e'
  • 执行merge(df2, 'left'),这将从正确的数据帧中拾取“ b”(因为它仅存在于正确的df中)
  • 最终执行df1.update(...),这将用df1['b']来更新df2的'b'列中的NaN。

解决方案:

df1.update(df1[['a', 'e']].merge(df2, 'left'))

df1

   a    b  e
0  1  0.0  a
1  2  1.0  1
2  3  0.0  2
3  4  1.0  b

注意:由于我使用了merge(..., how='left'),因此保留了调用数据帧的行顺序。如果我的df1的值a不正确

   a    b  e
0  1  0.0  a
1  2  1.0  1
2  4  1.0  b
3  3  NaN  2

结果将是

df1.update(df1[['a', 'e']].merge(df2, 'left'))

df1

   a    b  e
0  1  0.0  a
1  2  1.0  1
2  4  1.0  b
3  3  0.0  2

符合预期。


进一步...

如果您希望在涉及更多列时更加明确

df1.update(df1.drop('b', 1).merge(df2, 'left', 'a'))

甚至更...

如果您不想update数据框,我们可以使用combine_first

快速

df1.combine_first(df1[['a', 'e']].merge(df2, 'left'))

明确

df1.combine_first(df1.drop('b', 1).merge(df2, 'left', 'a'))

甚至还有!...

'left' merge可以保留顺序,但保留索引。这是极端保守的方法:

df3 = df1.drop('b', 1).merge(df2, 'left', on='a').set_index(df1.index)
df1.combine_first(df3)

答案 2 :(得分:2)

只有索引被指定(重要说明),我们才能使用update

df1['b'].update(df2['b'])


   a    b  e
0  1  0.0  a
1  2  1.0  1
2  3  0.0  2
3  4  1.0  b

或者只是fillna

df1['b'].fillna(df2['b'], inplace=True)

如果您未指定索引,请参见下面的WenNYoBen's答案或comment

答案 3 :(得分:2)

您可以屏蔽数据。

原始数据:

print(df)
   one  two  three
0    1  1.0    1.0
1    2  NaN    2.0
2    3  3.0    NaN

print(df2)
   one  two  three
0    4    4      4
1    4    2      4
2    4    4      3

请参见下文,根据情况填充遮罩。

# mask values where isna()
df1[['two','three']] = df1[['two','three']]\
        .mask(df1[['two','three']].isna(),df2[['two','three']])

输出:

   one  two  three
0    1  1.0    1.0
1    2  2.0    2.0
2    3  3.0    3.0