pandas groupby объединяет настраиваемую функцию с несколькими столбцами - PullRequest
0 голосов
/ 14 января 2019

Я пытаюсь использовать настраиваемую функцию с groupby в пандах. Я считаю, что использование apply позволяет мне сделать это следующим образом:

(Пример, который вычисляет новое среднее значение из двух групп)

import pandas as pd

def newAvg(x):
    x['cm'] = x['count']*x['mean']
    sCount = x['count'].sum()
    sMean = x['cm'].sum()
    return sMean/sCount

data = [['A', 4, 2.5], ['A', 3, 6], ['B', 4, 9.5], ['B', 3, 13]]
df = pd.DataFrame(data, columns=['pool', 'count', 'mean'])

df_gb = df.groupby(['pool']).apply(newAvg)

Возможно ли интегрировать это в функцию agg? Вдоль этих строк:

df.groupby(['pool']).agg({'count': sum, ['count', 'mean']: apply(newAvg)})

Ответы [ 5 ]

0 голосов
/ 14 января 2019

Если вы рассчитываете средневзвешенное значение, вы можете легко это сделать, используя функции agg и NumPy np.average. Просто прочитайте Серию для столбца «среднее»:

df_gb = df.groupby(['pool']).agg(lambda x: np.average(x['mean'], weights=x['count']))['mean']

Вы также можете сделать это, используя функцию newAvg, хотя это приведет к предупреждению:

df_gb2 = df.groupby(['pool']).agg(newAvg)['mean']

Если вы хотите использовать функцию newAvg, вы можете переопределить ее, чтобы избежать работы с копиями:

def newAvg(x):
    cm = x['count']*x['mean']
    sCount = x['count'].sum()
    sMean = cm.sum()
    return sMean/sCount

С этой модификацией вы получите ожидаемый результат:

df_gb2 = df.groupby(['pool']).agg(newAvg)['mean']
print(df_gb2)

# pool
# A     4.0
# B    11.0
# Name: mean, dtype: float64
0 голосов
/ 14 января 2019

Используйте assign с eval:

df.assign(cm=df['count']*df['mean'])\
  .groupby('pool', as_index=False)['cm','count'].sum()\
  .eval('AggCol = cm / count')

Выход:

  pool    cm  count  AggCol
0    A  28.0      7     4.0
1    B  77.0      7    11.0
0 голосов
/ 14 января 2019

Словарь с agg используется для выполнения отдельных расчетов для каждой серии. Для вашей проблемы предлагаю pd.concat:

g = df.groupby('pool')
res = pd.concat([g['count'].sum(), g.apply(newAvg).rename('newAvg')], axis=1)

print(res)

#       count  newAvg
# pool               
# A         7     4.0
# B         7    11.0

Это не самое эффективное решение, так как ваша функция newAvg выполняет вычисления, которые могут быть первоначально выполнены для всего кадра данных, но поддерживают произвольные предопределенные вычисления.

0 голосов
/ 14 января 2019

IIUC

df.groupby(['pool']).apply(lambda x : pd.Series({'count':sum(x['count']),'newavg':newAvg(x)}))
Out[58]: 
      count  newavg
pool               
A       7.0     4.0
B       7.0    11.0
0 голосов
/ 14 января 2019

Функция agg, работающая с каждым столбцом отдельно, поэтому возможным решением является создание столбца cm сначала с assign, а затем агрегирование sum, последнее деление каждого столбца :

df_gb = df.assign(cm=df['count']*df['mean']).groupby('pool')['cm','count'].sum()
print (df_gb)
        cm  count
pool             
A     28.0      7
B     77.0      7

out = df_gb.pop('cm') / df_gb.pop('count')
print (out)
pool
A     4.0
B    11.0
dtype: float64
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...