17 Ekim 2017 Salı

Keras LSTM ile Zaman Serisi Tahmini

Daha önceki bir yazımda ARIMA ile zaman serisi tahminine dair bir örnek paylaşmıştım. Bu yazı kapsamında ise Keras LSTM katmanı kullanarak zaman serisi tahmini yapan bir uygulama gerçekleştireceğim. LSTM ile ilgili daha ayrıntılı bilgi almak için, benim de bu yazıya referans olarak kullandığım derindelimavi adresindeki yazıyı okuyabilirsiniz. 

Uygulamamız için kullanacağımız veri seti ARIMA örneğindeki ile aynı, 1949-1961 yılları arasında aylara göre taşınan yolcu sayılarından oluşmakta.


LSTM 'nin açılımı Long Short-Term Memory , ve bir çeşit RNN (Recurrent Neural Network) yapısında bir sinir ağı modeli. Bu modelde bir hafıza hücresi de kullanılarak bir önceki zamandan gelen bilgi sonrakine aktarılabiliyor. Zaten zaman serilerinde istenen şey de zamana bağlı bir değişkenin önceki değerlerine bakarak geleceği tahmin etmek. Şimdi yavaş yavaş koda başlayalım ve ilk olarak veri setimizi okuyalım.
import pandas as pd
import numpy as np
import matplotlib.pylab as plt 
import matplotlib.patches as mpatches
from keras.layers.core import Dense,Activation,Dropout,Flatten,Reshape
from keras.layers import LSTM
from keras.models import Sequential
from sklearn.preprocessing import MinMaxScaler

data_orjinal = pd.read_csv('AirPassengers.csv')
data_orjinal = data_orjinal['#Passengers']


LSTM veri ölçeğine son derece bağımlı bu sebeple verimizi 0-1 arasına ölçeklememiz/normalize etmemiz lazım, en son ters dönüşüm ile tekrar gerçek ölçeğe çevireceğiz.
scaler = MinMaxScaler(feature_range=(0,1))
ts = scaler.fit_transform(data_orjinal)

