Как рассчитать совокупное средневзвешенное значение с помощью pandas

#python #pandas #dataframe #weighted-average

Вопрос:

Я хотел бы спросить вас о том, как найти совокупное среднее значение определенного значения столбца в фрейме данных pandas. Во-первых, данные выглядят так:

твердый Дата рецензент Оценить
A 2021-01-01 a 5
A 2021-01-01 b 1
A 2021-01-01 c 2
A 2021-01-02 d 3
A 2021-01-02 e 4
A 2021-01-03 f 3
A 2021-01-04 g 5
B 2021-01-01 h 5
B 2021-01-01 i 2
B 2021-01-02 j 3
B 2021-01-02 k 4
B 2021-01-03 a 3
B 2021-01-04 b 5

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

твердый Дата рецензент Оценить cum_avg_rate
A 2021-01-01 a 5 2.667
A 2021-01-01 b 1 2.667
A 2021-01-01 c 2 2.667
A 2021-01-02 d 3 3
A 2021-01-02 e 4 3
A 2021-01-03 f 3 3
A 2021-01-04 g 5 3.286
B 2021-01-01 h 5 3.5
B 2021-01-01 i 2 3.5
B 2021-01-02 j 3 3.5
B 2021-01-02 k 4 3.5
B 2021-01-03 a 3 3.4
B 2021-01-04 b 5 3.667

Метод, который я пробовал до сих пор, заключается в создании нового фрейма данных, который вычисляет средний балл и количество отзывов, используя метод «groupby» с указанием фирмы и даты, и использует его для создания совокупного среднего значения за каждый день.
Код приведен ниже.

 firm_gp=avg_mean_rate.groupby(['firm','date'])['mean']
firm_gp_count=avg_mean_rate.groupby(['firm','date'])['count']
avg_mean_rate['new_avg_grade']=( (firm_gp * firm_gp_count).cumsum())/firm_gp_count.cumsum()
 

Однако проблема заключается в том, что в процессе расчета совокупного среднего значения за каждый день возникает следующая ошибка.

TypeError: unsupported operand type(s) for *: 'SeriesGroupBy' and 'method'

В качестве второго метода я попробовал следующий метод, используя numpy.

 def w_cum_avg(avg_mean_rate,mean,count):
    d=avg_mean_rate['mean']
    w= avg_mean_rate['count']
    return(d*w).cumsum() / w.cumsum()
avg_mean_rate.groupby(['firm','date']).apply(w_cum_avg,'mean','count')
 

Но это работает не так хорошо, как я ожидал.

Я был бы признателен, если бы вы научили меня, как добиваться результатов.

Заранее спасибо.

Комментарии:

1. Вместо avg_mean_rate.groupby(['firm','date'])['mean'] использования avg_mean_rate.groupby(['firm','date'])['rate'].mean() Вам нужно указать, какой столбец агрегировать, и необходимо вызвать метод агрегирования.

Ответ №1:

Мы могли бы вычислить ежедневную sum и count за firm с groupby aggregate затем groupby cumsum , чтобы получить ежедневную совокупную сумму за firm . Вычислите среднее значение путем деления и join возврата к кадру данных:

 g = (
    df.groupby(['firm', 'date'])['rate']
        .agg(['sum', 'count'])
        .groupby(level='firm').cumsum()
)

df = df.join(
    g['sum'].div(g['count']).rename('cum_avg_rate'),
    on=['firm', 'date']  # align index on columns
)
 

df :

    firm        date reviewer  rate  cum_avg_rate
0     A  2021-01-01        a     5      2.666667
1     A  2021-01-01        b     1      2.666667
2     A  2021-01-01        c     2      2.666667
3     A  2021-01-02        d     3      3.000000
4     A  2021-01-02        e     4      3.000000
5     A  2021-01-03        f     3      3.000000
6     A  2021-01-04        g     5      3.285714
7     B  2021-01-01        h     5      3.500000
8     B  2021-01-01        i     2      3.500000
9     B  2021-01-02        j     3      3.500000
10    B  2021-01-02        k     4      3.500000
11    B  2021-01-03        a     3      3.400000
12    B  2021-01-04        b     5      3.666667
 

Установка:

 import pandas as pd

df = pd.DataFrame({
    'firm': ['A', 'A', 'A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'B', 'B'],
    'date': ['2021-01-01', '2021-01-01', '2021-01-01', '2021-01-02',
             '2021-01-02', '2021-01-03', '2021-01-04', '2021-01-01',
             '2021-01-01', '2021-01-02', '2021-01-02', '2021-01-03',
             '2021-01-04'],
    'reviewer': ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'a',
                 'b'],
    'rate': [5, 1, 2, 3, 4, 3, 5, 5, 2, 3, 4, 3, 5]
})