Yapay Zeka Yolculuğu II

2019 yılında yapay zekayı öğrenmeyi kendime hedef olarak belirlediğimde bu kadar hızlı ilerleyebileceğimi tahmin etmemiştim. Bugün Mart ayının sonundayız ve yapay zeka yolculuğu bölüm bir‘de bahsettiğim süreçlere epey hakimim.

Bölüm bir’de verinin sağlıklı birşekilde alınması ve daha sonra kolayca kullanılmak üzere temizlenip, aklanıp paklanıp saklanmasından bahsetmiştim ki devamında geliştirdiğim kodlar şuanda bunu yapabiliyor.

İkinci aşamada ise makina öğrenmesinin temeli olan regresyon analizlerinin ufak tefek entegre edilmesi var. Bu aşamada şikayetçi olduğum bir konu var; lineer regresyon yapan her firmanın “bizim yazılımımız yapay zeka” diyerekten ortaya zıplaması.

Yok öyle birşey; basit bir modeli uyarlıyorsun işte. Şimdi gelin basit bir lineer regresyon modeli ile ışımaya göre bir güneş enerjisi santralinin çıkış gücünü tahmin edelim.

Aşağıda üzerinde çalıştığım jupyter notebook dosyasını bulabilirsiniz. İçine kendimce notlar aldım ama sorunuz olursa yorumlar kısmından sorun.

Not: CSV hala indirilebilir durumda. Direkt indirip çalışabilirsiniz.

Lineer/Poly Regresyon İle GES Üretimlerini Modellemek

Bakalım modelimiz nasıl çıkacak?

In [27]:
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() 
Out[27]:
PV Plant Power (kW) Total Irradiance (W/m²) PV module temperature (℃)
Generated On
2019-02-27 00:00:00 0.0 0.0 -3.1
2019-02-27 00:05:00 0.0 28.9 -3.1
2019-02-27 00:10:00 0.0 0.0 -3.1
2019-02-27 00:15:00 0.0 0.0 -3.1
2019-02-27 00:20:00 0.0 0.0 -3.1

Ne yaptık?

Ö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?

In [2]:
#Bi çizdirelim
df.plot(figsize=(25,5)) 
Out[2]:
<matplotlib.axes._subplots.AxesSubplot at 0x73a560f0>

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?

In [3]:
df.shape
Out[3]:
(8901, 3)

Satır sayısı : 8901 – Peki veri setimizde boş veri varmı önce ona bakalım

In [4]:
df.isnull().values.any()
Out[4]:
False

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.

In [5]:
#Ü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
Out[5]:
(3034, 3)

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.

In [6]:
#Bakalım gece değerleri gitti mi?
df.head()
Out[6]:
PV Plant Power (kW) Total Irradiance (W/m²) PV module temperature (℃)
Generated On
2019-02-27 08:50:00 1.971 56.7 -4.6
2019-02-27 08:55:00 2.585 300.1 -4.2
2019-02-27 09:00:00 3.105 75.9 -4.1
2019-02-27 09:05:00 3.214 76.3 -4.0
2019-02-27 09:10:00 4.128 92.4 -3.9

Ş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

In [7]:
#Verimizin dağılımını scatter plot üzerinde görelim
plt.scatter(df['Total Irradiance (W/m²)'], df['PV Plant Power (kW)'])
Out[7]:
<matplotlib.collections.PathCollection at 0x6bcdc870>

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)

In [9]:
#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)
[0.8287854691298497, 0.8777587783295471, 0.8768398758391538]

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.

In [10]:
#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 
Out[10]:
0.752461081662071
In [11]:
#Intercept (b) değeri
intercept 
Out[11]:
-11.066787804106866
In [17]:
#r² değeri bizim modelimizin gerçeğe ne kadar uygun olduğunu söyler
r_value**2
Out[17]:
0.8619933678502559

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.

In [13]:
#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.

In [14]:
#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()
In [15]:
#Bu modelin r² değeri ne çıktı?
r2 = r2_score(y, p4(x)) 
print(r2)
0.8634209266921452

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ı?

In [19]:
#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.

In [23]:
#bi çizdirelim bakalım :D
df.loc[:,['Power Prediction (kW)','PV Plant Power (kW)','Total Irradiance (W/m²)']].plot(figsize=(25,5))
Out[23]:
<matplotlib.axes._subplots.AxesSubplot at 0x6bc253d0>

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.

Peki bu yapay zeka mı? Hayır değil 🙂

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.

Özetle

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. 😀

Bir sonraki adım? Tüm istatistiki kontrol mekanizmalarımızı bir framework haline getirip veri işleyen kodlar ile bütünleştirmek suretiyle tüm analizlerin doğru şekilde otomatik yapılmasını sağlamak. Bu yapay zeka mı? Değil. Lakin bundan sonrasının hızlı ilerleyeceğini öngörüyorum.

Üzerinde çalışmak isteyenler dosyayı buradan indirebilirler.

Selamlar,

1)https://orcun.baslak.com/yapay-zeka-yolculugu-ii/

References   [ + ]

1. https://orcun.baslak.com/yapay-zeka-yolculugu-ii/

İlk yorum yapan olun

Bir Cevap Yazın