Bu blog yazısında, derin öğrenme teknikleri kullanılarak elektrik tüketim tahmini yapmayı ele alıyoruz. LSTM (Long Short-Term Memory) mimarisini kullanarak zaman serisi verilerini analiz edecek ve gelecekteki enerji tüketimini öngören bir model geliştireceğiz. Elektrik tüketim tahmini, enerji yönetimi ve sürdürülebilirlik açısından kritik bir konu olup, bu çalışmada veri ön işleme, model eğitimi ve performans değerlendirme adımlarını detaylı bir şekilde inceleyeceğiz.
Proje Hangi Sorunu Çözmeyi Hedefliyor?
Elektrik tüketiminin tahmin edilmesi, enerji üretim planlaması, şebeke yönetimi ve sürdürülebilir enerji kullanımı açısından kritik bir konudur. Geleneksel tahmin yöntemleri, karmaşık tüketim desenlerini yeterince iyi modelleyemediği için hatalı tahminler üretebilir. Bu proje, LSTM tabanlı bir yapay zeka modeli kullanarak daha doğru ve güvenilir elektrik tüketim tahmini yapmayı hedeflemektedir.
Kullanılan Teknoloji
Bu projede veri çekme ve veri ön işleme işlemleri PyCharm ortamında gerçekleştirilmiştir. Elektrik tüketim verileri, EPİAŞ Şeffaflık Platformu API’si kullanılarak elde edilmiş ve uygun formatta düzenlenmiştir.
Model kurma ve eğitim aşamaları, yüksek hesaplama gücü gerektirdiği için Google Colab Pro üzerinde L4 GPU kullanılarak gerçekleştirilmiştir. Bu sayede, modelin daha hızlı eğitilmesi ve büyük veri kümeleriyle daha verimli çalışması sağlanmıştır.
Projede kullanılan programlama dili Python olup, veri analizi ve derin öğrenme için NumPy, Pandas, Matplotlib, TensorFlow ve Keras gibi popüler kütüphanelerden yararlanılmıştır.
Varsayımlar Neler?
Bu proje aşağıdaki varsayımlar üzerine inşa edilmiştir:
1.Veri Kalitesi: Modelin eğitimi için kullanılan elektrik tüketim verileri güvenilir ve eksiksizdir.
2.Zaman Serisi Örüntüleri: Elektrik tüketiminde belirli dönemsel ve mevsimsel desenler bulunmaktadır ve LSTM bu desenleri öğrenebilir.
3.Dış Etkenler: Model, sadece geçmiş elektrik tüketimi verilerine dayanarak tahmin yapacaktır. Hava durumu, ekonomik faktörler gibi dış etkenler varsayılan senaryoda göz ardı edilmektedir.
4.Eğilim: Elektrik tüketimi zaman içinde istikrarlı bir eğilim gösterir ve ani değişimlerin etkisi sınırlıdır
Veri çekme ve ön işleme.
Veriler, EPİAŞ Şeffaflık Platformu tarafından sağlanan API aracılığıyla elde edilmiştir. Bu platformdan veri alabilmek için öncelikle üye olunması ve ardından API dokümantasyonunun incelenmesi gerekmektedir. (https://seffaflik.epias.com.tr/documentation/web-service-user-guidimport
Epiaş Ticket Alma
import requests
url = "https://giris.epias.com.tr/cas/v1/tickets"
headers = {
"Content-Type": "application/x-www-form-urlencoded",
"Accept": "application/json"
}
data = {
"username": "****.com",
"password": "****"
}
response = requests.post(url, headers=headers, data=data)
if response.status_code == 201:
print("Ticket alındı:", response.text)
else:
print("Hata:", response.status_code, response.text)
Epiaş Veri Çekme
import requests
import datetime
import pandas as pd
# API URL
url = "https://seffaflik.epias.com.tr/electricity-service/v1/consumption/data/realtime-consumption"
headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"TGT": "TGT-18582929-Ys9fqCoNm4KFC1zLj2pZo8i3nxxaE2NFDIIVhHPveSk8Gbmu1nLeH-9aBsfd-pEIkY4-cas-7bc549fccd-tjszv"
}
# Başlangıç ve bitiş yılı , 2021 - 2024 yılı veri çekimi. api 1'er yıllık veri gönderiyor.
start_year = 2021
end_year = 2024
all_data = []
for year in range(start_year, end_year + 1): # 2024 dahil
start_date = f"{year}-01-01T00:00:00+03:00"
end_date = f"{year}-12-31T23:59:59+03:00"
print(f"Veri çekiliyor: {start_date} - {end_date}")
payload = {
"startDate": start_date,
"endDate": end_date
}
response = requests.post(url, headers=headers, json=payload)
if response.status_code == 200:
data = response.json().get("items", [])
all_data.extend(data)
print(f"{year} yılı için {len(data)} kayıt alındı.")
else:
print(f"Hata: {response.status_code}, {response.text}")
# 2025 Yılı için **1 Ocak - 31 Ocak** arası veriyi çekelim , 2025 ocak ayı için ayrı bir istek gönderdim.
start_date = "2025-01-01T00:00:00+03:00"
end_date = "2025-01-31T23:59:59+03:00"
print(f"Veri çekiliyor: {start_date} - {end_date}")
payload = {
"startDate": start_date,
"endDate": end_date
}
response = requests.post(url, headers=headers, json=payload)
if response.status_code == 200:
data = response.json().get("items", [])
all_data.extend(data)
print(f"2025 Ocak ayı için {len(data)} kayıt alındı.")
else:
print(f"Hata: {response.status_code}, {response.text}")
# Gelen verileri dataFrame çevirip ,api den gelen sutün isimleri ile birlikte excel'e kaydettik
df = pd.DataFrame(all_data)
if not df.empty:
df = df[["date", "time", "consumption"]]
excel_filename = "epias_elektrik_tuketim.xlsx"
df.to_excel(excel_filename, index=False, engine="openpyxl")
print(f"Toplam {len(df)} satır veri kaydedildi: {excel_filename}")
Özellik Mühendisliği ve Veri Ön işleme
import pandas as pd
import holidays
#Veri ön işleme ve tip dönüşümleri#######
df = pd.read_excel("epias_elektrik_tuketim.xlsx")
df_copy = df.reset_index() #index
df_copy["date"] = pd.to_datetime(df_copy["date"], errors="coerce")
df_copy["date"] = df_copy["date"].dt.tz_localize(None) # UTC bilginisi kaldırm
# Aykırı değer analizi
def outlier_thresholds(dataframe, col_name, q1=0.15, q3=0.85):
quartile1 = dataframe[col_name].quantile(q1)
quartile3 = dataframe[col_name].quantile(q3)
interquantile_range = quartile3 - quartile1
up_limit = quartile3 + 1.5 * interquantile_range
low_limit = quartile1 - 1.5 * interquantile_range
return low_limit, up_limit
def check_outlier(dataframe, col_name):
low_limit, up_limit = outlier_thresholds(dataframe, col_name)
if dataframe[(dataframe[col_name] > up_limit) | (dataframe[col_name] < low_limit)].any(axis=None):
return True
else:
return False
check_outlier(df_copy,"consumption")
# 0 - NaN değer kontrolü
problematic_rows = df_copy[(df_copy["consumption"] == 0) | (df_copy["consumption"].isna())]
print(problematic_rows)
-------------------------------------------------------------------------------------------------
# Özellik mühendisliği - > günün saati , Haftanın günü , Yılın ayı , Bir önceki güne göre tüketim farkı ve resmi tatiler özellik olarak eklendi
df_copy["hour"] = df_copy["date"].dt.hour + 1 # Günün saati
df_copy["weekday"] = df_copy["date"].dt.weekday # Haftanın günü (0 = Pazartesi, 6 = Pazar)
df_copy["month"] = df_copy["date"].dt.month # Yılın ayı (1-12)
df_copy["diff"] = df_copy["consumption"].diff()
turkey_holidays = holidays.Turkey() # Türkiye için resmi tatiller
df_copy["is_holiday"] = df_copy["date"].apply(lambda x: 1 if x in turkey_holidays else 0)
df_copy = df_copy.dropna() # NaN içeren satırları sil
df_copy = df_copy.drop(columns=["index","time"])
df_copy.to_excel("epias_elektrik_tuketimV1.xlsx")
Google Colab Pro ile model geliştirme
#Excel verisi google drive'a atıp, google colab pro ile oraya bağlandık.
from google.colab import drive
drive.mount('/content/drive')
data_path = "/content/drive/MyDrive/Colab Notebooks/epias_elektrik_tuketimV1.xlsx"
df = df.drop(columns=["Unnamed: 0","date"])
##Standart Fonksiyonlar
def split_data_by_time(df, train_frac=0.7, val_frac=0.15,test_size=720):
n = len(df) # Toplam veri uzunluğu
train_size = int(n * train_frac) # Eğitim veri seti boyutu
val_size = int(n * val_frac) # Doğrulama veri seti boyutu
# Test setini son 720 saat olarak ayarla
train_size = n - (val_size + test_size) # Eğitim setini yeniden ayarla
# Veriyi böl
train_data = df.iloc[:train_size]
val_data = df.iloc[train_size:train_size + val_size]
test_data = df.iloc[-test_size:] # Son 720 saatlik veriyi test olarak ayır
return train_data, val_data, test_data
train_df, val_df, test_df = split_data_by_time(df)
print(f"Eğitim veri boyutu: {len(train_df)}")
print(f"Doğrulama veri boyutu: {len(val_df)}")
print(f"Test veri boyutu: {len(test_df)}") # 720 olmalı
----------------------------------
def scale_data(train_df, val_df, test_df, feature_columns, target_column):
#veri setini ölçeklendirmek için kullanılır. Min-Max Normalizasyonu ile özellikleri ve hedef değişkeni [0,1] aralığına çeker, böylece LSTM gibi sinir ağları daha iyi öğrenir.
scaler_x = MinMaxScaler()
scaler_y = MinMaxScaler()
scaler_x.fit(train_df[feature_columns])
scaler_y.fit(train_df[[target_column]])
train_x = scaler_x.transform(train_df[feature_columns])
val_x = scaler_x.transform(val_df[feature_columns])
test_x = scaler_x.transform(test_df[feature_columns])
train_y = scaler_y.transform(train_df[[target_column]])
val_y = scaler_y.transform(val_df[[target_column]])
test_y = scaler_y.transform(test_df[[target_column]])
return train_x, val_x, test_x, train_y.flatten(), val_y.flatten(), test_y.flatten(), scaler_x, scaler_y
----------------------------------------------------------
def create_timewindow(X, y, time_steps=1):
#zaman serisi verisini LSTM modellerde kullanılabilecek şekilde zaman pencerelerine böler.Modelin geçmiş verileri öğrenmesini sağlar.Önceki time_steps kadar girişten sonra bir hedef (label) tahmini oluşturur.Zaman serisi tahmini için diziyi X (girdi) ve y (çıktı) olarak hazırlar.
Xs, ys = [], []
for i in range(len(X) - time_steps):
v = X[i:(i + time_steps)]
Xs.append(v)
ys.append(y[i + time_steps])
return np.array(Xs), np.array(ys), time_steps
-------------------------------------------------------------------------
def plot_training_history(history, train_loss='loss', train_metric='accuracy', val_loss='val_loss', val_metric='val_accuracy'):
#modelin eğitim sürecini görselleştirmek için kullanılır.Eğitim (training loss) ve doğrulama (validation loss) kayıplarını (loss) çizer. Eğitim (training accuracy) ve doğrulama (validation accuracy) doğruluklarını çizer.Modelin öğrenme sürecini analiz etmeye yardımcı olur.Overfitting (aşırı öğrenme) veya underfitting (yetersiz öğrenme) gibi problemleri tespit etmeyi sağlar.
plt.figure(figsize=(10, 5))
plt.plot(history.history[train_loss], label='Training Loss')
plt.plot(history.history[val_loss], label='Validation Loss')
plt.title('Training and Validation Loss Over Epochs')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.show()
plt.figure(figsize=(10, 5))
plt.plot(history.history[train_metric], label=f"Training: {train_metric}")
plt.plot(history.history[val_metric], label=f"Validation: {val_metric}")
plt.title(f'Training and Validation {train_metric} Over Epochs')
plt.xlabel('Epochs')
plt.ylabel(f'train_metric')
plt.legend()
plt.show()
----------------------------------------------------------------------------
def evaluate_predictions(model, X_train, y_train, X_val, y_val, X_test, y_test, scaler_y):
#eğitilmiş bir modelin tahminlerini değerlendirir ve gerçek değerlerle karşılaştırarak hata hesaplar.Model ile tahmin yapar:model.predict(X_train) → Eğitim seti için tahmin yapar.model.predict(X_val) → Doğrulama seti için tahmin yapar.model.predict(X_test) → Test seti için tahmin yapar.Ölçeklendirilmiş (normalize edilmiş) tahminleri geri çevirir (inverse_transform)Önceden MinMaxScaler() ile ölçeklenmiş verileri, orijinal değerlerine çevirir.Gerçek ve tahmin edilen değerler arasındaki Mean Squared Error (MSE) hesaplar:MSE (Ortalama Kare Hatası) → Modelin doğruluğunu ölçer (Daha düşük MSE = Daha iyi model).Sonuçları ekrana yazdırır.Gerçek ve tahmin edilen değerleri döndürerek görselleştirme veya daha fazla analiz yapmayı sağlar.
y_train_pred_ = model.predict(X_train, verbose=0)
y_val_pred = model.predict(X_val, verbose=0)
y_test_pred = model.predict(X_test, verbose=0)
true_y_train_pred = scaler_y.inverse_transform(y_train_pred_)
true_y_val_pred = scaler_y.inverse_transform(y_val_pred)
true_y_test_pred = scaler_y.inverse_transform(y_test_pred)
true_y_train = scaler_y.inverse_transform(y_train.reshape(-1, 1))
true_y_val = scaler_y.inverse_transform(y_val.reshape(-1, 1))
true_y_test = scaler_y.inverse_transform(y_test.reshape(-1, 1))
train_rmse = root_mean_squared_error(true_y_train, true_y_train_pred)
val_rmse = root_mean_squared_error(true_y_val, true_y_val_pred)
test_rmse = root_mean_squared_error(true_y_test, true_y_test_pred)
print("Train rMSE:", train_rmse, "Validation rMSE:", val_rmse, "Test rMSE:", test_rmse)
return true_y_train, true_y_train_pred, true_y_val, true_y_val_pred, true_y_test, true_y_test_pred, train_rmse, val_rmse, test_rmse
---------------------------------------------------------------------------------
Başlangıç modeli kurma
# bağımlı ve bağımsız değişkenler
feature_columns=[col for col in df.columns if col != 'consumption']
target_column='consumption'
----------------------------------------------
# train,validasyon ve test veri setlerini standartlaştırma
train_scaled_x, val_scaled_x, test_scaled_x, train_scaled_y, val_scaled_y, test_scaled_y, scaler_x, scaler_y = scale_data(train_df, val_df, test_df, feature_columns, target_column)
----------------------------------------------------------
# time window
X_train, y_train, time_steps = create_timewindow(train_scaled_x, train_scaled_y, time_steps = 5)
X_val, y_val, time_steps = create_timewindow(val_scaled_x, val_scaled_y, time_steps = 5)
X_test, y_test, time_steps = create_timewindow(test_scaled_x, test_scaled_y, time_steps = 5)
-----------------------------------------------------------
#LSTM modelinin giriş katmanına verilecek giriş veri biçimini belirler
input_shape = (X_train.shape[1], X_train.shape[2])
model = Sequential([
LSTM(50, input_shape=input_shape,
kernel_regularizer=l2(0.001)),
Dense(1)
])
optimizer = Adam(learning_rate=0.001)
model.compile(optimizer=optimizer,
loss='mean_squared_error',
metrics=['mse'])
model.summary()
early_stopping = EarlyStopping(
monitor='val_loss',
patience=20,
verbose=1,
restore_best_weights=True)
# İlk model başlatma ve sonuçları
history = model.fit(
X_train, y_train,
epochs=1000,
validation_data=(X_val, y_val),
batch_size=32,
verbose=1,
callbacks=early_stopping
)
train_loss = model.evaluate(X_train, y_train, verbose=0)
val_loss = model.evaluate(X_val, y_val, verbose=0)
test_loss = model.evaluate(X_test, y_test, verbose=0)
print(f"Train Loss: {train_loss[0]}", f"Validation Loss: {val_loss[0]}", f"Test Loss: {test_loss[0]}")
------------------------------------------------------------------------
Başlangıç model sonuçları :
Train Loss: 0.0033276465255767107 Validation Loss: 0.007493197917938232 Test Loss: 0.004928132519125938
Train rMSE: 1994.7619759611532 Validation rMSE: 3080.244224690701 Test rMSE: 2468.9416120812807
Hiperparametre Optimizasyonu
# Hiperparametre Optimizasyonu için arama uzayı oluşturulması
#Batchnormalization :LSTM gibi derin ağlarda gradyan kaymasının önlenmesine yardımcı olur.
Özellikle büyük veri setlerinde ve uzun sekanslı modellerde eğitimi hızlandırır ve modelin genelleştirme kapasitesini artırır.
#Dropout :her eğitim adımında rastgele bazı nöronları devre dışı bırakarak modelin aşırı öğrenmesini (overfitting) önler.Özellikle küçük veri setlerinde overfitting riski yüksektir ve Dropout ile bu risk azaltılabilir.
def build_model(hp):
model = Sequential()
model.add(Input(shape=input_shape))
for i in range(hp.Int('num_layers', 1, 5)):
model.add(LSTM(units=hp.Int('units_' + str(i), min_value=32, max_value=512, step=32),
return_sequences=(i < hp.Int('num_layers', 1, 5) - 1)))
model.add(BatchNormalization())
model.add(Dropout(hp.Float('dropout_' + str(i), min_value=0.0, max_value=0.5, step=0.1)))
model.add(Dense(1))
model.compile(optimizer=Adam(learning_rate=hp.Float('learning_rate', 1e-4, 1e-2, sampling='LOG')),
loss='mean_squared_error',
metrics=['mse'])
return model
Random Search Tuner- En iyi model kaydetme
#Random Search, belirlenen hiperparametre aralıklarından rastgele kombinasyonları seçerek en iyi modeli bulmaya çalışır.max_trials=15 ifadesi 15 denemeden sonra sonlandırmayı söyler. Eğtim süresini kısa tutmak için böyle bir yol izlendi.
#val_loss 5 epoch boyunca iyileşmezse eğitim durdurulacak.
#En iyi ağırlıklar (restore_best_weights=True) geri yüklenerek modelin aşırı öğrenmesi önlenecek.
random_search_tuner = RandomSearch(
build_model,
objective='val_loss',
max_trials=15,
executions_per_trial=1,
directory='hyperparam_tuning',
project_name='lstm_tuning',
overwrite=True)
early_stopping = EarlyStopping(
monitor='val_loss',
patience=5,
verbose=1,
restore_best_weights=True)
#Random Search Tuner’ı (random_search_tuner) başlatır ve en iyi hiperparametreleri bulmak için modeli farklı kombinasyonlarla eğitir.Her model eğitildiğinde,eğitim veri seti (X_train, y_train) ile eğitilir.Validasyon veri seti (X_val, y_val) ile test edilir.Val_loss takip edilir, en düşük val_loss’u veren model seçilir.
random_search_tuner.search(X_train, y_train,
epochs=500,
validation_data=[X_val, y_val],
callbacks=[early_stopping])
En iyi model ve hiperparametreler
best_hps.values
dump(best_hps, 'best_hps_lstm.joblib')
best_model = random_search_tuner.get_best_models(num_models=1)[0]
Hiperparametre Optimizasyonu Sonuçları
LSTM modelinde gerçekleştirdiğim hiperparametre optimizasyonu, modelin doğruluğunu önemli ölçüde artırdı. Aşağıda, başlangıç modelinin ve hiperparametre optimizasyonu sonrası modelin karşılaştırmalı RMSE (Root Mean Squared Error) değerlerini bulabilirsiniz:
| Model | Train RMSE | Validation RMSE | Test RMSE |
|---|---|---|---|
| Başlangıç LSTM Modeli | 1994.76 | 3080.24 | 2468.94 |
| Hiperparametre Optimizasyonu Sonrası | 2742.88 | 2474.24 | 1337.67 |
Train RMSE biraz artsa da (1994.76 → 2742.88), bu durum modelin daha iyi genelleştiğini ve overfitting’in azaldığını gösteriyor.
Bu gelişmeler, hiperparametre optimizasyonunun modelin genelleştirme performansını artırdığını ve test setinde daha iyi tahminler yapmasını sağladığını gösteriyor.
720 saatlik Test verisi için tahmin sonuçları

