Нахождение исторического сезонного среднего за данный месяц в месячном ряду во временном ряду данных - PullRequest
1 голос
/ 12 апреля 2020

У меня есть фрейм данных (фрагмент ниже) с индексом в формате YYYYMM и несколькими столбцами значений, включая один, называемый «месяц», в котором я извлек данные MM из столбца индекса.

      index             st             us       stu     px month
0    202001      2616757.0      3287969.0  0.795858  2.036    01
1    201912      3188693.0      3137911.0  1.016183  2.283    12
2    201911      3610052.0      2752828.0  1.311398  2.625    11
3    201910      3762043.0      2327289.0  1.616492  2.339    10
4    201909      3414939.0      2216155.0  1.540930  2.508    09

Что я хочу сделать, так это создать новый столбец с именем «stavg», который принимает среднее значение за 5 лет для столбца «st» за данный месяц. Например, поскольку верхняя строка относится к 202001, значение этой строки должно быть средним значением январских значений 2019, 2018, 2017, 2016 и 2015 годов. Возвращение во времени на каждый дополнительный год должно оттягивать скользящую среднюю назад. Кроме того, такой, что stavg для строки, скажем, 201205 должен показывать среднее значение майских значений за 2011, 2010, 2009, 2008 и 2007 годы.

      index             st             us       stu     px month   stavg   
0    202001      2616757.0      3287969.0  0.795858  2.036    01     xxx    
1    201912      3188693.0      3137911.0  1.016183  2.283    12     xxx
2    201911      3610052.0      2752828.0  1.311398  2.625    11     xxx
3    201910      3762043.0      2327289.0  1.616492  2.339    10     xxx
4    201909      3414939.0      2216155.0  1.540930  2.508    09     xxx

Я знаю, как генерировать новые столбцы данных, основанных на операциях над другими столбцами в той же строке (таких как деление 'st' на 'us' для получения 'stu' и извлечение цифр из индекса для получения 'month'), но это понятие создания столбца данных на основе предыдущие значения действительно ставят меня в тупик.

Любые подсказки о том, как подойти к этому, будут с благодарностью! Я знаю, что за первые пять лет данных я не смогу заполнить столбец 'stavg' чем-нибудь, что хорошо - я мог бы использовать NaN там.

Ответы [ 2 ]

1 голос
/ 12 апреля 2020

Попробуйте определить функцию и использовать apply метод

df['year'] = (df['index'].astype(int)/100).astype(int)

def get_stavg(df, year, month):
    # get year from index

    df_year_month = df.query('@year - 5 <= year < @year and month == @month')
    return df_year_month.st.mean()


df['stavg'] = df.apply(lambda x: get_stavg(df, x['year'], x['month']), axis=1)
0 голосов
/ 12 апреля 2020

Если вы ищете решение pandas only, вы можете сделать что-то вроде

Фиктивные данные

Здесь мы создаем фиктивные наборы данных с данными за 10 лет всего за два месяца (январь и февраль).

import pandas as pd


df1 = pd.DataFrame({"date":pd.date_range("2010-01-01", periods=10, freq="AS-JAN")})
df2 = pd.DataFrame({"date":pd.date_range("2010-01-01", periods=10, freq="AS-FEB")})
df1["n"] = df1.index*2
df2["n"] = df2.index*3
df = pd.concat([df1, df2]).sort_values("date").reset_index(drop=True)

df.head(10)
        date   n
0 2010-01-01   0
1 2010-02-01   0
2 2011-01-01   2
3 2011-02-01   3
4 2012-01-01   4
5 2012-02-01   6
6 2013-01-01   6
7 2013-02-01   9
8 2014-01-01   8
9 2014-02-01  12

Groupby + скользящее среднее

df["n_mean"] = df.groupby(df["date"].dt.month)["n"]\
                 .rolling(5).mean()\
                 .reset_index(0,drop=True)
         date   n  n_mean
0  2010-01-01   0     NaN
1  2010-02-01   0     NaN
2  2011-01-01   2     NaN
3  2011-02-01   3     NaN
4  2012-01-01   4     NaN
5  2012-02-01   6     NaN
6  2013-01-01   6     NaN
7  2013-02-01   9     NaN
8  2014-01-01   8     4.0
9  2014-02-01  12     6.0
10 2015-01-01  10     6.0
11 2015-02-01  15     9.0
12 2016-01-01  12     8.0
13 2016-02-01  18    12.0
14 2017-01-01  14    10.0
15 2017-02-01  21    15.0
16 2018-01-01  16    12.0
17 2018-02-01  24    18.0
18 2019-01-01  18    14.0
19 2019-02-01  27    21.0

По определению за первые 4 года результат равен NaN.

Обновление

Для вашего конкретного случая

import pandas as pd

index = [f"{y}01" for y in range(2010, 2020)] +\
        [f"{y}02" for y in range(2010, 2020)]

df = pd.DataFrame({"index":index})
df["st"] = df.index + 1
# dates/ index should be sorted
df = df.sort_values("index").reset_index(drop=True)

# extract month
df["month"] = df["index"].str[-2:]


df["st_mean"] = df.groupby("month")["st"]\
                  .rolling(5).mean()\
                  .reset_index(0,drop=True)


...