Как при вычислении столбца получить предыдущее его значение в pandas?
Стоит задача: в столбце 'Плановый остаток' вычислить значения по следующей логике: Если Дата=='2024-01-01, то значение берется из столбца 'Остаток на начало расчета' (далее прибавляется плановый приход и вычитается продажи 'Продажи + сезонность + рост') Иначе берется значение в столбце 'Плановый остаток' предыдущего дня (например для вычисления на дату 2024-01-20 остаток возьмется из предыдущей строки - 2024-01-19) далее прибавляется плановый приход и вычитается продажи 'Продажи + сезонность + рост'.
Формула из excel(если кому будет понятнее):
# =ЕСЛИМН(
# Расчет!A76124=ДАТАЗНАЧ("01.01.2024"); # Если дата = 01.01.2024,
# ВПР( ВПРится остаток из таблицы базовых значений
# C76124; Суммируется с приходом за этот день
# 'Базовые значения'!A:G; и вычитается [Продажи + сезонность + рост]
# 7;
# 0
# )+M76124-K76124; # Если дата > 01.01.2024,
# A76124>ДАТАЗНАЧ("01.01.2024"); Остаток на день раньше суммируется с
# ЕСЛИ( приходим за этот день и вычитается
# L76123+M76124-K76124<0; [Продажи + сезонность + рост]
# 0; Если полученное выражение < 0
# L76123+M76124-K76124 то значение = 0, иначе полученное значение
# )
# )
Часть данных для примера:
df_calculation = pd.DataFrame({"Артикул":{"191808":"99156","191809":"99156","191810":"99156","191811":"99156","191812":"99156","191813":"99156","191814":"99156","191815":"99156","191816":"99156","191817":"99156"},"Наименование":{"191808":"name","191809":"name","191810":"name","191811":"name","191812":"name","191813":"name","191814":"name","191815":"name","191816":"name","191817":"name"},"Группа":{"191808":"Группа 1","191810":"Группа 1","191812":"Группа 1","191813":"Группа 1","191814":"Группа 1","191815":"Группа 1","191816":"Группа 1","191817":"Группа 1"},"Ид категории ВБ":{"191808":67,"191809":67,"191810":67,"191811":67,"191812":67,"191813":67,"191814":67,"191815":67,"191816":67,"191817":67},"Ц.З.WB Текущая":{"191808":3149,"191809":3149,"191810":3149,"191811":3149,"191812":3149,"191813":3149,"191814":3149,"191815":3149,"191816":3149,"191817":3149},"Средние продажи":{"191808":100,"191809":100,"191810":100,"191811":100,"191812":100,"191813":100,"191814":100,"191815":100,"191816":100,"191817":100},"Базовые продажи для расчета (Август-Сентябрь-Октябрь 2023)+ корректировки":{"191808":3000,"191809":3000,"191810":3000,"191811":3000,"191812":3000,"191813":3000,"191814":3000,"191815":3000,"191816":3000,"191817":3000},"Остаток на начало отсчета":{"191808":1000,"191809":1000,"191810":1000,"191811":1000,"191812":1000,"191813":1000,"191814":1000,"191815":1000,"191816":1000,"191817":1000},"Дата":{"191808":1704067200000,"191809":1704153600000,"191810":1704240000000,"191811":1704326400000,"191812":1704412800000,"191813":1704499200000,"191814":1704585600000,"191815":1704672000000,"191816":1704758400000,"191817":1704844800000},"Общая сезонность выручки":{"191808":0.7263,"191809":0.9784,"191810":0.8993,"191811":0.9551,"191812":1.0019,"191813":1.0221,"191814":1.0871,"191815":1.0625,"191816":1.0951,"191817":1.0093},"Общая сезонность продаж":{"191808":0.7276,"191809":0.9945,"191810":0.9304,"191811":0.9855,"191812":1.0271,"191813":0.9888,"191814":1.0273,"191815":1.1154,"191816":1.0645,"191817":1.0295},"К.роста":{"191808":0.0000022334,"191809":0.0000044669,"191810":0.0000067003,"191811":0.0000089338,"191812":0.0000111672,"191813":0.0000134006,"191814":0.0000156341,"191815":0.0000178675,"191816":0.000020101,"191817":0.0000223344},"Продажи + сезонность":{"191808":73.0,"191809":99.0,"191810":93.0,"191811":99.0,"191812":103.0,"191813":99.0,"191814":103.0,"191815":112.0,"191816":106.0,"191817":103.0},"Продажи + сезонность + рост":{"191808":73.0819627462,"191809":99.1639254925,"191810":93.2458882387,"191811":99.3278509849,"191812":103.4098137312,"191813":99.4917764774,"191814":103.5737392237,"191815":112.6557019699,"191816":106.7376647161,"191817":103.8196274624},"План прихода":{"191808":0.0,"191809":0.0,"191810":0.0,"191811":0.0,"191812":0.0,"191813":0.0,"191814":0.0,"191815":0.0,"191816":1908.0,"191817":0.0}})
Вычисления которые производились:
df_calculation['Продажи + сезонность'] = (df_calculation['Средние продажи'] * df_calculation['Общая сезонность продаж']).round(0)
df_calculation['Продажи + сезонность + рост'] = df_calculation['К.роста']*df_calculation.groupby('Артикул')['Продажи + сезонность'].transform('sum') + df_calculation['Продажи + сезонность']
df_calculation = df_calculation.set_index(['Артикул', 'Дата'])
condition = df_calculation.index.get_level_values('Дата') == '2024-01-01'
df_calculation['План остатков'] = df_calculation.loc[condition, 'Остаток на начало отсчета'] + df_calculation.loc[condition, 'План прихода'] - df_calculation.loc[condition, 'Продажи + сезонность + рост']
# Пробовал так
# df_calculation['План остатков'] = df_calculation['План остатков'].fillna(
# df_calculation.loc[~condition, 'План остатков'].shift(-1) + df_calculation.loc[~condition, 'План прихода'] - df_calculation.loc[~condition, 'Продажи + сезонность + рост'])
или так
# df_calculation['План остатков'] = df_calculation['План остатков'].fillna(df_calculation.loc[~condition, 'План остатков'].shift(-1) + df_calculation.loc[~condition, 'План прихода'] + df_calculation.loc[~condition, 'Продажи + сезонность + рост'])
К сожалению оба варианта не дали желаемого результата. Подскажите как можно решить? (хотелось бы обойтись без цикла)
P.S. Использовав предложенный вариант в целом поведение правильное, но когда остаток достигает <0, то расчет не правильный, в чем может быть причина? Фрейм данных:
df_calculate = pd.read_csv('https://raw.githubusercontent.com/Rett-oo/test/main/test.csv')
код который я поправил, мне нужны данные остатков только на начало года(насколько я понял от этого условия зависит откуда берется остаток)
df_calculation['План остатков'] = df_calculation[df_calculation["Дата"].dt.is_year_start].apply(lambda x: x['Остаток на начало отсчета'] + x['План прихода'] - x['Продажи + сезонность + рост'], axis=
df_calculation["План остатков"] = df_calculation.groupby(df_calculation["Дата"].dt.is_year_start.cumsum())["План остатков"].cumsum()
Ответы (1 шт):
совсем уж элегантно не получилось, но можно попробовать так
UPDATE
в связи с тем, что должна происходить ещё и группировка по артикулу, решение принимает следующий вид:
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/Rett-oo/test/main/test.csv', usecols=[0,7,8,11,12,13,14])
df = df.iloc[:25,:]
df["Дата"] = pd.to_datetime(df["Дата"])
df['План остатков'] = df[df["Дата"].dt.is_year_start].apply(lambda x: x['Остаток на начало отсчета'] + x['План прихода'] - x['Продажи + сезонность + рост'], axis=1)
df['План остатков'] = df.groupby("Артикул")['План остатков'].fillna(df['План прихода'] - df['Продажи + сезонность + рост'])
df['План остатков'] = df.groupby(df["Артикул"], as_index=False).apply(lambda x: x.groupby(x["Дата"].dt.is_year_start.cumsum())["План остатков"].cumsum(), include_groups=False).reset_index(drop=True)
df:
Артикул Остаток на начало отсчета Дата К.роста Продажи + сезонность Продажи + сезонность + рост План прихода План остатков
0 7010 500 2024-01-01 0.000002 38.0 38.047188 0.0 461.952812
1 99156 1000 2024-01-01 0.000002 73.0 73.081963 0.0 407.858436
2 99156 1000 2024-01-02 0.000004 99.0 99.163925 0.0 356.716871
3 7010 500 2024-01-02 0.000004 54.0 54.094376 0.0 302.528119
4 99156 1000 2024-01-03 0.000007 93.0 93.245888 0.0 248.292178
5 7010 500 2024-01-03 0.000007 51.0 51.141564 0.0 194.009050
6 7010 500 2024-01-04 0.000009 54.0 54.188752 0.0 138.678733
7 99156 1000 2024-01-04 0.000009 99.0 99.327851 0.0 88.301228
8 7010 500 2024-01-05 0.000011 54.0 54.235941 0.0 35.876535
9 99156 1000 2024-01-05 0.000011 103.0 103.409814 0.0 -22.595346
10 99156 1000 2024-01-06 0.000013 99.0 99.491776 0.0 -90.114415
11 7010 500 2024-01-06 0.000013 54.0 54.283129 0.0 -154.680672
12 7010 500 2024-01-07 0.000016 55.0 55.330317 0.0 926.918037
13 99156 1000 2024-01-07 0.000016 103.0 103.573739 0.0 827.754112
14 7010 500 2024-01-08 0.000018 50.0 50.377505 0.0 734.508224
15 99156 1000 2024-01-08 0.000018 112.0 112.655702 0.0 635.180373
16 7010 500 2024-01-09 0.000020 52.0 52.424693 0.0 531.770559
17 99156 1000 2024-01-09 0.000020 106.0 106.737665 0.0 432.278782
18 99156 1000 2024-01-10 0.000022 103.0 103.819627 0.0 328.705043
19 7010 500 2024-01-10 0.000022 58.0 58.471881 0.0 216.049341
20 7010 500 2024-01-11 0.000025 67.0 67.519069 0.0 109.311676
21 99156 1000 2024-01-11 0.000025 105.0 105.901590 0.0 5.492049
22 7010 500 2024-01-12 0.000027 64.0 64.566257 0.0 -100.409541
23 99156 1000 2024-01-12 0.000027 103.0 103.983553 0.0 -204.393094
24 99156 1000 2024-01-13 0.000029 97.0 98.065516 0.0 -302.458610