İzin ve Yokluk Yönetimi: Optimizasyon ve Sezgisel Algoritmalar-1

Şükrü İmre, PhD
7 min readJun 10, 2024

Organizasyonlar, verimliliklerini sürdürebilmeleri, rekabet avantajlarını koruyabilmeleri ve satış kaybı yaşamamaları için çalışanların izinleri ve yokluklarını etkin bir şekilde planlamalıdır. Dengeli ve etkili bir yönetim için stratejik planlama ve yenilikçi çözümler geliştirmek durumundadır. Planladığım yazı dizisinde, çalışan izin ve yokluk yönetiminin optimizasyon ve sezgisel algoritmalar kullanılarak nasıl çözümler üretilebileceğini göstereceğim. İlk yazıda, optimizasyon teorisini ve matematiksel modeli temel alarak, optimum çözümün nasıl yapılacağını Python kodlama dilini ve PuLP kütüphanesini kullanarak göstereceğim. İkinci yazıda ise sezgisel (heuristic) yaklaşımla ile optimizasyon ile çözülemeyen örneklerin nasıl çözülebileceğini kapsamlı bir şekilde ele alacağım. Tüm çözümler, tasarladığım perakende satış vakası ve ürettiğim sentetik veri ile yapılmıştır. Bu çözüm yaklaşımlarıyla sektör fark etmeksizin probleme özgü uyarlanarak kullanılabilir.

Problem Tanımı ve Veri

Satış yapan orta ölçekli bir perakende firmasını düşünelim. Bu firmanın 10 adet mağazası olsun. Her bir mağazanın da bağlı olduğu bölgeler olsun. Toplamda 3 bölge ve 10 mağaza. Bölgeler mağazaların gidişatını takip eden ve yeri geldiğinde destek olan birimlerdir. Bölgedeki çalışanlar, mağazalarda uzun süre tecrübe edinmiş ve her türlü işte kullanılabilecek kişilerden oluştuğunu düşünelim. Diğer bir deyişle, eğer bir mağazada herhangi bir kişiye ihtiyaç duyduğunda, bölgelerdeki herhangi bir çalışan, mağazaya yardım edebilecek bilgi birikimine ve tecrübeye sahip.

Firma haftanın her günü satış yapıyor olsun. Organizasyonun çizdiği vizyona ulaşmak için hedefleri vardır ve bunlardan birisi de satış hedefidir. Firma hayat yolculuğunda dinamik olarak işgücü kaynağını, hedeflerine uyumlu olacak şekilde yönetir. Mağazada çalışan personelinin yıllık izin, doğum günü izni, hastalık gibi yokluk durumlarında, mağazaya bölgelerden personel atayarak yokluğu giderip satış kaybı ve müşteri memnuniyetsizliği yaşamadan hedeflerine ulaşma yolculuğuna devam ediyor.

Genellikle manuel olarak ilerletilen yokluk planlama süreci, otomatik bir yaklaşımla optimizasyon teorisi ve sezgisel algoritmalardan yararlanarak çözülebilir mi? Bu soruya cevap arayacağım.

Tanımlanan problemi çözebilmek için mağazadaki çalışan sayılarına, mağaza-gün detayında kaç yokluk olacağını, hangi mağazaların hangi bölgelere bağlı olduğunu, bölgelerde gün bazında atanabilecek kaç çalışan olduğu ve hangi mağazanın öncelikli olduğu bilgilerine ihtiyaç vardır. Bu bilgilerin hepsini sentetik olarak oluşturdum.

Bölge verisi: Bölgede her gün atanabilecek personel sayısını Tablo 1’de verdim. Örneğin; Bölge 2’de her gün 11 atanabilir çalışan bulunduğunu anlayabiliriz.

Tablo 1. Bölge bazlı uygun personel sayısı

