Tüm yazılar
Veri Otomasyonu 6 dk okuma

Multi-Product Demand Forecasting: ARIMA, Prophet ve LSTM Karşılaştırması

Binlerce ürün için talep tahmini çerçevesi: ARIMA, Prophet ve LSTM karşılaştırması, aralıklı talep, taban çizgisi ve walk-forward doğrulama rehberi.

#machine-learning #time-series #forecasting #python #lstm #prophet

Envanter planlaması üzerine çalıştığım projelerde en sık duyduğum soru şu: "Talep tahmini için en iyi model hangisi — ARIMA mı, Prophet mi, yoksa LSTM mi?" Deneyimime göre sorunun kendisi hatalı. Birkaç yüz, hatta binlerce ürün içeren bir katalogda her ürün için ayrı model kurmak, parametrelerini ayarlamak ve bakımını yapmak pratikte mümkün değil. İhtiyacınız olan tek bir "kazanan" model değil; ürünleri talep desenine göre sınıflandıran, her adayı taban çizgisiyle kıyaslayan ve ürün başına uygun yöntemi otomatik seçen bir tahmin çerçevesi.

Bu yazıda kendi projelerimde oturttuğum çerçeveyi adım adım anlatacağım: talep desenine göre sınıflandırma, taban çizgisi disiplini, üç model ailesinin gerçekçi karşılaştırması, zaman serisi tahmini için doğru değerlendirme düzeni ve üretime alma. Kod örnekleri pandas, numpy, statsmodels ve scikit-learn ile çalışır durumda; kendi verinize kolayca uyarlayabilirsiniz.

Önce Ürünleri Talep Desenine Göre Sınıflandırın

Modelden önce veri hazırlığı gelir. Ürün ana verisi neredeyse her projede kirlidir: aynı ürün farklı tedarikçi kodlarıyla iki üç ayrı satırda yaşar ve satış geçmişi yapay olarak bölünür. Bu bölünmüş serilerle kurulan her model, gerçekte var olmayan bir "düşük hacimli" talep görür. Bu yüzden işe fuzzy matching ile kayıt eşleştirme yaparak mükerrer ürün kodlarını birleştirmekle başlıyorum. Tatil takvimi, promosyon dönemleri ve fiyat değişiklikleri gibi dış sinyalleri de tahminden önce bir veri zenginleştirme pipeline'ı ile serilere ekliyorum; bu adım özellikle regresör kabul eden modellerde karşılığını veriyor.

Veri temizlendikten sonra ilk iş, her seriye aynı gözle bakmayı bırakmak. Pratikte üç ana desen görüyorum:

  • Düzgün talep: hemen her dönemde satış var, oynaklık makul. Klasik zaman serisi modellerinin rahat ettiği bölge.
  • Yavaş hareket eden / düzensiz talep: satış görece sık ama miktarlar dalgalı; dikkatli metrik seçimi gerektirir.
  • Aralıklı (intermittent) talep: dönemlerin çoğu sıfır, arada bir sipariş geliyor. Yedek parça ve uzun kuyruk ürünlerinin tipik hali.

Sınıflandırma için Syntetos-Boylan yaklaşımını kullanıyorum: ortalama talep aralığı (ADI) ve talep büyüklüğünün varyasyon katsayısının karesi (CV²):

import pandas as pd
import numpy as np

def talep_deseni(seri: pd.Series) -> str:
    # Syntetos-Boylan siniflandirmasi: ADI ve CV kare esikleri
    talepli = seri[seri > 0]
    if len(talepli) < 2:
        return 'yetersiz-veri'
    adi = len(seri) / len(talepli)              # ortalama talep araligi
    cv2 = (talepli.std() / talepli.mean()) ** 2
    if adi < 1.32 and cv2 < 0.49:
        return 'duzgun'
    if adi >= 1.32 and cv2 < 0.49:
        return 'aralikli'    # intermittent: Croston ailesine yonlendir
    if adi < 1.32:
        return 'duzensiz'
    return 'topakli'

desenler = satislar.groupby('urun_kodu')['adet'].apply(talep_deseni)
print(desenler.value_counts())

