Разложение временных рядов Pandas на основе високосного года

У меня есть временной ряд pandas (называемый df), в котором есть один столбец (с именем data), который содержит данные с ежедневной частотой в течение 5 лет. Следующий код создает некоторые случайные данные:

import pandas as pd
import numpy as np


df_index = pd.date_range('01-01-2012', periods=5 * 365 + 2, freq='D')
df = pd.DataFrame({'data': np.random.rand(len(df_index))}, index=df_index)

Я хочу выполнить простую декомпозицию годового тренда, где для каждого дня я вычитаю его значение год назад. Кроме того, я хочу присутствовать при вычитании високосных лет. Есть ли какой-нибудь элегантный способ сделать это? Мой способ сделать это - выполнить различия с 365 и 366 днями и назначить их новым столбцам.

df['diff_365'] = df['data'].diff(365)
df['diff_366'] = df['data'].diff(366)

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

def decide(row):
    if (row.name - 59).is_leap_year:
        return row[1]
    else:
        return row[0]

df['yearly_diff'] = df[['diff_365', 'diff_366']].apply(decide, axis=1)

Объяснение: функция решить принимает в качестве аргумента строку из DataFrame, состоящую из столбцов diff_365 и diff_366 (вдоль с DatetimeIndex). Выражение row.name возвращает дату строки и, предполагая, что временной ряд имеет ежедневную частоту (freq = 'D'), вычитается 59 дней, что является количеством дней с 1 января по 28 февраля. В зависимости от того, является ли результирующая дата днем ​​високосного года, возвращается значение из столбца diff_366, в противном случае — значение из столбца diff_365.

Это заняло 8 строк, и кажется, что вычитание можно выполнить в одну или две строки. Я попытался применить аналогичную функцию непосредственно к столбцу data (через apply и взяв аргумент по умолчанию axis=0). Но в этом случае я не могу учитывать свой DatetimeIndex. Есть ли лучший способ выполнить вычитание?


person Alex G    schedule 28.05.2018    source источник


Ответы (1)


Возможно, вам не нужно беспокоиться о том, чтобы явно обращаться с високосными годами. При создании DatetimeIndex можно указать параметры start и end. Согласно документам:

Из четырех параметров start, end, periods и freq должны быть указаны ровно три.

Вот пример того, как вы можете реструктурировать свою логику:

df_index = pd.date_range(start='01-01-2012', end='12-31-2016', freq='D')

df = pd.DataFrame({'data': np.random.rand(len(df_index))}, index=df_index)

df['yearly_diff'] = df['data'] - (df_index - pd.DateOffset(years=1)).map(df['data'].get)

Пояснение

  • Мы создаем объект DatetimeIndex, предоставляя аргументы start, end и freq.
  • Вычтите 1 год из вашего индекса, вычитая pd.DateOffset(years=1).
  • Используйте pd.Series.map, чтобы сопоставить эти даты отставания на 1 год с data.
  • Вычтите полученный ряд из исходного ряда data.
person jpp    schedule 28.05.2018