Mağaza verisi: Mağazalardaki çalışan sayısını, yokluk bilgisini (izin sayısını) gün bazında Tablo 2’de verdim. Örneğin; Mağaza 1, Salı günü için çalışan sayısı 5 olup, o günkü izin sayısı 4’tür. O gün mağazada kalan çalışan sayısı 1’dir. Mağazada kalan çalışan sayısı eğer 1 ise bu mağazanın öncelikli atanması gerekir.

Bu yüzden modelde kullanmak üzere, bir mağaza öncelik tanımlaması yaptım. Bu tanıma göre; mağazada yokluk sonrası 0 veya 1 kalan çalışan olması durumunda, mağazaları birinci öncelikli olarak tanımladım. Eğer, 2–4 arasında kalan çalışan sayısı olması durumunda, ikinci öncelikli aksi halde üçüncü öncelikli olarak belirledim.

Tablo 2. Mağaza bazlı veriler

Bölge-mağaza bağ verisi: Hangi mağazaların hangi bölgelere bağlı olduğu Tablo 3’te gösterdim. Bir mağaza sadece bir bölgeye bağlı olabilir ancak bir bölge birden fazla mağaza içerebilir.

Tablo 3. Mağaza-Bölge bağı

Metodoloji

Bu problemi iki aşamada ele alacağım. Böylelikle, mümkün olduğunca mağazalardaki yoklukları giderip bölge çalışanlarını atayacağım.

  • Tüm yokluk bilgisi ve bölgedeki atanabilir çalışanları dikkate alarak; optimizasyon modeli ile çözülebilir olanları kurduğum matematiksel modelleme ile çözeceğim. Bu ilk yazımın konusu.
  • İkinci adımda ise optimizasyon sonucunda atanan personelleri ve giderilen yokluk bilgilerini alarak; karşılanmayan yokluk ve atıl duran bölge çalışanlarını sezgisel algoritmayla atayacağım. Bu kısım ikinci yazımın konusu olacak.

Her bir bölge ve gün özelinde çözüm üretecek şekilde mağaza bazında optimizasyon modeli kurdum.

Modelin temel amacı, önceliği düşük olan mağazalara atamaları yaparak bölgeden minimum sayıda personel atamayı gerçekleştirmek.

Her optimizasyon modeli gibi bu modelin de kısıtları bulunuyor. Modelin kısıtlarından biri, mağaza yaşanan yokluk kadar atama yapmasıdır (kısıt 1). Yani, mağazadaki eksik personel kadar kadar ilgili mağaza personel desteği verilmesinin gerekir.

Diğer kısıt ise o bölge içerisinde bulunan mağazaların yokluk miktarıları dikkate alarak atanabilir personel sayısını aşmayan bir atama yapması gerekmektedir (kısıt 2). Aynı zamanda yapılan atamalar tamsayı olmak zorundadır ve minimum 0 olabilir.

Aşağıda modele ait bilgileri — parametreleri, karar değişkeni, amaç fonksiyonu ve kısıtlarını — bir bütün halde teorik gösterimini paylaştım.

Python PuLP ile Çözüm

Pythonda kodlama dili ve ilgili kütüphaneler kullanılarak veri hazırlığı yaptım. Modelin matematiksel ifadesi baz alınarak Python PuLP kütüphanesi ile kodlanarak çözdüm.

Aşağıdaki kod, bahsettiğim verilerin sentetik olarak nasıl oluşturulduğunu içeriyor.

