Почему Панды не добавляют здесь два столбца одновременно?
В настоящее время я работаю над симулятором "пополнения запасов", который начинается с позиции на складе, отличной от фактической, получает ежедневные данные о фактических продажах и выполняет 3 задачи:
- обновить позиции на складе для всех магазинов во всех магазинах после сегодняшних продаж
- проверить, достигла ли текущая позиция на складе "точки пополнения" (85% от полной позиции на складе)
- рассчитать запас для всех магазинов во всех магазинах после
LEAD_TIME
(у каждого магазина свойLEAD_TIME
)
Сначала я изложу все концепции, которые вы, ребята, должны знать:
GRID
- Можно описать как "цель акций" максимальную позицию по акциям. В первый день работы складская позиция равнаGRID
и пополнение запасов всегда будет пытаться вернуть позицию на складеGRID
В целях упрощения мы будем использовать фиксированную GRID, но в действительности эта GRID должна быть динамичной и пересчитываться после каждого пополнения запаса.
SIM_SALES = SALES
SIM_STOCK(day n) = SIM_STOCK(day n-1) - SALES(day n) + RESTOCK(day n)
- Если
SIM_STOCK - SALES <= 0
,SALES
дня также будет приниматься равным нулю.
Структура DataFrame
идет примерно так (пример с ОДИН ITEM
- ОДИН STORE
) и содержит фактические значения:
INDEX ITEM STORE STOCK(UN) SALES(UN) DAY LEAD_TIME GRID
0 4058855 1000 173 0 1 5 55
1 4058855 1000 172 1 2 5 55
2 4058855 1000 163 9 3 5 55
3 4058855 1000 149 14 4 5 55
Аналогично, наша имитированная сетка будет выглядеть так:
INDEX ITEM STORE STOCK(UN) SALES(UN) DAY LEAD_TIME GRID KEY RESTOCK COUNTER
0 4058855 1000 55 0 1 5 55 False 0 0
1 4058855 1000 0 0 2 5 55 False 0 0
2 4058855 1000 0 0 3 5 55 False 0 0
3 4058855 1000 0 0 4 5 55 False 0 0
Я ищу вот что:
INDEX ITEM STORE SIM_STOCK(UN) SIM_SALES(UN) DAY LEAD_TIME GRID KEY RESTOCK COUNTER
0 4058855 1000 55 0 1 5 55 False 0 0
1 4058855 1000 54 1 2 5 55 False 0 0
2 4058855 1000 45 9 3 5 55 True 0 5
3 4058855 1000 31 14 4 5 55 True 0 4
4 4058855 1000 24 7 5 5 55 True 0 3
5 4058855 1000 15 9 6 5 55 True 0 2
6 4058855 1000 19 6 7 5 55 True 10 1
7 4058855 1000 11 8 8 5 55 True 0 5
8 4058855 1000 3 8 9 5 55 True 0 4
Я пришел к решению в 3 этапа:
- Сохраняйте все значения (Stock, Sales, Key и Counter) в словарях.
- Обновить все значения после текущих продаж
- Пересчитать все значения словарей
Так как код очень обширный и сложный, я опубликовал всю записную книжку, где (там есть CSV-файл)
Но важной частью является то, что это фактическое DataFrame
что я получаю:
INDEX ITEM STORE SIM_STOCK(UN) SIM_SALES(UN) DAY LEAD_TIME GRID KEY RESTOCK COUNTER
0 4058855 1000 55 0 1 5 55 False 0 0
1 4058855 1000 54 1 2 5 55 False 0 0
2 4058855 1000 45 9 3 5 55 True 0 5
3 4058855 1000 31 14 4 5 55 True 0 4
4 4058855 1000 24 7 5 5 55 True 0 3
5 4058855 1000 15 9 6 5 55 True 0 2
6 4058855 1000 9 6 7 5 55 True 10 1
7 4058855 1000 1 8 8 5 55 True 0 5
8 4058855 1000 1 0 9 5 55 True 0 4
Код делает все, кроме как, чтобы добавить RESTOCK
, Вот часть кода, где я добавляю RESTOCK
и вычесть SALES
:
DF['SIM_STOCK'] = DF.apply(lambda row:(dict_est[(row['ITEM'],row['STORE'],row['DAY']-1)]
-row['SIM_SALES']
+row['RESTOCK'])
if row['DAY'] == CURRENT_DAY
else row['SIM_STOCK'],
axis=1)
Почему Pandas вычитает, но не добавляет, если обе операции происходят в одной строке кода?
2 ответа
Я не уверен, почему ваш код не работает, но есть гораздо лучший, векторизованный способ выполнения вычислений, которые вы хотите выполнить. Этот метод также может решить вашу проблему.
DF['DICT_KEY'] = list(zip(DF['ITEM'], DF['STORE'], DF['DAY']-1))
DF['SIM_STOCK'] = np.where(DF['DAY'] == CURRENT_DAY,
DF['DICT_KEY'].map(dict_est) - DF['SIM_SALES'] + DF['RESTOCK'],
DF['SIM_STOCK'])
объяснение
- Создать
pd.Series
кортежей, которые затем подают в качестве ключей кdict_est
, - использование
np.where
указать свойif / else
условия.
Проблема была на самом деле довольно простой...
Я пытался получить значение из столбца DF['RESTOCK]
, следующее:
DF['RESTOCK'] = np.where(DF['COUNTER'] == 1,
DF['DICT_RESTOCK'].map(dict_RST),
0)
Но DF['COUNTER']
столбец обновляется после обоих RESTOCK
а также STOCK
,
Это правильный способ получить значение:
DF['ABAST'] = np.where(((DF['DICT_KEY'].map(dc) == 1)&(DF['DAY'] == DIA_ATUAL))
|(DF['COUNTER'] == 1),
DF['DICT_ABAST'].map(dict_abs),
0)