Teknik

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ı
LightGBM2,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:

KuralLightGBM
Öngörü155.732202.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ı.

KuralYalnız LightGBMFark
Bulunabilirlik%65,10%63,21−1,89 puan
Kayıp oranı%38,89%40,79+1,90 puan
Gönderilen adet1.543.0821.473.543−69.539
Dört ayın sonunda mağaza stoğu311.819299.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:

  1. Öngörüyü kim üretiyor: geçen haftanın satışı mı, LightGBM mi?
  2. Ö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ı:

KuralLightGBM + tabanYalnız LightGBM
Bulunabilirlik%65,10%65,00%63,21
Kayıp oranı%38,89%39,35%40,79
Satışa dönme7,5 gün7,5 gün7,2 gün
Gönderilen adet1.543.0821.508.6901.473.543
Dört ayın sonunda mağaza stoğu311.819331.606299.711
Toplama maliyeti7.673.800 TL7.606.220 TL7.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çütMedyan fark5 akışın kaçında
Bulunabilirlik−0,33 puan4’ünde eksi
Kayıp oranı+0,69 puan4’ünde artı
Dört ayın sonunda mağaza stoğu+19.866 adet5’inde artı
Toplama maliyeti−16.430 TL4’ünde eksi

Politikanın etkisi: yalnız LightGBM eksi LightGBM + taban. Öngörü aynı, taban kalkıyor.

ÖlçütMedyan fark5 akışın kaçında
Bulunabilirlik−1,79 puan5’inde eksi
Kayıp oranı+1,44 puan5’inde artı
Dört ayın sonunda mağaza stoğu−16.655 adet3’ünde eksi
Toplama maliyeti−112.680 TL5’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.

Yazan: Sabri Suyunu