Объединить DataFrames в Pandas, используя среднее значение

У меня есть набор DataFrames с числовыми значениями и частично перекрывающимися индексами. Я хотел бы объединить их, принять среднее значение, если индекс имеет место в более чем одном DataFrame.

import pandas as pd
import numpy as np

df1 = pd.DataFrame([1,2,3], columns=['col'], index=['a','b','c'])
df2 = pd.DataFrame([4,5,6], columns=['col'], index=['b','c','d'])

Это дает мне два DataFrames:

   col            col
a    1        b     4
b    2        c     5
c    3        d     6

Теперь я хотел бы объединить DataFrames и принять среднее значение для каждого индекса (если это применимо, т.е. если оно встречается более одного раза).

Должно выглядеть так:

    col
a     1
b     3
c     4
d     6

Могу ли я сделать это с помощью некоторого расширенного слияния/присоединения?

Ответ 1

что-то вроде этого:

df3 = pd.concat((df1, df2))
df3.groupby(df3.index).mean()

#    col
# a    1
# b    3
# c    4
# d    6

или наоборот, как в ответе @unutbu:

pd.concat((df1, df2), axis=1).mean(axis=1)

Ответ 2

In [22]: pd.merge(df1, df2, left_index=True, right_index=True, how='outer').mean(axis=1)
Out[23]: 
a    1
b    3
c    4
d    6
dtype: float64

Что касается римского вопроса, я нахожу IPython %timeit команду удобного способа сравнения кода:

In [28]: %timeit df3 = pd.concat((df1, df2)); df3.groupby(df3.index).mean()
1000 loops, best of 3: 617 µs per loop

In [29]: %timeit pd.merge(df1, df2, left_index=True, right_index=True, how='outer').mean(axis=1)
1000 loops, best of 3: 577 µs per loop

In [39]: %timeit pd.concat((df1, df2), axis=1).mean(axis=1)
1000 loops, best of 3: 524 µs per loop

В этом случае pd.concat(...).mean(...) оказывается немного быстрее. Но на самом деле мы должны тестировать более крупные данные, чтобы получить более значимый ориентир.

Кстати, если вы не хотите устанавливать IPython, эквивалентные тесты можно запустить с помощью Python timeit module. Это требует немного больше настроек. В docs есть несколько примеров, показывающих, как это сделать.


Обратите внимание, что если df1 или df2 должны иметь повторяющиеся записи в своем индексе, например:

N = 1000
df1 = pd.DataFrame([1,2,3]*N, columns=['col'], index=['a','b','c']*N)
df2 = pd.DataFrame([4,5,6]*N, columns=['col'], index=['b','c','d']*N)

то эти три ответа дают разные результаты:

In [56]: df3 = pd.concat((df1, df2)); df3.groupby(df3.index).mean()
Out[56]: 
   col
a    1
b    3
c    4
d    6

pd.merge, вероятно, не дает желаемого ответа:

In [58]: len(pd.merge(df1, df2, left_index=True, right_index=True, how='outer').mean(axis=1))
Out[58]: 2002000

Пока pd.concat((df1, df2), axis=1) вызывает значение ValueError:

In [48]: pd.concat((df1, df2), axis=1)
ValueError: cannot reindex from a duplicate axis