Dengeli İş Atama — Optimizasyon Model Örneği

Bu yazı, depo içerisinde ürün toplamak için verilen iş emirlerinin, toplayıcılara adil/dengeli bir dağıtım yapılmasını sağlayan optimizasyon modeli örneğini ele alıyor. Bu tip optimizasyon modeline hangi durumlarda ihtiyaç olduğunu, özetlediği süreç bilgisiyle aktarıyor. Kurulan optimizasyon modelinin matematiksel modelleme kısmıyla teorik modellemesini yaptıktan sonra Python’da PuLP kütüphanesinden yararlanarak modelin çözümünü ait kodlamaları detaylandırıyor.
Özet Süreç
Lojistik faaliyeti sürdüren firmaların depolarında stoklanan ürünler gelen siparişe, talebe göre toplanıyor. Benzer şekilde, perakende sektöründe faaliyet gösteren firmaların eğer kendilerine ait depoları bulunuyorsa, mağazaları ve e-ticaret operasyonlarında oluşturulan iş emirlerine göre ürünler toplanıyor. Örneğin; X firmasının AVM’lerdeki, caddelerdeki vb. yerlerdeki mağazaları için toplanacak ürünler çalışanları tarafından ürünlerin satış performansları, iklim, müşteri demografik özelliklerine akıllı bir şekilde planlanıyor. Planın nasıl bir şey olduğunu devam eden örnekten anlamak mümkündür.
Y mağazasına K ürününden 5 tane, L ürününden 3 tane iken Z mağazasına K ürününden 2 tane, L üründen 1 tane, M ürününden 4 tane gönderilmeli.
Burada iki mağaza için örnek verildiği görülüyor, bir firmanın mağaza sayısı yüzlerce olabilir ve binlerce ürünü planlaması gerekebilir. Planlamanın bu boyutunu da gözden kaçırmamak gerekir. Planlanan mağaza-ürün ikilileri firmanın deposundaki bulunduğu lokasyon ve stok adetleri ile analitik değerlendirilmeye tabi tutulur. Bunun sonucunda depodaki operasyon ekiplerine iş emri iletilir.
Bu iş emri, hangi ürünün hangi mağaza için ne kadar miktarda hangi depo lokasyonundan toplanacağının bilgisidir.
İş emirleri, analitik yaklaşımla bir algoritma (sezgisel, matematiksel model vb.) tarafından üretileceği gibi kural bazlı (maksimum miktar, maksimum mesafe vb.) bir şekilde de üretilebilir.
Özetle, firma özelinde farklılık gösterse de genellikle süreç, planlanma ekibinden analitik ekiplere oradan da depo operasyonlarına akar. Depo operasyon yöneticisinin, Analitik birim tarafından oluşturulan iş emirlerini toplayıcılara nasıl adil dağıtıcağı bir problem noktasıdır. Bu problemin tanımını aşağıda detaylandırılıyor.
Problem Tanımı
Analitik çalışanlar tarafından üretilen iş emirleri içinde toplanacak ürün adetleri, toplanacak ürünlerin hacimlerini (desi) içerir.
Bir iş emrine, diğer bir deyişle “tur” denilir. Toplayıcı iş emrini gerçekleştirmek için, toplama listesinden yazan depo içerisindeki lokasyonlara uğrayarak hedefindeki mağazalara planlanmış ürünleri toplar ve böylelikle bir tur atmış olur.
Aldığı iş emrini bitirdikten sonra paketleme alanına topladığı ürünleri teslim eder ve diğer iş emrini yani turu alır, toplamaya devam eder. Toplayıcılar günlük çalışmasını bu şekilde tamamlar. Depo operasyon yönetimi, iş emirlerini toplayıcıya verirken adil veya dengeli bir yaklaşım sergilemeyi amaçlar çünkü günün sonunda tüm toplayıcıların eşit miktarda, eşit hacimde ve gerçekleştirdiği tur sayısı bakımından eşit sayıda iş almasını ister. Bu kapsamda, firmanın depo operasyonları yönetimi, Analitik departmanından bu üç amacı dikkate alacak bir dengeli tur (iş emri) atama modeline ihtiyaç duyduğunu düşünelim.
Dengeli Tur Atama Matematiksel Modeli
Bu ihtiyacı karşılayacak modelin örnek bir veri kullanarak oluşturulması amaçlanıyor. Modelin kullanacağı veride toplamda 5177 ürünün toplanacağı 74 tur bulunuyor (Tablo 1). Depo operasyon ekibi, tüm ürünlerin toplanmasında 8 toplayıcı elinde bulunsun. Buradaki soru, 74 turun 8 toplayıcıya (operatör) adil bir şekilde atanması mümkün müdür? Yani, öyle bir dağıtım olmalı ki her bir toplayıcıya düşen toplam ürün hacmi, toplam tur sayısı dengeli olsun.

