Я хочу рассчитать процентное изменение по сравнению с прошлым годом для данных на уровне месяца, принимая во внимание, что последний (текущий) период является неполным.
Об этом уже спрашивали: Повторная выборка и расчет по годам с частичными данными, но я не могу понять полученный ответ.
Мой код выглядит следующим образом:
import pandas as pd
import numpy as np
np.random.seed(555)
# Create a sample dataframe
df_input = pd.DataFrame({
'order_date': pd.date_range(start='2022-01-01', end='2024-07-10'),
'customers': np.random.randint(0, 100, size=(922, )),
'orders': np.random.randint(0, 100, size=(922, ))
})
df = df_input.copy()
df.set_index('order_date',inplace=True)
df_monthly = df.resample('ME').sum()
print(df_monthly.tail())
customers orders
order_date
202403 1358 1513
202404 1581 1419
202405 1584 1565
202406 1456 1652
202407 389 378
Теперь я рассчитываю процентное изменение за каждый месяц и добавляю его обратно в исходный набор данных:
yoy_change = df_monthly.pct_change(12).mul(100)
for column in df_monthly.columns:
df_monthly[f'{column}_pct_change'] = yoy_change[column]
customers orders customers_pct_change orders_pct_change
order_date
202403 1358 1513 -6.215470 -13.095922
202404 1581 1419 -1.801242 -11.423221
202405 1584 1565 22.885958 3.232190
202406 1456 1652 7.772021 -6.508206
202407 389 378 -78.460687 -76.330620
Однако повторная выборка pandas суммирует неполный месяц с июля 2024 года (до 10-го числа) и сравнивает его с полным месяцем июля 2023 года прошлого года, когда рассчитывается процентное изменение. Это оставляет его очень отрицательным числом, хотя это не так (поскольку мы сравниваем полный месяц с неполным).
Например, количество клиентов за июль 2023 года «до 10-го числа» составило 513, следовательно, годовой % за июль 2024 года должен быть -24, а не -78.
Код
tmp = df.set_index('order_date')
tmp1 = pd.concat([
tmp,
tmp.set_axis(tmp.index + pd.DateOffset(years=1))
.resample('D').sum() # to avoid 02-28 & 02-29 duplicate
.rename({'customers': 'prev'}, axis=1)
], axis=1, join='inner'
).resample('MS').sum()
out = tmp1.assign(
pct_change=tmp1.pct_change(-1, axis=1)['customers'].mul(100)
)
out.хвост():
customers prev pct_change
order_date
2024-03-01 1358 1448 -6.215470
2024-04-01 1581 1610 -1.801242
2024-05-01 1584 1289 22.885958
2024-06-01 1456 1351 7.772021
2024-07-01 389 513 -24.171540
используйте DateOffset
по-хорошему.
Обновлен ответ на дополнительный вопрос
tmp = df.set_index('order_date')
tmp1 = pd.concat([
tmp,
tmp.set_axis(tmp.index + pd.DateOffset(years=1))
.resample('D').sum() # to avoid 02-28 & 02-29 duplicate
.add_prefix('prev_')
], axis=1, join='inner'
).resample('MS').sum()
out = pd.concat([
tmp1,
tmp1.pct_change(-tmp.shape[1], axis=1)
.dropna(axis=1, how='all')
.mul(100)
.add_suffix('_pct_change')
], axis=1
).filter(regex='^(?!prev_)')
out.хвост():
customers orders customers_pct_change orders_pct_change
order_date
2024-03-01 1358 1513 -6.215470 -13.095922
2024-04-01 1581 1419 -1.801242 -11.423221
2024-05-01 1584 1565 22.885958 3.232190
2024-06-01 1456 1652 7.772021 -6.508206
2024-07-01 389 378 -24.171540 -29.870130
Если вы не используете функцию filter
в последней строке out
, вы также можете увидеть предыдущее значение.
@Джакомо, я обновляю свой ответ
Привет, Панда Ким, большое спасибо за ответ, это работает. Однако я изо всех сил пытаюсь обобщить ваше решение на фрейм данных с несколькими столбцами. Я обновил свой вопрос, спасибо за вашу помощь.