У меня есть временной ряд 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. Есть ли лучший способ выполнить вычитание?