Панды объединяют кадры данных с общим столбцом, слева - справа - PullRequest
9 голосов
/ 01 июля 2019

Я пытаюсь объединить два кадра данных и заменить nan в левом df правым df, я могу сделать это с тремя строками кода, как показано ниже, но я хочу знать, есть ли лучший / более короткий путь?

# 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 ]

5 голосов
/ 01 июля 2019

Короткая версия

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

Также мы можем перейти к fillna с помощью df

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
4 голосов
/ 01 июля 2019

Проблема слияния заключается в том, что оба кадра данных имеют столбец 'b', но в левой и правой версиях имеются NaN в несоответствующих местах.Вы хотите избежать получения нежелательных множественных столбцов «b» «b_x», «b_y» из merge, во-первых, :

  • нарезать неиспользуемые столбцы «a», «e 'из df1
  • do merge(df2, 'left'), это выберет' b 'из правильного кадра данных (так как он существует только в правильном df)
  • наконец, выполните df1.update(...), это обновит NaN в столбце 'b', взятом из df2, с df1['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

Примечание: Поскольку я использовал 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 голосов
/ 01 июля 2019

Вы можете замаскировать данные.

исходные данные:

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
2 голосов
/ 01 июля 2019

Только если индексы выровнены (важное примечание), мы можем использовать 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 или комментарий ниже.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...