Bakalım modelimiz nasıl çıkacak?
import pandas as pd
import numpy as np
from scipy import stats
from datetime import datetime
from sklearn import preprocessing
from sklearn.model_selection import KFold
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score
import matplotlib.pyplot as plt
%matplotlib inline
# Örnek veriyi al
df = pd.read_csv("https://orcun.baslak.com/Orcun/SMV1.csv", encoding='utf-16',
sep=" ", header=0, decimal=".", parse_dates=['Generated On'])
# Tarih-saat sütünunu nsdatetime64'e çevir.
df['Generated On'] = pd.to_datetime(df['Generated On'], errors='coerce')
#Tarih saat bilgisini endeks olarak tanımla
df = df.set_index('Generated On')
#Sadece kullanacağımız sütunları seç
df = df[['PV Plant Power (kW)','Total Irradiance (W/m²)','PV module temperature (℃)']]
#Verisetinde "-" karakterleri var. Onları temizleyelim.
df.replace({'-': '0'}, regex=True, inplace=True)
#Nümerik değerleri Python'un anlayacağı hale çevirelim
cols=[i for i in df.columns if i not in ["Generated On"]]
for col in cols:
df[col]=pd.to_numeric(df[col])
#Verimiz ne halde bir bakalım :)
df.head()
Önce verilerimizi CSV dosyası olarak çektik. Verilerimizin kaynağı Huawei NetEco sistemi o sebeple Çin'e özel bazı tanımlamalar yapmamız gerekli. O sebeple read_csv dosyası içerisinde encoding belirtmek durumunda kaldık. Sizin kullanacağınız başka bir veri kümesinde buna ihtiyaç olmayabilir.
Daha sonra "Generated On" isimli sütunun tarih/saat verisi içerdiğini Python'a anlattık. Tarih/saat bazlı arama yapabilmemiz için nsdatetime64 veri tipine çevirdik.
Daha sonra kullanmayacağımız sütunları temizledik. Sade bir veri seti ile çalışmak hataları daha rahat görmemizi sağlar.
Huawei'nin siteminde boş veri noktaları için 0 yerine - karakteri kullanılıyor. Bunu 0'a dönüştürdük.
Daha sonra tarih/saat sütunu hariç diğer sütunları nümerik değer olarak Python'a tanıttık. Artık elimizdeki dataframe düzgün veri içeren sade kısa öz bir dataframe.
Şimdi bu dataframe'i bir ekrana çizdirip bakalım içeriği nasıl?
#Bi çizdirelim
df.plot(figsize=(25,5))
Grafikten gördüğümüz kadarıyla sistemde kısa sürede maksimum güce ulaşılıyor. Sistemde 680kWe eviricilerin limitli gücü ve bu güce 850 w/m2 gibi bir ışıma değerinde ulaşıyor. Bu değere ulaştıktan sonra da kesmeler başlıyor lakin bunun haricinde ışıma sensörü gece de veri veriyor. Demekki ışıma sensörünü bir elden geçirmek gerekli.
IoT ile uğraştığınızda elinizdeki veri setini pek çok kez düzeltmeniz gerekir keza sensörler epey hatalı veri verir. Ne yazık ki bu sistem de bunlardan birisi.
Şimdi elimizde kaç satır veri var ona bakalım?
df.shape
Satır sayısı : 8901 - Peki veri setimizde boş veri varmı önce ona bakalım
df.isnull().values.any()
Boş veri yokmuş. Bu güzel. Şimdi veri setimizi biraz düzenleyelim. Üretimin olmadığı gece saatlerini öncelikle eleyelim. Daha sonra da Üretimin 680kWe'ye ulaştığı tepe nokta olan 850 w/m2'leri eleyelim.
#Üretim 1'den büyükse (yani gündüzse) seç.
df = df[df['PV Plant Power (kW)'] > 1]
#Işımanın 850'den yüksek olduğu yerleri analizden çıkart.
df = df[df['Total Irradiance (W/m²)'] < 850]
#Ebatları alalım :)
df.shape
Geriye regresyon analizinde kullanılabilir 3034 adet satır kaldı. Şimdi bir kez daha verimizin grafiğini çizdirip gece değerlerinin gittiğini görelim.
#Bakalım gece değerleri gitti mi?
df.head()
Şimdi piyasada YAPAY ZEKA (!) olarak adlandırılan ama 1805'den beri hayatımızda olan lineer regresyon analizimize geçelim :) Önce üretim ve ışımanın lineer olup olmadığına scatter plot üzerinden bakalım
#Verimizin dağılımını scatter plot üzerinde görelim
plt.scatter(df['Total Irradiance (W/m²)'], df['PV Plant Power (kW)'])
Veri gayet lineer ama sensörden hatalı verilerin alındığı günler de mevcut. Sensör bazen doğru olmayan veriler veriyor. Şimdi elimizdeki veri setini çalışma ve test etme olarak 3'e bölelim. Train'de çalıştırıp Test'de test edelim. Sonra bu veri setlerini kendi aralarında karıştırıp birbirlerine karşı deneyelim (bunun da havalı adı KFold-Validation ama siz 3'e böldük birinde öğrendiğimizi diğerinde test ettik gibi düşünebilirsiniz)
#Güç ve ışıma değerini birbirinden ayıralım
Power = pd.DataFrame(df['PV Plant Power (kW)'])
Irradiance = pd.DataFrame(df['Total Irradiance (W/m²)'])
#Modelimizi belirleyelim
model = LinearRegression()
#KFold-Validation'u yapalım
scores = []
kfold = KFold(n_splits=3, shuffle=True, random_state=42)
for i, (train, test) in enumerate(kfold.split(Irradiance, Power)):
model.fit(Irradiance.iloc[train,:], Power.iloc[train,:])
score = model.score(Irradiance.iloc[test,:], Power.iloc[test,:])
scores.append(score)
#Ne çıktı?
print(scores)
Neredeyse %90'lık bir tutturma oranı. Bu gerçekten başarılı. Şimdi modeli tüm veri seti üzerinden oluşturalım. Modelimiz lineer olduğu için y=ax+b'de ki a(slope) ve b(intercept) katsayılarını bulmaya çalışıyoruz.
#Lineer regresyonumuzu uygulayıp slope/intercept değerlerimizi alalım
slope, intercept, r_value, p_value, std_err = stats.linregress(df['Total Irradiance (W/m²)'], df['PV Plant Power (kW)'])
#Slope eğimimiz (a) değeri
slope
#Intercept (b) değeri
intercept
#r² değeri bizim modelimizin gerçeğe ne kadar uygun olduğunu söyler
r_value**2
Burada ortaya çıkan modelimiz y = ax+b'nin a ve b değişkenleri. y = Power, x = Irradiance, a = slope, b = intercept. Bildiğimiz lineer denklem. Özetle burada lineer regresyon formülümüz Power = 0.752xIrradiation - 11.066 Şimdi bu lineer denklem sonuçlarını scatter plot üzerinde gösterelim.
#Modelimizi oluşturalım
def power_prediction(irradiance):
return slope * irradiance + intercept
#Modelimizi hesaplatalım
fitLine = power_prediction(df['Total Irradiance (W/m²)'])
#Sonuçları çizdirelim
plt.scatter(df['Total Irradiance (W/m²)'], df['PV Plant Power (kW)'])
plt.plot(df['Total Irradiance (W/m²)'], fitLine, c='r')
plt.xlabel("Irradiance")
plt.ylabel("Power")
plt.show()
Irradiance değerinin yüksek olup üretimin düşük olduğu anlar mevcut. Bu durumda tesiste karlanma da olmuş olabilir sensör hatası da olabilir. Veri kümesinin geneline baktığımızda sensörün arada sırada hatalı veriler verdiğini biliyoruz. Burada bu hataları düzeltebilirim daha sağlıklı bir regresyon modeli almak adına ama over-fitting denen hataya düşeceğimi bildiğim için yapmıyorum. Veri kümesi bir senelik olsaydı sadece aylık bazda farklı regresyon modelleri kullanırdım keza kışın panellerin kar altında kalması ile yazın sıcaklarında ortaya çıkan verim kayıpları farklılıkları tek modelde kurgulamak doğruluğumuzu azaltır.
Sektördeki yapay-zeka-hede-hödö kısmı burada bitiyor. Biz bir adım daha ileri gidip bir de polinom deneyelim.
#Verileri tek boyutlu hale getirelim
x = np.array(Irradiance).ravel()
y = np.array(Power).ravel()
#Polinom hesaplama aralığını belirleyelim
xp = np.linspace(0, 850, 850)
#Polinomu çözelim
p4 = np.poly1d(np.polyfit(x, y, 3))
#Çözümü çizdirelim
plt.scatter(x, y)
plt.plot(xp, p4(xp), c='r')
plt.xlabel("Irradiance")
plt.ylabel("Power")
plt.show()
#Bu modelin r² değeri ne çıktı?
r2 = r2_score(y, p4(x))
print(r2)
Bu arada bahsetmedim; r2 skoru modelin gerçeğe yakınlığını ölçen bir değişkendir. Polinomda da lineer'e çok yakın bir başarı elde ettik o sebeple polinom kullanmaya gerek duymuyorum (keza verimizin lineer olduğunu biliyorum; göstermek için bu kısmı tasarladım).
Lineer modelimiz ile polinom modelimiz arasında bir fark yok. Şimdi lineer modelimiz ile devam edelim. Rastgele bir gün için bakalım değerlerimiz tutacak mı?
#Tarih aralıklarını belirleyelim
start_date = '13-03-2019'
end_date = '14-03-2019'
mask = (df.index > start_date) & (df.index <= end_date)
#Aralığı dataframe'e uygulayalım
df = df.loc[mask]
#Elimizdeki ışıma değerleri için modeli hesaplayıp yeni bir sütuna yazalım
df['Power Prediction (kW)'] = power_prediction(df['Total Irradiance (W/m²)']) #
Sonra da bu elde ettiğimiz değişkenin bir grafiğini çizelim.
#bi çizdirelim bakalım :D
df.loc[:,['Power Prediction (kW)','PV Plant Power (kW)','Total Irradiance (W/m²)']].plot(figsize=(25,5))
Bakın, görüyorsunuz. Diyecek birşey yok :) Kendi tahmin algoritmamızı yaptık :) Sensör hatası sebebi ile 08:00-10:00 arası saatlerde ve 16:00-20:00 arası saatlerde beklenen üretim gerçekleşenden yukarı yönlü olarak sapmış ama üretim toplamlarına baktığımızda bu çok minik bir hata.
Bu gerçekleştirilen çalışma çok basit bir çalışma. Bu çalışmaya panel sıcaklığı da eklenebilir, günün saatlerindeki değişimlere göre kategorik veriler eklenebilir, aylık bazda da multi-regresyon modelleri kullanılabilir. Eklenebilir de eklenebilir ama şunu fark edeceksiniz; siz değişken ekledikçe model bazı noktalarda sapıtmaya başlayacak. O sebeple ne kadar sade o kadar iyi. Elinizde bir senelin güzel bir üretim verisi alıp kendiniz test edebilirsiniz.
Lineer regresyonun tarihi 1805'lere dayanıyor. Yani 200 yıldır hayatımızda olan bu model son birkaç yıldır IoT ve Endüstri 4.0 ile "yapay zeka", "akıllı cart curt" olarak hayatımıza katıldı.
Bugünlerde gördüğünüz sözde "akıllı" pek çok girişim aslında hiç de akıllı değil.
Bir tesisin bir yıllık verisi üzerinde çalışıp bir lineer regresyon kurguladığınız durumda bu regresyondan sapmaları kolayca yakalayıp "aaaaa biz yapay zeka yapıyoruz hede hödö" diyerek 200 yıllık lineer regresyonu AI olarak satabilirsiniz. :)
Bu yaptığımızı Excel'de kurgulayıp Goal-Seek ile veya grafik çizdirip "Trend Line" ile de yapabilirdik ama Python ile yapmak daha havalı :) Kod olunca malum yapay zekaya daha çok benziyor. :D