Tahminle Yöntem ve Dürüst Karşılaştırma
LightGBM ile mağaza–option tahmini kurduk ve kuralla yarıştırdık. Model öngörüde açıkça daha isabetli çıktı, sonuçta değil. Asıl mesele hangisinin kazandığı değil, farkın nereden geldiği.
Depodan Mağazaya · 5 / 6
Geçen yazıda kural tabanlı yöntemi kurduk: son yedi günün satışı, özel gün katsayısı ve bir taban. Sonra onu Lumoda’nın bugünkü yöntemiyle yarıştırdık. Kural 8,77 puan geride kaldı ve bu farkın 5,45 puanı ne kadar stok taşındığından geliyordu.
Şimdi aynı işi makine öğrenmesiyle yapacağız ve aynı dört ayı, aynı müşteri akışıyla yeniden oynatacağız. Sorumuz şu: kuralın öngörüsü kaba bir hesap, daha iyi bir öngörü sonucu değiştirmez mi?
Baştan söyleyeyim: bu yazıda önemli olan hangi yöntemin kazandığı değil. Daha iyi öngörü daha iyi sonuç getirmedi. Asıl mesele, farkın nereden geldiği.
Model
Tek bir küresel LightGBM modeli kullanıyoruz. Yani her mağaza–option çifti için ayrı bir model yok. Bütün çiftler aynı modelde.
Hedef değişken: önümüzdeki yedi günün mağaza–option satışı.
Özellikler: son dört haftanın haftalık satışı, dört ve sekiz haftalık ortalamalar, zincirin geçen haftaki toplam satışı, line, kategori, mağaza tipi, önümüzdeki haftadaki tatil ve Black Friday günleri. Bir özellik daha var: çiftin geçen hafta kaç gün rafta olduğu. Bu sayı modele, geçen haftanın sıfır satışının “talep yok” mu yoksa “raf boştu” mu demek olduğunu söylüyor.
Amaç fonksiyonu: Poisson. Veri sayım verisi.
Eğitim: model bir kez eğitiliyor. Sezonun ilk ürünleri rafa çıkmadan önceki güne kadar, üç yıla yakın bir geçmişle: 128 pazartesi, 1.651.315 satır. Her satır bir pazartesi, bir çift ve o çiftin ertesi haftaki satışı. Ertesi hafta bir gün bile rafta olmayan çiftleri eğitime almadık, çünkü boş rafın sıfır satışı talep hakkında bir şey söylemez. Eğitim bu bitiş gününden sonrasının hiçbir satırını okumuyor; bunu bir test güvence altına alıyor.
Model dört ay boyunca yeni bir şey öğrenmiyor. Her pazartesi yalnız girdiler, yani son haftaların satışı yenileniyor; ağaçlar ilk pazartesi neyse son pazartesi de o.
Hiperparametreler: 31 yaprak, 400 ağaç, öğrenme oranı 0,05. Bunları başka bir veriyle yaptığımız bir denemede küçük bir ızgaradan seçmiştik, bu veride yeniden aramadık.
Modelin kodu vakalar/replenishment/replenishment/tahmin.py içinde. Üç
kolun tanımı politika.py’de, koşuların hepsi oyun.py’de, beş müşteri
akışı yollar.py’de.
“ML ile tahmin” denince kurulan standart model budur. Rakibi bilerek güçlü seçtik. Zayıf bir modelle kıyaslamak kimseye bir şey öğretmez.
Öngörüde model önde
Önce modelin kendisine bakalım. Eğitim geçmişinin son sekiz pazartesisini dışarıda bıraktık, modeli öncekilerle eğittik ve o sekiz haftanın satışını öngördük. Hata ölçüsü Poisson sapması; küçük olan iyi:
| Öngörü | Poisson sapması |
|---|---|
| LightGBM | 2,978 |
| Son dört haftanın ortalaması | 3,866 |
| Geçen haftanın satışı | 9,108 |
Bu tablo öngörüyü satışa karşı ölçüyor: doğrulama haftalarında gerçekleşen satışa. Geçen haftanın satışı, kuralın öngörüsünün ham hâli. Kural onu stoklu güne bölüyor ve özel gün katsayısıyla düzeltiyor; bu tabloda o düzeltmeler yok. Yine de aradaki mesafe büyük.
Böyle bir yarışta en sık duyulan bahane veri seyrekliğidir: haftada bir iki adet satan bir çiftte öğrenilecek bir örüntü yoktur, ortalama almakla model kurmak arasındaki fark kapanır. Bu veride o bahane geçmiyor. Doğrulama haftalarında rafta olan bir çift haftada ortalama 12,35 adet satıyor, modelin öngörüsü ortalamada 11,78.
Asıl sınav karar gününde. Dört ayın ilk pazartesisi temiz bir karşılaştırma veriyor, çünkü o sabah bütün kolların geçmişi aynı: henüz hiçbiri tek bir karar vermedi. Satıştaki 10.868 çiftin önümüzdeki haftaki gerçek talebi 205.714 adet. Bu sayıyı yalnız hakem biliyor, raf boşken gelip giden müşteri de içinde:
| Kural | LightGBM | |
|---|---|---|
| Öngörü | 155.732 | 202.745 |
| Gerçek talebe oranı | %75,7 | %98,6 |
LightGBM’in öngörüsü kuralınkinden %30,2 yüksek ve gerçek talebe çok daha yakın. Kural talebin dörtte birine yakınını görmüyor, model neredeyse tamamını görüyor.
İlk kurulum
Modeli kurduk, öngörüsünü doğrudan hedef stok yaptık ve dört ayı oynattık. Depo kısıtları üçüncü yazıdaki gibi: koli kuralı ve haftada 25.826 adetlik açık toplama tavanı.
| Kural | Yalnız LightGBM | Fark | |
|---|---|---|---|
| Bulunabilirlik | %65,10 | %63,21 | −1,89 puan |
| Kayıp oranı | %38,89 | %40,79 | +1,90 puan |
| Gönderilen adet | 1.543.082 | 1.473.543 | −69.539 |
| Dört ayın sonunda mağaza stoğu | 311.819 | 299.711 | −12.108 |
Felaket değil. Ama daha iyi öngörü daha iyi sonuç getirmedi. İlk pazartesi kuraldan çok daha fazla mal öngören model, dört ayın toplamında daha az mal gönderdi ve daha düşük bulunabilirlikle bitirdi.
Buradan “demek ki ML işe yaramıyor” diye bir sonuç çıkarmak kolay. Ama bu yanlış olurdu. Çünkü iki kolu karşılaştırırken aynı anda iki şeyi değiştirmiştik:
- Öngörüyü kim üretiyor: geçen haftanın satışı mı, LightGBM mi?
- Öngörünün altında bir taban var mı?
Kuralda 4 adetlik taban vardı, LightGBM kolunda yoktu. Dördüncü yazıda tabanın kararların beşte ikisinden fazlasında son sözü söylediğini görmüştük. Bu kıyas “kural mı iyi, ML mi” sorusunu değil, iki sorunun karışımını ölçüyordu.
Üçüncü kol
Bunun üzerine üçüncü bir kol kurduk. Öngörüyü LightGBM üretiyor. Geri kalan her şey kural koluyla aynı: taban, beden bölüşümü, depo kısıtları, koli kuralı, paylaştırma önceliği. Kodda üç kol yalnız hedefi kurdukları yerde ayrılıyor:
# replenishment/politika.py (üç kolun hedefi; sınıfların öbür üyeleri çıkarıldı)
class KuralKol(_HedefliKol):
"""hedef = max(kural öngörüsü, güvenlik stoku); özel gün katsayıları bir kez."""
def _hedef(self, g):
ongoru = self._ongoru(g)
return np.maximum(ongoru, self._gs(g)), ongoru
class TahminKol(_HedefliKol):
"""hedef = LightGBM öngörüsü (taban yok)."""
def _hedef(self, g):
ongoru = self._ongoru(g)
return ongoru, ongoru
class TahminTabanKol(TahminKol):
"""hedef = max(LightGBM, güvenlik stoku): kuralla aynı taban, öngörü farklı."""
def _hedef(self, g):
ongoru = self._ongoru(g)
return np.maximum(ongoru, self._gs(g)), ongoru
_gs güvenlik stoku, yani taban. İkinci dönen değer öngörünün kendisi:
paylaştırma önceliği (cover) mağazaları sıralarken onu kullanıyor. Yani
öncelik kuralı aynı, ama sırayı her kol kendi öngörüsüyle kuruyor.
Üç kolun aynı dört aydaki sonuçları:
| Kural | LightGBM + taban | Yalnız LightGBM | |
|---|---|---|---|
| Bulunabilirlik | %65,10 | %65,00 | %63,21 |
| Kayıp oranı | %38,89 | %39,35 | %40,79 |
| Satışa dönme | 7,5 gün | 7,5 gün | 7,2 gün |
| Gönderilen adet | 1.543.082 | 1.508.690 | 1.473.543 |
| Dört ayın sonunda mağaza stoğu | 311.819 | 331.606 | 299.711 |
| Toplama maliyeti | 7.673.800 TL | 7.606.220 TL | 7.493.540 TL |
Tabanı geri koyunca LightGBM kurala yetişiyor, aradaki fark 0,10 puan. Ama önüne geçemiyor. Üstelik dört ayı 19.787 adet daha çok stokla bitiriyor.
Farkı ikiye ayırmak
Şimdi asıl hesaba geldik. Tek bir müşteri akışına bakmak yetmez: 0,10 puanlık bir fark şans da olabilir. Bu yüzden aynı dört ayı beş farklı müşteri akışında oynattık. Her akışta LightGBM o akışın kendi geçmişiyle yeniden eğitildi.
İki fark hesaplıyoruz.
Öngörünün etkisi: LightGBM + taban eksi kural. Taban aynı, öngörü farklı.
| Ölçüt | Medyan fark | 5 akışın kaçında |
|---|---|---|
| Bulunabilirlik | −0,33 puan | 4’ünde eksi |
| Kayıp oranı | +0,69 puan | 4’ünde artı |
| Dört ayın sonunda mağaza stoğu | +19.866 adet | 5’inde artı |
| Toplama maliyeti | −16.430 TL | 4’ünde eksi |
Politikanın etkisi: yalnız LightGBM eksi LightGBM + taban. Öngörü aynı, taban kalkıyor.
| Ölçüt | Medyan fark | 5 akışın kaçında |
|---|---|---|
| Bulunabilirlik | −1,79 puan | 5’inde eksi |
| Kayıp oranı | +1,44 puan | 5’inde artı |
| Dört ayın sonunda mağaza stoğu | −16.655 adet | 3’ünde eksi |
| Toplama maliyeti | −112.680 TL | 5’inde eksi |
Politikanın etkisi beş akışın beşinde aynı yönde: taban kalkınca bulunabilirlik düşüyor, kayıp artıyor. Öngörünün etkisi küçük ve beş akışın birinde yön değiştiriyor.
Kayıp oranında politikanın etkisi öngörününkinin 2,09 katı: medyanda 1,44 puana karşı 0,69 puan. Bulunabilirlikte oran daha da büyük, 5,42. Yani fark yaratan şey modeli değiştirmek değil, modelin çıktısıyla ne yaptığınız.
Bu dizinin ana fikirlerinden biri de bu: tahmin motorunu değiştirmek az şey değiştirir, politikayı değiştirmek çok şey değiştirir. Dördüncü yazıda aynı şeyi başka bir yerden görmüştük. Kuralı Lumoda’ya en çok yaklaştıran şey öngörü değil, tabanın yüksekliğiydi.
Daha iyi öngörü neden sonuca dönüşmedi?
LightGBM öngörüde kuraldan açıkça isabetli. Tabanı da kuralınkiyle aynı. Yine de bulunabilirlikte kuralın önüne geçemedi: beş akışın dördünde geride. Beşinde de daha çok stokla bitiriyor. Dördüncü yazının ölçütüyle bakarsak bu bir kazanç değil: daha çok stokla biraz daha az bulunabilirlik.
Nedenini bu deneyden söyleyemiyoruz. Söyleyebildiğimiz şu: veri ortalamada seyrek değil, model de öngörüde kuraldan iyi. Üç kolda da depo aynı sınırda çalışıyor; açık toplama tavanı haftaların %94,4’ünde dolu.
Pars’ın bu konudaki cümlesi kısa:
— Öngörü rafa kendi kendine gitmez. Arada taban var, beden bölüşümü var, depoda ne olduğu, haftalık tavan, koli kuralı var. Öngörü bu zincirin ilk halkası. İlk halkayı iyileştirmek zincirin sonunu kendiliğinden değiştirmiyor.
Daha iyi öngörünün hangi halkada kaybolduğunu ayrıca ölçmedik.
Bir dürüstlük notu daha. Lumoda sentetik bir veri seti ve talebi bilinen kurallarla üretiliyor. Teoride bu, modelin işine yarayabilirdi: örüntüyü keşfedip gerçek hayatta olacağından daha iyi görünebilirdi. Öngörüde gerçekten iyi göründü, sonuçta değil. Gerçek bir zincirin verisinde iki taraf da değişebilir. Biz bunu ölçmedik.
Peki ML hiç mi işe yaramıyor?
Tablodaki bir satır modelin lehine: toplama maliyeti. Yalnız LightGBM kuraldan 180.260 TL, LightGBM + taban 67.580 TL ucuz. Beş akışa bakınca yalnız LightGBM beşinde, LightGBM + taban dördünde kuraldan ucuz. Yayımlanan müşteri akışında, yani tablodaki akışta, satışa dönme süresi de en kısa yalnız LightGBM’de.
Yani yalnız LightGBM “yanlış” değil, sadece başka bir noktada duruyor: daha az mal gönderiyor, daha az toplama maliyeti çıkarıyor, daha çok satış kaybediyor. Hangisinin doğru olduğu brüt kârınıza ve maliyetlerinize bağlı. Transfer dizisindeki getiri hesabının burada da yapılması gerekir.
Benim çıkarımım şu: mağaza–option düzeyinde tahmin kurmak bu veride zor değildi, model öngörüde kuralı açıkça geçti. Ama bu deneyde sonucu öngörünün isabetinden çok, öngörünün üstüne kurulan politika oynattı. Model kurmak isterseniz kurun. Ama önce politikanızı düzeltin: tabanı, ne kadar stok taşıyacağınızı. Kayıp oranında oradaki etki iki kat büyük.
Sizin verinizde zor olan
Bu yazıda doğrulama tablosu öngörüyü satışa karşı ölçtü; ilk pazartesinin tablosu ise gerçek talebe karşı. İkincisini yapabildik, çünkü Lumoda’da raf boşken gelip giden müşteri de bir yerde yazılı duruyor. Sizin verinizde öngörüyü ancak satışa karşı ölçebilirsiniz. Satış da raf boşken düşük görünür. Raf boşken düşen satışı iyi öngören bir model doğrulama tablosunda başarılı görünür, rafa yine az mal gönderir.
İkincisi karar anı. Modeli geçmiş tablolarla eğitirsiniz, ama pazartesi sabahı özellikleri canlı sistemden hesaplarsınız. İkisi aynı sayıyı vermezse model eğitimde görmediği bir dünyada karar verir. Biz oyundan önceki bir pazartesi 66.559 fiziksel çiftte iki yolun aynı özellikleri birebir ürettiğini denetledik. Gerçek bir zincirde geç işlenen transferler, iadeler ve sayım düzeltmeleri bu iki yolu sessizce ayırır.
Son yazıda başarının nasıl ölçüleceğine bakacağız. Bu yazıdaki tablolara orada bir kez daha döneceğiz, çünkü içlerindeki ölçütlerden biri yalan söylüyor. Lumoda’yla aradaki 3,32 puanın nerede açıldığına da orada bakacağız.