import numpy as np
import pandas as pd
import pulp
# Rastgelelik için sabit tohum
np.random.seed(42)
# Mağaza ve çalışan sayısı bilgileri- sentetik veri
magaza = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
calisan_sayisi = [5, 4, 6, 7, 3, 4, 7, 5, 5, 6]
# Haftanın günleri
haftanin_gunleri = [1, 2, 3, 4, 5, 6, 7]
# Mağazaları bölgelere ayırma- mağaza-bölge bağ
bolgeler = {
'Bölge 1': [1, 4, 7, 9],
'Bölge 2': [2, 3, 6],
'Bölge 3': [5, 8, 10]
}
# Bölgedeki çalışan sayısı bilgisi
bolge_calisan_sayisi = {
'Bölge 1': 10,
'Bölge 2': 11,
'Bölge 3': 10
}
# Bölge - mağaza eşleştirme
magaza_bolge = {mag: bolge for bolge, mag_listesi in bolgeler.items() for mag in mag_listesi}
# Veri oluşturma - mağaza bazlı
data = [
[magaza_id, calisan, gun, np.random.randint(1, 5), magaza_bolge[magaza_id]]
for magaza_id, calisan in zip(magaza, calisan_sayisi)
for gun in haftanin_gunleri
]
# DataFrame oluşturma
df = pd.DataFrame(data, columns=['magaza', 'calisan_sayisi', 'gun', 'izin_sayisi', 'bolge'])
df['kalan_calisan_sayisi'] = df['calisan_sayisi'] - df['izin_sayisi']
# Öncelik seviyesini belirleme
def oncelik_seviyesi(kalan_calisan_sayisi):
if kalan_calisan_sayisi < 2:
return 1
elif 2 <= kalan_calisan_sayisi < 5:
return 2
else:
return 3
df['öncelik'] = df['kalan_calisan_sayisi'].apply(oncelik_seviyesi)
# Bölge sütununda bölge adlarını sayısal değerlere dönüştürme
bolge_mapping = {'Bölge 1': 1, 'Bölge 2': 2, 'Bölge 3': 3}
df['bolge_id'] = df['bolge'].map(bolge_mapping)
df.head()

Optimizasyon modelini kodlanması aşağıda gösterilmiştir. Bu kod içerisinde, optimizasyon modeliyle optimal bir şekilde çözülen model sonuçları ayrı bir dataframede tutuluyor. Model eğer çözülemezse (infeasible ise), çözülemeyen mağaza-bölge-gün üçlüsü ayrı bir dataframe olarak tutulur.

# Optimizasyon fonksiyonu
def optimize_assignment(df, bolge_df):
optimal_results = []
infeasible_results = []
# bölge ve gün bazında mağazalar için kurulan model yaklaşımı
for b in bolge_df['bolge_id'].unique():
for g in df['gun'].unique():
df_opt_magaza = df[(df['bolge_id'] == b) & (df['gun'] == g)]
magaza_list = df_opt_magaza['magaza'].unique()

# Optimizasyon modeli oluşturma
prob = pulp.LpProblem(f"Yokluk_Atama_Bolge_{b}_Gun_{g}", pulp.LpMinimize)

# Karar değişkeni
x = pulp.LpVariable.dicts("Atama_", magaza_list, lowBound=0, cat="Integer")

# Amaç fonksiyonu
prob += pulp.lpSum([x[i] * df_opt_magaza[df_opt_magaza['magaza'] == i]['öncelik'].values[0] for i in magaza_list])

# Kısıtlar
for m in magaza_list:
izin_sayisi = df_opt_magaza[df_opt_magaza['magaza'] == m]['izin_sayisi'].values[0]
prob += x[m] >= izin_sayisi

uygun_personel = bolge_df[bolge_df['bolge_id'] == b]['uygun_personel'].values[0]
prob += pulp.lpSum([x[i] for i in magaza_list]) <= uygun_personel

# Modeli çözme
prob.solve()

# Sonuçları toplama
for m in magaza_list:
if prob.status == pulp.LpStatusOptimal and x[m].varValue <= uygun_personel:
optimal_results.append({
"bolge_id": b,
"magaza": m,
"gun": g,
"atanan_personel": x[m].varValue
})
else:
infeasible_results.append({
"bolge_id": b,
"magaza": m,
"gun": g
})

return pd.DataFrame(optimal_results), pd.DataFrame(infeasible_results)
# Optimizasyonu çalıştırma
df_optimal_results, df_infeasible_results = optimize_assignment(df, bolge_gunluk_calisan_df)