Aralıklı talepte klasik ARIMA'nın zorlanmasının nedeni basit: ARIMA sürekli ve düzenli bir süreç varsayar; serinin çoğu sıfır olunca model ya sıfıra yapışır ya da anlamsız salınım üretir. Croston ailesi (Croston, SBA, TSB) ise talebi ikiye ayırır: sipariş geldiğinde ne kadar geliyor ve iki sipariş arası ne kadar sürüyor. Bu iki bileşeni ayrı ayrı üstel düzeltmeyle tahmin ettiği için aralıklı serilerde tipik olarak çok daha kararlı sonuç verir.

Taban Çizgisi Kurmadan Model Konuşmayın

Deneyimimde en çok tekrarladığım kural bu: bir modelin "iyi" olduğunu ancak basit bir taban çizgisini geçtiğinde söyleyebilirsiniz. Kurulması dakikalar süren üç taban çizgisi her projede masada olmalı:

  • Naive: gelecek dönem = son gözlenen değer.
  • Mevsimsel naive: gelecek dönem = geçen yılın aynı dönemi. Güçlü mevsimselliği olan perakende serilerinde şaşırtıcı derecede zor geçilir.
  • Hareketli ortalama: son k dönemin ortalaması; gürültülü ama trendsiz serilerde sağlam bir çıpa.

Bu disiplinin bir yan ürünü de MASE metriğidir: modelin hatasını naive tahminin hatasına oranlar. 1'in altındaki değer "taban çizgisinden iyi" demektir ve ölçekten bağımsız olduğu için binlerce ürünü tek tabloda kıyaslamayı mümkün kılar.

Taban çizgilerinin bir faydası daha var: veri sorunlarını erken yakalarlar. Mevsimsel naive'in bile tutturamadığı bir seri gördüğümde önce modeli değil, veriyi sorgularım — çoğu zaman kayıp bir promosyon kaydı, birleşmemiş bir ürün kodu ya da değişen bir birim çıkar ortaya.

ARIMA, Prophet ve LSTM: Hangisi Ne Zaman?

ARIMA / SARIMA

Düzgün talepli, yeterli geçmişi olan serilerde hâlâ ilk tercihim. Trendi ve mevsimselliği fark alma ile açıkça modellediği için davranışı öngörülebilir, katsayıları yorumlanabilir. Zayıf yanı ölçek: her seri için ayrı derece seçimi gerekir; otomatik derece arama ile bu aşılabilir ama binlerce seri ciddi işlem süresi demektir. Çoklu mevsimsellik ve hareketli tatiller de SARIMA'da zorlayıcıdır.

Prophet

Prophet'i güçlü mevsimsellik, belirgin tatil etkileri (bayramlar gibi hareketli takvim olayları dahil) ve eksik ya da aykırı gözlem içeren serilerde tercih ediyorum. Seriyi trend, mevsimsellik ve tatil bileşenlerine ayırdığı için çıktısı iş tarafına anlatılabilir; az ayarla makul sonuç vermesi de çok ürünlü senaryoda pratik bir avantaj. Buna karşılık aralıklı taleple arası iyi değildir ve varsayılan ayarlarla trend kırılmalarına fazla iyimser uyum sağlayabilir.

LSTM

LSTM'in gerçekten kazandığı yer tek tek seriler değil, binlerce ilişkili seriyi birlikte öğrenen global modellerdir: uzun geçmiş, zengin ek değişkenler ve seriler arası ortak örüntüler varsa doğrusal olmayan ilişkileri yakalayabilir. Ama dürüst olalım: haftalık ya da aylık frekanslı, birkaç yıllık tipik envanter serilerinde bu koşullar çoğunlukla oluşmaz. Deneyimimde LSTM'in bakım maliyeti — veri hazırlama, hiperparametre ayarı, eğitim altyapısı, tekrarlanabilirlik — getirisini çoğu envanter probleminde aşıyor. Hangi modelin kazanacağı tamamen veriye bağlıdır; bu yüzden karar kişisel tercihle değil, bir sonraki bölümdeki düzenekle verilmeli.

Doğru Değerlendirme: Walk-Forward ve Metrikler

Zaman serisinde rastgele eğitim/test bölmesi yasaktır: gelecekteki gözlemler eğitime sızar ve gerçekte asla elde edemeyeceğiniz skorlar görürsünüz. Doğru düzen, ileriye doğru zincirleme (walk-forward / rolling origin) doğrulamadır: belli bir kesime kadar eğit, sonraki ufku tahmin et, kesimi ilerlet, tekrarla.

import pandas as pd
from statsmodels.tsa.statespace.sarimax import SARIMAX
from sklearn.metrics import mean_absolute_error

