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

kso*_*all 9 python merge dataframe pandas

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

# 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)
Run Code Online (Sandbox Code Playgroud)

piR*_*red 7

混淆合并的问题是两个数据框都有一个“b”列,但左右版本在不匹配的地方有 NaN。你要避免不必要的越来越多“B”列“B_X”,“b_y”merge摆在首位

  • 从 df1 中切出非共享列 'a','e'
  • merge(df2, 'left'),这将从正确的数据帧中选取“b”(因为它只存在于正确的 df 中)
  • 最后做df1.update(...),这将更新从 df2 中获取的列 'b' 中的 NaNdf1['b']

解决方案:

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
Run Code Online (Sandbox Code Playgroud)

注意: 因为我使用了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
Run Code Online (Sandbox Code Playgroud)

结果是

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
Run Code Online (Sandbox Code Playgroud)

正如预期的那样。


更远...

如果您想在可能涉及更多列时更明确

df1.update(df1.drop('b', 1).merge(df2, 'left', 'a'))
Run Code Online (Sandbox Code Playgroud)

更深入...

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

快的

df1.combine_first(df1[['a', 'e']].merge(df2, 'left'))
Run Code Online (Sandbox Code Playgroud)

显式

df1.combine_first(df1.drop('b', 1).merge(df2, 'left', 'a'))
Run Code Online (Sandbox Code Playgroud)

更深入!...

'left' merge可维持秩序,但不是指标。这是超保守的方法:

df3 = df1.drop('b', 1).merge(df2, 'left', on='a').set_index(df1.index)
df1.combine_first(df3)
Run Code Online (Sandbox Code Playgroud)


WeN*_*Ben 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
Run Code Online (Sandbox Code Playgroud)

既然您提到过,会有多列

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
Run Code Online (Sandbox Code Playgroud)

我们也可以通过fillnadf

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
Run Code Online (Sandbox Code Playgroud)

  • 在数据框df1上进行操作而没有任何原位突变...如果您想:df1.fillna({'b':df1.a.map(df2.set_index('a')。b)})) (2认同)