Часто, когда задействованы такие остатки, как инвентарь, «векторизация» может быть достигнута с использованием кумулятивного для потоков.
итеративный balance[t] = balance[t-1] + in[t] - out[t]
становится векторизованным balance = in.cumsum() - out.cumsum()
import numpy as np
in_ = np.array( [10, 5, 30, 20, 10, 50, 5, 30, 0, 0, 0, 0] )
orders = np.array( [0, 0, 0, 0, 70, 0, 60, 0, 0, 0, 0, 0] )
# 4 extra periods to handle the out of date range.
out_of_date = np.zeros_like( in_ )
out_of_date[ 4: ] = in_[ :-4 ]
# Parts fall out of date after 4 weeks if not already delivered.
# Create cumulatives to work with
cum_in = in_.cumsum() # Constant through calculation
cum_orders = orders.cumsum() # Constant through calculation
cum_ood = out_of_date.cumsum() # Amended at each iteration
cum_deliveries = np.zeros_like( cum_in ) # One period filled each iteration
available = np.zeros_like( in_ ) # One period filled each iteration
deliveries = np.zeros_like( cum_in ) # One period filled each iteration
def decum( in_, axis=-1 ):
""" Take differences in_[t] - in_[t-1] fill first period with in_[0] """
res = in_.copy()
res[ 1: ] = np.diff(in_, 1, axis = axis)
return res
def cum_dels( week ):
""" Calcultes cumulative deliveries at the week specified.
Also calculates the value of deliveries in the week """
available[ week ] = cum_in[ week ] - cum_ood[ week ]
cum_deliveries[ week ] = np.minimum( cum_orders[ week ], available[ week ] )
if week:
deliveries[ week ] = cum_deliveries[ week ] - cum_deliveries[ week-1 ]
else:
deliveries[ week ] = cum_deliveries[ week ] # If week == 0 no difference to take
def amend_ood( week ):
""" Amend the cum_ood for deliveries in the week. """
min_cum_ood = cum_ood[ week ] # Don't subtract to below the cum_ood in this week.
available_notused = available[ week ] - cum_deliveries[ week ]
# Don't subtract any available that's not delivered.
# This has the effect of taking deliveries from the most recent in_
max_subtract = np.maximum( cum_ood[ week: ] - min_cum_ood - available_notused, 0)
# The maximum to subtract is the cum_ood less the fixed bands and never less than zero.
to_subtract = np.minimum( max_subtract, deliveries[ week ] ) # max_subtract clipped at the weeks deliveries
cum_ood[ week: ] -= to_subtract
week_range = range(8)
# Iterate the above functions by week.
# This can be rewritten to calculate all part numbers for each week.
for week in week_range:
cum_dels( week )
amend_ood( week )
print(deliveries)
print(decum(cum_ood)[4:])
Функции должны переписать для работы с 2d массивами, part_number x week. Затем каждая итерация за неделю вычисляет все номера деталей для этой недели.
Я посмотрю, как сделать это 2d, как только у меня будет время, но это может помочь как есть. Также есть возможность оптимизировать код. Это написано, чтобы помочь мне понять, что я делал.
** Изменить Изменения для запуска 2D-версии **
out_of_date = np.zeros_like( in_ )
out_of_date[ :, 4: ] = in_[ :, :-4 ]
# Parts fall out of date after 4 weeks if not already delivered.
# Create cumulatives to work with
cum_in = in_.cumsum(axis=1) # Constant through calculation
cum_orders = orders.cumsum(axis=1) # Constant through calculation
cum_ood = out_of_date.cumsum(axis=1) # Amended at each iteration
cum_deliveries = np.zeros_like( cum_in ) # One period filled each iteration
available = np.zeros_like( in_ ) # One period filled each iteration
deliveries = np.zeros_like( cum_in ) # One period filled each iteration
def decum( in_, axis=-1 ):
""" Take differences in_[t] - in_[t-1] fill first period with in_[0] """
res = in_.copy()
res[ :, 1: ] = np.diff(in_, 1, axis = axis)
return res
def cum_dels( week ):
""" Calcultes cumulative deliveries at the week specified.
Also calculates the value of deliveries in the week """
available[ :, week ] = cum_in[ :, week ] - cum_ood[ :, week ]
cum_deliveries[ :, week ] = np.minimum( cum_orders[ :, week ], available[ :, week ] )
if week:
deliveries[ :, week ] = cum_deliveries[ :, week ] - cum_deliveries[ :, week-1 ]
else:
deliveries[ :, week ] = cum_deliveries[ :, week ] # If week == 0 no difference to take
def amend_ood( week ):
""" Amend the cum_ood for deliveries in the week. """
min_cum_ood = cum_ood[ :, week ] # Don't subtract to below the cum_ood in this week.
available_notused = available[ :, week ] - cum_deliveries[ :, week ]
# Don't subtract any available that's not delivered.
# This has the effect of taking deliveries from the most recent in_
max_subtract = np.maximum( cum_ood[ :, week: ] - min_cum_ood[:,None] - available_notused[:,None], 0)
# The maximum to subtract is the cum_ood less the fixed bands and never less than zero.
to_subtract = np.minimum( max_subtract, deliveries[ :, week ].reshape(-1,1) ) # max_subtract clipped at the weeks deliveries
cum_ood[ :, week: ] -= to_subtract
Это не дает те же результаты, что и ваша версия для части число Z.
Какие результаты ожидаются со следующим сценарием ios?
data = {
"Part": ["Z", "Z", "Z", "Z", "Z", "Z"],
"Week": [1, 2, 3, 4, 5, 6],
"Gross Forecast": [10, 5, 10, 30, 30, 0],
"Orders": [ 0, 0, 0, 0, -90, 0]
}
Или с этим
data = {
"Part": ["Z", "Z", "Z", "Z", "Z", "Z", "Z", "Z"],
"Week": [1, 2, 3, 4, 5, 6,7,8],
"Gross Forecast": [10, 5, 10, 30, 30, 0, 0, 100],
"Orders": [ 0,-90, 0, 0, 0, 0, 0, -50]
}