Modeli nasıl iyileştirebiliriz ?
Özellik Üretme:
Hava durumu (sıcaklık, nem, yağış) gibi ek değişkenler eklenebilir.Gün içindeki tüketim değişikliklerini modellemek için gecikmeli değişkenler (lag features) oluşturulabilir .Hareketli ortalamalar ve trend bilgileri ekleyerek modelin geçmiş eğilimleri öğrenmesini kolaylaştırabiliriz.
LSTM Katmanlarını Optimize Edin:
Katman sayısını artırarak veya azaltarak en iyi derinlik seviyesini bulunabilir.Farklı pencere uzunluklarını deneyerek en uygun olanı belirlenebilir.
Alternatif ve Hibrit Modeller
CNN katmanları ile zaman serisi içindeki kısa vadeli desenleri yakalayıp, ardından LSTM ile uzun vadeli bağımlılıkları öğrenebilir. LSTM yerine, özellikle uzun vadeli tahminlerde Transformer veya Temporal Fusion Transformer (TFT) gibi modeller daha başarılı olabilir.LSTM tahminlerini geleneksel makine öğrenme modelleriyle(XGBoost veya Random Forest ile Ensemble) birleştirerek hata oranlarını düşürebilirsiniz.
📩 Geri Bildirimleriniz Değerli!
Bu yazıda LSTM ile elektrik tüketim tahmin modelimi geliştirirken edindiğim deneyimleri paylaştım. Eğer yazıyla ilgili düşüncelerinizi paylaşmak, model hakkında tartışmak veya önerilerde bulunmak isterseniz :
📧 E-posta: thinkoptimize@yandex.com
