Изменение Python Pandas ежемесячно по сравнению с прошлым годом, если текущий месяц является неполным

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

Об этом уже спрашивали: Повторная выборка и расчет по годам с частичными данными, но я не могу понять полученный ответ.

Мой код выглядит следующим образом:

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.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
68
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Код

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, вы также можете увидеть предыдущее значение.

Привет, Панда Ким, большое спасибо за ответ, это работает. Однако я изо всех сил пытаюсь обобщить ваше решение на фрейм данных с несколькими столбцами. Я обновил свой вопрос, спасибо за вашу помощь.

Giacomo 11.07.2024 16:45

@Джакомо, я обновляю свой ответ

Panda Kim 11.07.2024 17:29

Другие вопросы по теме