Optimizasyon sonrası atananları bir bakalım.

# Optimizasyon model sonuçları 
print("Optimal Results:")
df_optimal_results.head()
Tablo 4. Optimal sonuç

Optimizasyon sonucu elde edilen çözümün doğruluğunu kontrol etmek gerekir. Çözümün kontrolü için aşağıdaki sorunun cevaplanması gerekir.

Bölge bazlı toplam atanan personel sayısı, bölgedeki uygun personel sayısını aşıyor mu?

İlk etapta, optimum çözüm için oluşturulan dataframede bölge ve gün bazlı atanan personel sayıları çıkarılır.

grouped_df = df_optimal_results[['bolge_id', 'gun', 'atanan_personel']].groupby(['bolge_id', 'gun']).sum().reset_index()
grouped_df
Tablo 5. Bölge ve gün bazlı atanan personel sayısı

Daha sonra Tablo 1'de özetlenen personel sayısı ile gruplanan veri (Tablo 5) karşılaştırılır. Örneğin; Tablo 1'den ikinci bölgedeki uygun personel sayısı 11 olarak verilmiş iken, aynı bölge cuma günü (5. gün) için üretilen çözümde 10 personel atanmıştır. Bu değer 11'den küçük olduğu için yapılan atama uygundur diyebiliriz. Bunu tek tek manuel bir şekilde yapmak yerine aşağıdaki kodu kullanabiliriz.

# Gruplama sonrası veri kontrolü ve yazdırma
for g in grouped_df['gun'].unique():
for b in grouped_df['bolge_id'].unique():
filtered_data = grouped_df[(grouped_df['gun'] == g) & (grouped_df['bolge_id'] == b)]
if not filtered_data.empty:
atanan_personel = filtered_data['atanan_personel'].values[0]
bolge_uygun_kisi = bolge_df.loc[bolge_df['bolge_id'] == b, 'uygun_personel'].values[0]
if atanan_personel <= bolge_uygun_kisi:
print(f"{b}. bölgede {g}. gün için atanan personel sayısı {int(atanan_personel)} kişidir. Atamalar bölgedeki uygun personel sayısına göre yapılmıştır.")
else:
print("Atamalar bölgedeki uygun personel sayısını aşmaktadır. Optimum çözüm bulunmamıştır. Modeli yeniden incele!")

Tablo 6'daki sonuçlara göre, atama yapılan tüm bölge ve günler için üretilen çözümler optimaldir ve uygundur.

Tablo 6. Bölge ve gün bazlı kontrol sonucu

Model ile çözülemeyen; yani infeasible çıkan mağaza-bölge-gün listesini Tablo 7'de gösterdim. Bu üçlüler için heuristic bir algoritma geliştirerek çözüm üreteceğim.

# Infeasible model sonuçları
print("Infeasible Results:")
df_infeasible_results.head()
Tablo 7. Infeasible sonuç

Sonuç

Tarif edilen yokluk ve izin yönetim probleminin nasıl çözüleceğine yönelik bir yaklaşım geliştirdim. Bu yaklaşımın ilk adımı olan optimizasyon ile çözümün nasıl yapıldığını detaylı bir şekilde paylaştım. Kalan kısmı serinin ikinci yazısında paylaşacağım. İlk sonuçlara göre; manuel olarak yürütülen ve zaman kaybına sebep olan iş problemlerinin modellenerek daha kısa sürede çözülmesi mümkün olduğunu gösterdim. Bu tip uygulamaları yaygınlaştırarak, bu tip planlamaları yapan çalışanların daha etkin ve odaklı işlerde kullanılması daha da olası hale gelecektir.

Dr. Şükrü İmre

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Şükrü İmre, PhD
Şükrü İmre, PhD

Written by Şükrü İmre, PhD

// Head of Data Science at Yapı Kredi Bank // Guest Lecturer at MEF University // Author at Harvard Business Review Türkiye // Author at Medium

No responses yet

Write a response