скользящее среднее панд по групповому расчету неверно

Моя датафрейм priceDF начинается так:

    Date        symbol  Close
0   2000-01-03  HELN.SW 28.28
1   2000-01-04  HELN.SW 27.50
2   2000-01-05  HELN.SW 26.71
3   2000-01-06  HELN.SW 27.16
4   2000-01-07  HELN.SW 27.50

Чтобы вычислить скользящее среднее закрытий, сгруппированных по символам, я сделал:

priceDF['avg'] = priceDF.groupby('symbol')'Close'].rolling(3).mean().reset_index(drop=True)

и я получаю:

    Date        symbol  Close   avg
0   2000-01-03  HELN.SW 28.28   NaN
1   2000-01-04  HELN.SW 27.50   NaN
2   2000-01-05  HELN.SW 26.71   12.537398
3   2000-01-06  HELN.SW 27.16   12.022164
4   2000-01-07  HELN.SW 27.50   11.922733

В строке 2 я хочу, чтобы avg = 27,50, среднее значение закрытия в строках от 0 до 2. Что я неправильно понял?


person Bartli    schedule 21.03.2021    source источник
comment
Я не могу воспроизвести вашу проблему, т.е. получаю правильные числа. В вашем коде есть небольшая синтаксическая ошибка, но предположим, что это проблема копирования и вставки, а не фактический код (поскольку он не будет работать так, как написано). Проверить версию вашей панды? посмотрите, что делает calc без присваивания (например, запустите только эту часть priceDF.groupby('symbol')['Close'].rolling(3).mean(), посмотрите, имеют ли числа смысл)   -  person piterbarg    schedule 21.03.2021


Ответы (1)


Я почти уверен, что это проблема того, как здесь используется reset_index, в сочетании с наличием нескольких групп. Рассмотрим немного расширенный пример:

from io import StringIO

data = StringIO(
'''
   Date        symbol  Close
0   2000-01-03  HELN.SW 28.28
1   2000-01-04  HELN.SW 27.50
2   2000-01-05  HELN.SW 26.71
3   2000-01-06  HELN.SW 27.16
4   2000-01-07  HELN.SW 27.50
5   2000-01-07  AAAA.SW 30.00
''')
df = pd.read_csv(data, sep = '\s+', index_col=0)

(мы добавили AAAA.SW в список)

Теперь это:

df.groupby('symbol')['Close'].rolling(3).mean()

производит разумные числа (поскольку для AAAA есть только одна дата, мы ожидаем NaN:


symbol    
AAAA.SW  5          NaN
HELN.SW  0          NaN
         1          NaN
         2    27.496667
         3    27.123333
         4    27.123333
Name: Close, dtype: float64

но это:

df.groupby('symbol')['Close'].rolling(3).mean().reset_index(drop=True)

дает неправильные индексы

0          NaN
1          NaN
2          NaN
3    27.496667
4    27.123333
5    27.123333
Name: Close, dtype: float64

и при помещении в исходный df оказываются в неправильных строках:

df['avg'] = df.groupby('symbol')['Close'].rolling(3).mean().reset_index(drop=True)
df

производит

     Date       symbol  Close   avg
0   2000-01-03  HELN.SW 28.28   NaN
1   2000-01-04  HELN.SW 27.50   NaN
2   2000-01-05  HELN.SW 26.71   NaN
3   2000-01-06  HELN.SW 27.16   27.496667
4   2000-01-07  HELN.SW 27.50   27.123333
5   2000-01-07  AAAA.SW 30.00   27.123333

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

df.groupby('symbol').apply(lambda g: g.assign(avg = g['Close'].rolling(3).mean())).reset_index(drop=True)

так что мы получаем


    Date        symbol  Close   avg
0   2000-01-07  AAAA.SW 30.00   NaN
1   2000-01-03  HELN.SW 28.28   NaN
2   2000-01-04  HELN.SW 27.50   NaN
3   2000-01-05  HELN.SW 26.71   27.496667
4   2000-01-06  HELN.SW 27.16   27.123333
5   2000-01-07  HELN.SW 27.50   27.123333
person piterbarg    schedule 21.03.2021
comment
Большое спасибо, piterbarg за подробный ответ и правильное решение. - person Bartli; 21.03.2021
comment
Большое спасибо, piterbarg за подробный ответ. Теперь я понимаю свою ошибку. Назначение priceDF [avg] = ... было плохой идеей, потому что groupby возвращает значения, отсортированные по символу. HELN.SW - первый символ из многих в исходном фрейме данных. Первый символ, возвращаемый groupby, - 0012.HK. Итак, я соединил скользящие средние 0012.HK и HELN.SW. После применения вашего кода результирующий фрейм данных начинается следующим образом: '' 'Символ даты Close avg 0 2000-01-04 0012.HK 13.450359 NaN 1 2000-01-05 0012.HK 12.474124 NaN 2 2000-01-06 0012.HK 11.687712 12.53 3 2000-01-07 0012.HK 11.904655 12.02 '' - person Bartli; 21.03.2021