Şimdi ise veri setimizi eğitim ve test için parçalara ayıralım. Daha önceki keras sınıflandırma örneğinde cross-validation ile daha sağlıklı bir değerlendirme yapılacağından bahsetmiştik, zaman serisi problemi için ise verilerin sırası önemli olduğundan bu şekilde bir rastgele parçalara ayırma işlemi gerçekleştirmiyoruz. Verisetini LSTM için uygun girdi formatına çevirip, eğitim ve test verilerini oluşturuyoruz. (144 aylık veri mevcut, 70'ini eğitim için ayırdık).
timestep=3
X=[]
Y=[]

data = ts

for i in range(len(data)-timestep):
    X.append(data[i:i+timestep])
    Y.append(data[i+timestep])

X = np.asanyarray(X)
Y = np.asanyarray(Y)

X = X.reshape((X.shape[0],X.shape[1],1))


k = 70
Xtrain = X[:k,:,:]
Ytrain = Y[:k]

Xtest = X[k:,:,:]
Ytest = Y[k:]

timestep değişkeni giriş verisinin büyüklüğünü belirliyor. Bu değeri 3 ayarladık, böylece önceki 3 değere bakarak sonraki değer tahmin edilmeye çalışılacak. İki LSTM katmanını 0.2'lik Dropout katmanı ile birlikte modelimize ekleyelim. Dropout katmanı overfitting 'i yani sistemin eğitim verisini aşırı ezberlemesini engellemek için kullanılan bir katman. 
model = Sequential()
model.add(LSTM(64,batch_input_shape=(None,timestep,1),return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(32,return_sequences=False))
model.add(Dropout(0.2))
model.add(Dense(1))

model.compile(loss='mse',optimizer='rmsprop')
model.fit(Xtrain, Ytrain, batch_size=512, epochs=50)

Modelimizi kurduk ve eğitim verisi ile ağı eğittik. Artık tahmin işlemi yapıp sonuçları elde edebiliriz. Bu noktada tahmin edilen değerleri ters dönüşüm ile yeniden ölçekleyeceğimizi hatırlatmak istiyorum.
Ypred = model.predict(X)

Ypred = scaler.inverse_transform(Ypred)
Ypred = Ypred[:,0]

Ve son olarak gerçek değerler ile tahmin edilen değerleri karşılaştıralım.
Yreel = data_orjinal[timestep:].values

plt.plot(Yreel,label='Yreel',color='blue')
plt.plot(Ypred,label='Ypred',color='red')

blue_patch = mpatches.Patch(color='blue', label='Yreel')
red_patch = mpatches.Patch(color='red', label='Ypred')
plt.legend(handles=[blue_patch,red_patch])
plt.title('RMSE: %.4f'% np.sqrt(sum((Ypred-Yreel)**2)/len(Yreel)))
plt.show()


RMSE hata oranını grafiğin üstünde yazdırdık, gerçek değer ile tahmin edilen değerin benzer grafik gösterdiğini söyleyebiliriz. Daha iyi bir karşılaştırma için daha önceki ARIMA ile zaman serisi inceleme yazımızda elde ettiğimiz grafiği de paylaşmak istiyorum.
RMSE hata değerine bakacak olursak, LSTM ile ARIMA'ya kıyasla gerçeğe daha yakın sonuç elde ettik. 

Böylece Keras ile LSTM ağ yapısını kullanarak zaman serisi tahmininin nasıl yapılacağına dair bir örnek uygulama gerçekleştirmiş olduk.

Ve son olarak tüm kodları bir arada paylaşıyorum...
"""
Created on Mon Oct 16 17:50:41 2017

@author: IbrahimD
"""
import pandas as pd
import numpy as np
import matplotlib.pylab as plt 
import matplotlib.patches as mpatches
from keras.layers.core import Dense,Activation,Dropout,Flatten,Reshape
from keras.layers import LSTM
from keras.models import Sequential
from sklearn.preprocessing import MinMaxScaler

data_orjinal = pd.read_csv('AirPassengers.csv')
data_orjinal = data_orjinal['#Passengers']

scaler = MinMaxScaler(feature_range=(0,1))
ts = scaler.fit_transform(data_orjinal)
          
seed = 7
np.random.seed(seed)

timestep=3
X=[]
Y=[]

data = ts

for i in range(len(data)-timestep):
    X.append(data[i:i+timestep])
    Y.append(data[i+timestep])

X = np.asanyarray(X)
Y = np.asanyarray(Y)

X = X.reshape((X.shape[0],X.shape[1],1))


k = 70
Xtrain = X[:k,:,:]
Ytrain = Y[:k]

Xtest = X[k:,:,:]
Ytest = Y[k:]

model = Sequential()
model.add(LSTM(64,batch_input_shape=(None,timestep,1),return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(32,return_sequences=False))
model.add(Dropout(0.2))
model.add(Dense(1))


model.compile(loss='mse',optimizer='rmsprop')
model.fit(Xtrain, Ytrain, batch_size=512, epochs=50)

Ypred = model.predict(X)

Ypred = scaler.inverse_transform(Ypred)
Ypred = Ypred[:,0]

Yreel = data_orjinal[timestep:].values

plt.plot(Yreel,label='Yreel',color='blue')
plt.plot(Ypred,label='Ypred',color='red')

blue_patch = mpatches.Patch(color='blue', label='Yreel')
red_patch = mpatches.Patch(color='red', label='Ypred')
plt.legend(handles=[blue_patch,red_patch])
plt.title('RMSE: %.4f'% np.sqrt(sum((Ypred-Yreel)**2)/len(Yreel)))
plt.show()



8 yorum:

  1. Güzel bir çalışma, teşekkür

    YanıtlaSil
  2. Merhaba,

    Paylaşımınız için teşekkürler. Yalnız veri ölçeklenirken scaler.fit_transform(data_orjinal.values.reshape(-1, 1))
    şeklinde bir kullanım gerekli. Böylece pandas frame'ini 1D yerine 2D'ye reshape yapabiliriz. Aksi halde fit_transform metodu 1D dizi kabul etmiyor. Bilginize.

    YanıtlaSil
  3. burada illa bir tarih zaman gibi featıre olması gerekli değil dimi önemli olan bizim zaman pulumuz aslında??

    YanıtlaSil
    Yanıtlar
    1. Belirli bir geçmişteki veriyi ağa girdi olarak veriyoruz ve bu girdiye karşılık bir sonuç üretiliyor. LSTM katman tipinde bir hafıza var nihayetinde ve buna göre geçmiş bilgisi de bir şekilde kullanılıyor. Yani burada zaman bilgisini direkt vermiyoruz, girdiyi kendimiz oluşuruyoruz dikkat ederseniz, bizim örneğimizde son 7 girdi değeri ağa iletilmekte.

      Sil
  4. Hocam paylaşım için öncellikle teşekkürler.

    Bende rüzgar hızı tahmin işlemi yapıyorum ve bunu yaparken iki tane mantıksal hatalar oluştu.

    1-) Eğitim ve Test hata oranı (MSE) 0.03 civarında sonuç vermekte. Fakat başarım ise hata ile ters orantılı durumunda olması lazımken onda da eğitim ve test hatası gibi başarım da 0.03 civarı değer vermekte.

    2-) Yukarıda dediğim gibi sistemin hata fonksiyonu MSE 0.03 civarı değer verdirirken RMSE oranı ise 0.5 civarlarında.

    Bu ikisinin nedeni nedir biliyorsanız cevaplarsanız sevinirim. Tekrardan Teşekkürler.

    YanıtlaSil
    Yanıtlar
    1. Soruyu tam anlayamadım. Başarımdan kasıt ne?

      RMSE = sqrt(MSE)
      0.54 = sqrt(0.3)
      Yani MSE 0.3 için karekökünün 0.5 çıkması normal.

      Sil
  5. merhaba, RMSE sonucunun 60 olması kötü değil mi? bunu nasıl iyileştirebiliriz?

    YanıtlaSil