Bunu sağlayabilmek için ilk etapta kümeleri belirlemek gerekir. Buradaki kümeler; operatör, tur, her bir turun karşılık geldiği toplam hacim (desi) ve toplam ürün miktarı olarak belirlenir. Kurulacak optimizasyon modeli bu kümeler üzerinden modellenecektir.

Modellemede kullanılacak parametrelerden ilk ikisi, her bir turdaki toplanacak ürün miktarı (mt) ve desi miktarıdır (dt). Dengeli atamaya yardımcı olacak operatör başına düşün ortalama desi miktarı (Davg) ve tur sayısı (Tavg) da birer parametre olarak modele girdi sağlar. Modelin çözümüne yardımcı olacak ve dengeli atamada desi ve tur sayısı arasında eşik değerin belirlenmesine yardımcı olacak M1, M2 ve M3 parametreleri de modelde bulunur.

Dengeli tur atama modelinde kullanılacak karar değişkenler üç tiptedir. İlk karar değişkeni, hangi operatörün hangi tura atanmasını belirleyen binary karar değişkendir. Diğer ikisi ise operatör başına düşün ortalama desi ve ortalama tur sayısının ne oranda katkı sağlayacağını belirleyen değişkenlerdir. Örneğin 3 tane tur ve 2 operatör olsun. Burada operatör başına ortalama tur sayısı 1,5’dur. Bir tur iki bölünemeyeceği için bir operatöre 1 tur diğerine 2 tur atamasını yaptırabilmek için bu karar değişkenine ihtiyaç vardır. Aksi halde model infeasible çıkar. Benzer örnek desi için de verilebilir.

Optimizasyon modelinin amaç fonksiyonu; turdaki tüm ürünlerin toplanmasını garantiye almak için maksimizasyon problemi olarak tanımlanıyor. Ortalama desi ve tur sayısının katılım oranını maksimum yapmak için amaç fonksiyonuna M1 ve M2 parametreleri ile eklenir. Diğer bir deyişle, operatör başına düşen desi miktarı ve tur sayısına yakın bir atamayı garanti kılar.

Modelin 1 numaralı kısıdı, her bir turun tek bir operatöre atanmasını belirten kısıttır. 2 numaralı kısıt, operatör başına düşen desiye yakın bir atama yapmasına yardımcı olacak kısıt olarak oluşturulur. Benzer şekilde 3 numaralı kısıt, operatör başına düşen tur sayısına yakın atama yapmasını sağlar. Yani, bu iki kısıt atama gerçekleştiğinde ortalama değerlerin etrafında değerler almasını sağlar. Örneğin; operatör başına ortalama 5,4 tur sayısı belirlenmişse, kimi operatörün 5 tur, kimi operatörün 6 tur, kiminin ise 4 tur almasını beklenir. Veriye göre değişkenlik göstereceği aşikardır. 5 numaralı kısıt ise karar değişkenlerin hangi aralıkta olacağını ve işaret kısıdı ifade eder.