def walk_forward(seri: pd.Series, ilk_egitim: int, ufuk: int = 4):
    # Ileriye dogru zincirleme (rolling origin) dogrulama
    y_gercek, y_model, y_naive = [], [], []
    for kesim in range(ilk_egitim, len(seri) - ufuk + 1, ufuk):
        egitim = seri.iloc[:kesim]
        test = seri.iloc[kesim:kesim + ufuk]
        model = SARIMAX(egitim, order=(1, 1, 1),
                        seasonal_order=(0, 1, 1, 52),
                        enforce_stationarity=False,
                        enforce_invertibility=False).fit(disp=False)
        y_model.extend(model.forecast(steps=ufuk))
        y_naive.extend([egitim.iloc[-1]] * ufuk)   # naive taban cizgisi
        y_gercek.extend(test)
    mae_m = mean_absolute_error(y_gercek, y_model)
    mae_n = mean_absolute_error(y_gercek, y_naive)
    return mae_m, mae_n, mae_m / mae_n   # oran < 1 ise model kazandi

mae_model, mae_naive, oran = walk_forward(haftalik_seri, ilk_egitim=104)

Bu döngüde eğitim penceresi her adımda büyüyor (genişleyen pencere); yapısı hızla değişen serilerde sabit uzunlukta kayan pencere de deneyebilirsiniz. Binlerce ürüne ölçeklerken kesim sayısını sınırlamak ve modelleri ürün bazında paralel koşturmak, işlem süresini yönetilebilir tutmanın en pratik yoludur.

Metrik seçiminde üç pratik kural:

  • MAE yorumlaması en kolay olan; "ortalama kaç adet şaşıyoruz" sorusunun cevabı.
  • RMSE büyük hataları daha sert cezalandırır; stok tükenmesinin maliyeti yüksekse tercih nedeni olabilir.
  • MAPE'den kaçının: sıfır satışlı dönemlerde payda sıfırlanır ve metrik patlar. Aralıklı talebin bol olduğu kataloglarda MAPE tablosu yanıltıcıdır; ölçekten bağımsız kıyas gerekiyorsa MASE kullanın.

Üretime Alma: Çerçeveyi Otomatikleştirin

Binlerce ürünlük bir sistemde model seçimi bir toplantı kararı değil, kodun kendisinin verdiği bir karardır. Benim kurduğum düzen şöyle çalışıyor:

  • Her ürün önce talep desenine göre sınıflanır; aralıklı seriler doğrudan Croston ailesine gider.
  • Kalan seriler için aday modeller (taban çizgileri, SARIMA, Prophet, gerekirse global bir model) walk-forward düzeneğinde yarıştırılır; ürün başına şampiyon, taban çizgisini geçemiyorsa taban çizgisinin kendisi seçilir.
  • Tahmin ufku tedarik süresiyle hizalanır: karar dört hafta sonrasına bakıyorsa modeli on iki haftalık ufukla değerlendirmenin anlamı yoktur.
  • Yeniden eğitim planlama döngüsüne bağlanır — tipik olarak haftalık ya da aylık — ve her koşuda skorlar loglanır; şampiyonun MASE değeri bozulmaya başladığında yarış otomatik tekrarlanır.

Bu yaklaşımın en büyük getirisi sürpriz değil, sürprizsizliktir: hiçbir ürün "modaya uyduğu için" LSTM'e, "alışkanlıktan" ARIMA'ya gitmez; her aday aynı sınavdan geçer.

Sonuç

Talep tahmininde tek doğru model aramak, deneyimime göre en pahalı yanlış sorudur. İşe yarayan şey bir çerçevedir: ürünleri desenlerine göre sınıflandırın, taban çizgilerini kurun, adayları walk-forward düzeneğinde ve sıfıra dayanıklı metriklerle yarıştırın, ürün başına şampiyonu otomatik seçin ve düzenli yeniden eğitimle canlı tutun. ARIMA, Prophet ve LSTM bu çerçevenin içinde birer adaydır; hangisinin kazanacağını veriniz söyler.

Benzer bir tahmin çerçevesini kendi ürün kataloğunuz için kurmak isterseniz veri otomasyonu çalışmalarım hakkında ana sayfadan fikir edinebilir, projenizi konuşmak için iletişim bölümünden bana ulaşabilirsiniz.