Повторите в качении окна с помощью панд

Предположим, что у меня есть ежедневные данные ( не регулярные интервалы ), я хочу вычислить за каждый месяц отклонение стандартного отклонения (или произвольно нелинейную функцию) за последние 5 месяцев. Например, на май 2012 года я бы вычислил stddev с периода, начиная с января 2012 года по май 2012 года (5 месяцев). В июне 2012 года период начинается в феврале 2012 года и т. Д. Конечным результатом является временной ряд с месячными значениями.

Я не могу применить переходящее окно, потому что это будет сначала ежедневным, а во-вторых, мне нужно указать количество значений (скользящее окно не агрегируется по временным рамкам, некоторые сообщения рассматривают эту проблему, но они не имеют отношения к моей проблеме, поскольку все равно для каждого нового дня).

Я не могу применить повторную выборку , потому что тогда образец будет каждые 5 месяцев, e..g. У меня были бы только значения для мая 2012 года, октябрь 2012 года, март 2013 года … Наконец, поскольку функция не является линейной, я не могу ее восстановить сначала делая ежемесячный образец, а затем применяя на нем 5-секундное окно.

Поэтому мне понадобится какая-то функция передискретизации, примененная к качению, определяемому временным интервалом (не числом значений).

Как я могу сделать это в пандах? Один из подходов может состоять в том, чтобы объединить несколько (5 в этом примере) ремаркетированных (5 месяцев) временных рядов, каждый с одним месяцем смещения, а затем выровнять все эти серии в один … но я не знаю, как это реализовать.

Вот попытка – не супер чистая, но она может работать.

Манекен:

 df = pd.DataFrame(data={'a': 1.}, index=pd.date_range(start='2001-1-1', periods=1000)) 

Сначала определите функцию для уменьшения даты n числа месяцев. Это нужно очистить, но работает при n <= 12.

 from datetime import datetime def decrease_month(date, n): assert(n <= 12) new_month = date.month - n year_offset = 0 if new_month <= 0: year_offset = -1 new_month = 12 + new_month return datetime(date.year + year_offset, new_month, 1) 

Затем добавьте 5 новых столбцов для 5 периодов прокатки, которые будут пересекать каждая дата.

 for n in range(rolling_period): df['m_' + str(n)] = df.index.map(lambda x: decrease_month(x, n)) 

Затем – используйте функцию melt для преобразования данных от широких к длинным, поэтому каждый период прокатки будет иметь одну запись.

 df_m = pd.melt(df, id_vars='a') 

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

 In [222]: df_m.groupby('value').sum() Out[222]: a value 2000-09-01 31 2000-10-01 59 2000-11-01 90 2000-12-01 120 2001-01-01 151 2001-02-01 150 2001-03-01 153 2001-04-01 153 2001-05-01 153 2001-06-01 153 2001-07-01 153 ... 

У меня была аналогичная проблема, связанная с серией timedelta, где я хотел взять скользящую среднюю, а затем повторить. Вот пример, когда у меня есть 100 секунд данных. Я беру скользящую среднюю 10-секундные окна, а затем повторно сбрасываю каждые 5 секунд, беря первую запись в каждом контейнере для повторной выборки. Результатом должно быть предыдущее 10-секундное среднее значение с шагом 5 секунд. Вы могли бы сделать что-то подобное в формате месяца вместо секунд:

 df = pd.DataFrame(range(0,100), index=pd.TimedeltaIndex(range(0,100),'s')) df.rolling('10s').mean().resample('5s').first() 

Результат:

  0 00:00:00 0.0 00:00:05 2.5 00:00:10 5.5 00:00:15 10.5 00:00:20 15.5 00:00:25 20.5 00:00:30 25.5 00:00:35 30.5 00:00:40 35.5 00:00:45 40.5 00:00:50 45.5 00:00:55 50.5 00:01:00 55.5 00:01:05 60.5 00:01:10 65.5 00:01:15 70.5 00:01:20 75.5 00:01:25 80.5 00:01:30 85.5 00:01:35 90.5