Python PuLP ile Modelin Kodlaması ve Çözümü
İlk olarak kütüphaneler yüklenir.
import pandas as pd
from pulp import *
Operatör, tur, turlara ait desi ve miktar bilgileri eklenir.
# operator ve tur bilgileri
operator_list=list(range(1,9))
tur_list=list(range(1,75))
tur_desi=[188,199,164,199,199,188,188,188,210,188,188,155,144,199,210,210,188,199,199,199,210,177,188,199,199,199,210,210,210,199,199,188,210,210,199,199,188,199,199,210,188,166,210,210,210,210,210,210,199,199,210,210,210,199,210,210,166,188,199,177,199,177,210,199,188,188,188,188,210,199,199,210,177,164]
miktar=[18,23,17,33,52,39,37,29,38,48,15,6,6,7,6,13,28,17,91,128,99,79,63,31,40,29,41,52,57,28,74,134,156,160,132,142,154,161,133,152,77,71,59,62,63,81,76,68,60,96,68,24,56,89,51,104,57,118,67,82,91,72,109,66,82,120,45,120,39,63,81,120,69,103]
Operatör bilgileri dataframe (df) olarak oluşturulur.
# operatör bilgisi dataframe yapılır
df_operator = pd.DataFrame(operator_list, columns=['operator'], index =list(range(len(operator_list))))
df_operator

Daha sonra tur verisi df yapılır.
# tur bilgisi df olarak üretilir
tur_info = pd.DataFrame(zip(tur_list,tur_desi,miktar),columns=['tur','desi','miktar']
, index =list(range(len(operator_list),len(tur_list)+len(operator_list))))
tur_info

Operator ve tur bilgisine ait dfler crosslanarak potansiyel atama havuz verisi oluşturulur.
# potansiyel operatör-tur eşleşme karar verisi
df_operator['key'] = 1
tur_info['key'] = 1
model_df = pd.merge(df_operator, tur_info, on ='key').drop("key", 1)
model_df

Bu veri, tüm turların operatör bazlı çoklanmasından oluşur. Modele bu veri sokularak hangi operatöre hangi turun atanacağına karar verilecektir.
Şimdi dengeli dağıtım yapabilmesi için operatör başına düşen tur sayısını ve desi miktarına ait parametreleri belirlemek gerekiyor.
Tavg=len(tur_list)/len(operator_list)
Davg=sum(tur_desi)/len(operator_list)
print('Operator başına düşen tur sayısı (Tavg) : ', Tavg)
print('Operator başına düşen desi miktarı (Davg) : ', Davg)
print('Toplanacak toplam miktar', sum(miktar))

Modelin diğer parametreleri ve karar değişkenleri ise aşağıdaki kod yardımıyla belirlenir. Modelin uygun çözümü bulunması için M1 ve M2 10000 ve M3 parametresi 0.53 olarak alınmıştır. Bu parametreler, veriye ve model kısıtlarına göre değişebilecek olması göz ardı edilmemelidir.
M1=10000
M2=10000
M3=0.53
# model karar değişkeni
x=LpVariable.dicts("assign",[(i,j) for i in operator_list for j in tur_list], cat='Binary')
y=LpVariable("parameter_avg_desi", lowBound=0.5, upBound=0.99, cat='Continuous')
z=LpVariable("parameter_avg_tur", lowBound=0.5, upBound=0.99, cat='Continuous')
Model türü ve amaç fonksiyonu tanımlanır.
# model ve amaç fonksiyonu
model=LpProblem("Max Amount",LpMaximize)
model += M1*y+M2*z+(lpSum([x[(i,j)]*model_df[(model_df['operator']==i) & (model_df['tur']==j)].iloc[0,3] for i in operator_list for j in tur_list]))
Modelin kısıtları eklenir.
# her tur bir operatöre atanmalı
for j in tur_list:
model += (lpSum([x[(i,j)] for i in operator_list]))>=1
model += (lpSum([x[(i,j)] for i in operator_list]))<=1
# ortalama desi ve tur sayısına göre atanma yapılmalı
for i in operator_list:
model += (lpSum([x[(i,j)] for j in tur_list])) >=Tavg*z
model += (lpSum([x[(i,j)]*model_df[(model_df['operator']==i) & (model_df['tur']==j)].iloc[0,2] for j in tur_list])) >=Davg*y
# desi ile tur sayısı arasındaki öncelik ilişkisi
model+=z<=M3*y
Modelin çözümü ve amaç fonksiyon değeri bulunur.
# model çözümü ve amaç fonksiyonu değeri
model.solve()
print("Çözülen Model : {}".format(LpStatus[model.status]))
print("Toplam Miktar = ", value(model.objective))

Karar değişkenlerin aldığı değer sonuçları alınır.
var_name= []
var_value=[]
for v in model.variables():
if v.varValue>0:
var_name.append(v.name)
var_value.append(v.varValue)
# sonuçlar dataframe olarak oluşturulur.
df_result=pd.DataFrame(zip(var_name,var_value), columns=['Değişken','Değer'])
df_result

Yukarıdaki sonuçlara göre, “assign_(1,_10) = 1” değeri demek 1 numaralı operatöre 10 numaralı tur atanmış demektir. Model tarafından y ve z karar değişkenlerinin değeri ise sırayla 0.99 ve 0.52 olarak belirlenmiştir.
Atanan operator-tur ikilileri df olarak üretilir.
op_list=[]
tur_la=[]
assign_infoa=[]
for i in operator_list:
for j in tur_list:
if x[(i,j)].value()>0:
op_list.append(i)
tur_la.append(j)
assign_infoa.append(x[(i,j)].value())
df_result2=pd.DataFrame(zip(op_list,tur_la,assign_infoa), columns=['operator','tur','assign_flag'])
df_result2

Operatör bazlı sonuçlar özetlenir.
# sonuçlar özetlenir
result_summary=model_df.merge(df_result2, on=['operator','tur'], how='inner')
df_sonuc=result_summary[['operator','desi','miktar','assign_flag']].groupby('operator').sum()
df_sonuc.reset_index(inplace=True)
df_sonuc.head()

Bu sonuçlara bakıldığında operatörlerin aldıkları turlara göre dengeli bir desi dağılımı ve tur sayısı olduğu görmek mümkündür.
Operatör bazlı atanan turlara göre toplam desi miktarları aşağıdaki kod ile görselleştirilebilir.
fig, ax = plt.subplots(figsize=(14,10))
plt.rcParams['font.size'] = 18
x_axis = df_sonuc['operator'].to_list()
y_axis = df_sonuc['desi'].to_list()
plt.bar(x_axis, y_axis, color='crimson', align='edge', width=0.6)
plt.xlabel("Operatör", size=20)
plt.ylabel("Toplam Desi", size=20)
for index in range(len(x_axis)):
ax.text(x_axis[index], y_axis[index], y_axis[index])
plt.show()

Benzer şekilde toplam tur sayısı da görşelleştirilebilir.
fig, ax = plt.subplots(figsize=(14,10))
plt.rcParams['font.size'] = 18
x_axis = df_sonuc['operator'].to_list()
y_axis = df_sonuc['assign_flag'].to_list()
plt.bar(x_axis, y_axis, color='limegreen', align='edge', width=0.6)
plt.xlabel("Operatör", size=20)
plt.ylabel("Toplam Tur Sayısı", size=20)
for index in range(len(x_axis)):
ax.text(x_axis[index], y_axis[index], y_axis[index])
plt.show()

Her iki bar-charttan da görüleceği üzere kurulan dengeli tur atama modeli belirlenen kısıtlar altında dengeli bir dağıtım yaptığı söylenebilir.
Sonuç olarak, depo operasyon yöneticisinin istediğini sağlayacak bir karar modeli kurulmuş oldu. Yönetici, operatörlere atanan tur numaralarını eşleştirerek işini planlayabilir hale geldi. Unutulmamalıdır ki model parametreleri, karar değişkenleri, kısıtlar firmadan firmaya değişkenlik gösterebilir. Burada basit bir yaklaşımla dengeli bir atama modeli nasıl kurulabilir sorusuna örnek veri setiyle cevap aranmıştır. Belirtmek isterim ki depo içi operasyonları için yapılan bu dengeli iş atama modeli, başka sektörlerdeki iş atama optimizasyon problemlere esin kaynağı olabilir.
Dr. Şükrü İMRE