EEG Sinyallerinden Makine Öğrenmesi ile Epilepsi Hastalığı Tespiti

Elif Nur Korkmaz
Kodluyoruz
Published in
16 min readFeb 17, 2020
https://giphy.com/gifs/stupid-smart-l44QzsOLXxcrigdgI/fullscreen

Herkese merhaba, ben Elif Nur Korkmaz. Bundan birkaç ay önce Kodluyoruz’un Microsoft ve Avrupa Birliği sponsorluğunda düzenlediği “Ankara Uygulamalı Veri Bilimi ve Makine Öğrenmesi Bootcamp”e katılma fırsatım oldu. Bu 1.5 aylık kurs boyunca bize Damla Dokuzoğlu hocamız veri biliminde istatistiğin nasıl kullanıldığı ve makine öğrenmesi üzerine eğitim verdi. Burdan kendisine ve bize bu fırsatı sunan herkese tekrar teşekkür ediyoruz :)

Bu yazıda sizlere Nur Aslıhan Karaman ile birlikte yaptığımız bitirme projemiz “EEG Sinyallerinin Python ile Analizi ve Makine Öğrenmesi Modelleri ile Epilepsi Hastalığının Tespiti”ni anlatacağım.

Öncelikle projemizde kullanılan ifadeleri açıklayalım.

Epilepsi (ya da sara) nöbeti (ya da krizi), sinir hücrelerinde geçici olarak meydana gelen anormal elektriksel aktivite sonucu beynin normal aktivitesinin bozulması ile oluşan klinik bir durumdur.

EEG, beynin hareket faaliyetlerini sinyallerle ölçen ve görüntüleyen elektroensefalografi olarak adlandırılan beyin görüntülemesidir.

Sizleri daha fazla bekletmeden projeye başlayalım.

https://giphy.com/gifs/memecandy-Ln2dAW9oycjgmTpjX9/fullscreen

Proje verimiz olan EEG sinyallerine kaggle’daki bu linkten erişebilirsiniz.
- Öncelikle projemizde kullanacağımız gerekli kütüphaneleri sırayla eklemeye başlayalım.

import numpy as np
import pandas as pd
import os
os.chdir('C:/Users/username/Downloads/EpilepticSeizureRecognition')#username'e kullanici adinizi yaziniz.

En temel 2 kütüphaneyi ekledikten sonra verimizi dataframe’e çevirip verimizdeki boş değer barındıran satırları dropna() ile silelim.

*Yeterince verimiz olduğu icin biz siliyoruz, boş verileri doldurmak için çeşitli yöntemler mevcut (Medyan ya da ortalama ile doldurmak veya verinin dağılımını çıkarıp o dağılımdan denk düşen değerle doldurmak vb.)

Verimizdeki ilk kolon “Unnamed” isminde bir kolon ve işimize yaramayacağını düşündüğümüz için onu da drop ile siliyoruz.

df=pd.read_csv(“Epileptic_Seizure_Recognition.csv”)
df=df.copy()
df=df.dropna()
df=df.drop(“Unnamed”,axis=1)
#axis=0 satır ,axis=1 kolon demektir yani ona verdiğimiz kolon bazinda silme islemi yapar
df.head() #verinin ilk 5 satırını ekrana basarak inceleyelim.
Şekil 1

*Verimiz bu haliyle gerçekten hiç anlaşılabilir değil :) Verimizin içeriği hakkında bilgileri kaggledan alıp iletiyorum.

“Referanstaki orijinal veri kümesi, her biri 100 dosya içeren 5 farklı klasörden oluşur ve her dosya tek bir konuyu / kişiyi temsil eder. Her dosya 23.6 saniyelik beyin aktivitesinin kaydıdır. Karşılık gelen zaman serileri 4097 veri noktasına örneklenir. Her veri noktası, EEG kaydının farklı bir zamandaki değeridir. Yani her biri 23.5 saniye boyunca 4097 veri noktasına sahip toplam 500 kişimiz var.

Her 4097 veri noktasını 23 parçaya böldük ve karıştırdık, her yığın 1 saniye boyunca 178 veri noktası içeriyor ve her veri noktası EEG kaydının farklı bir zamandaki değeri. Şimdi 23 x 500 = 11500 parça bilgimiz var (satır), her bilgi 1 saniye boyunca 178 veri noktası içeriyor (sütun), son sütun y {1,2,3,4,5} etiketini temsil ediyor.

Bu 179 kolon bilgisine yanıt olarak oluşan çıktı kolonu y’dir, Açıklayıcı değişkenler X1, X2,…, X178

y, 178 boyutlu giriş vektörünün kategorisini içerir. {1, 2, 3, 4, 5} ‘de özellikle y:
1 — Nöbet etkinliğinin kaydedilmesi
2 — Tümörün bulunduğu bölgeden EEG’nin kaydedilmesi
3 — Tümör bölgesinin beynin neresinde olduğunu belirler ve sağlıklı beyin alanından EEG aktivitesini kaydeder
4 — Hastanın gözleri kapalıyken EEG sinyalinin kaydedildiği anlamına gelir
5 -Hastanın gözleri açıkken EEG sinyalinin kaydedildiği anlamına gelir.

Sınıf 2, 3, 4 ve 5'e giren tüm denekler epileptik nöbet geçirmeyen deneklerdir. Sadece 1. sınıftaki denekler epileptik nöbet geçirir.“

Bu bilgileri de özetleyecek olursak elimizde 500 kişiden alınmış olan 23.6 saniyelik EEG sinyal örnekleri, kayıtları var ve 178 kolonun her birinde bu EEG sinyalinin oluşmasını sağlayan sinyal ölçücülerin ölçtüğü değerler var. Bizim veri setimizde 5 tane hedef değişkenimiz (sınıfımız) var yani her satır, kişinin EEG sinyalinin kaydedilme anındaki durumuna dair bilgi veriyor ve o kişinin EEG sinyalinin kaydedilirken bu 5 sınıftan birine ait olduğunu söylüyor.

Mesela bir satır için 178 tane sinyal ölçücünün değerleri kaydedilmiş ve ilgili değerler o kişinin gözü kapalıyken toplandığı için o satırın y kolonunda değer olarak “4” yazmaktadır yada bir kişinin sinyalleri tümörlü bölgeden toplandıysa y hedef değişkeni değeri “2” olarak etiketlenmiştir.

Biz bu projede kişinin gözlerinin açık yada kapalı olmasıyla değil yalnızca epilepsi hastası olmasıyla ilgilendiğimiz için bu 5 sınıfın içindeki 2–3–4–5 sınıflarını epilepsi hastası değil (sınıf 0) diye etiketleyip 1 numaralı sınıfı da epilepsi hastası diye etiketleyerek aslında ikili sınıflandırma yapmak üzere modelimizi eğiteceğiz.

Şekil 2

Yandaki kodu incelersek, y hedef değişkenimizde değeri 1'den farklı olanları “0” sınıfı olarak setliyoruz yani bu onların epilepsi hastası olmadığı anlamına geliyor.

İlgili sınıfa ait kaç tane örneğin olduğunu gösteren grafik.

Şimdi verimizi incelemeye devam edelim info () ile verimizin dataframe olduğunu kaç tane satır ve sütun içerdiğini ve içeriğinin tipini görebiliyoruz. Bir diğer metod olan describe() metoduyla verimizin her kolonu için bir takım istatiksel bilgilerine (adet, ortalaması, standart sapması, kolondaki en küçük değer ve en büyük değer, q1, q2, q3 değerleri) ulaşabiliyoruz.

Q1, q2, q3 değerleri bizim verisetimizi baz aldığımızda bu veri setindeki uç değerleri bulmamıza yarayan değerlerdir. Kısacası bir veri setinin çoğu IQR=q3-q1 olacak sekilde q1–1.5IQR ile Q3 +1.5IQR arasında dağılıyordur bu aralığa güven aralığı denir bu aralığın dışında kalan verilere ise uç değer marjinal değer, anomali yada outlier deriz.

Bu uç değerler bizim modelimizi etkiler, saptırır.Yani elimdeki verinin sınıfının yada değerinin ne olduğuna karar verirken çok uç bir örnek benim vereceğim kararı bozabilir.Dolayısıyla bu değerlerden kurtulmak isteyebiliriz ama biz bu projede tüm datayla eğitim yapacağız.

Şekil 3

Gelelim hedef değişkenimizi ayrı bir dataframe olarak ele almaya. Bunun amacı modelimizi eğitirken girdi ve çıktı değerlerini yani bir satır EEG sinyal değerlerini ve bu sinyalin hangi sınıfa ait olduğu bilgisini modelimize ayrı bilgiler olarak vermek. Böylece model, bu girdiler için bu çıktılar oluşuyor şeklinde eğitilebilir.

y = df[‘y’]
X = df.drop([‘y’], axis = 1)
X.head()
Şekil 4

Y hedef değişkenini X dataframe’inden sildikten sonra oluşan X dataframe’i

Şekil 5

Yan tarafta ise y kolonunu dataframe olarak aldıktan sonra ilk 5 değerini görüyoruz.

Şimdi elimizde X dataframe’inde 178 tane kolon var. Şimdi soru şu, biz modelimizde bu kolonların hepsini kullanacak mıyız? Modelin karmaşıklığını, dolayısıyla çalışma süresini azaltıp daha az eforla aynı verimi yakalamak için çeşitli yöntemler var.

Bunlardan birisi özellik seçimi (feature selection). Burada da farklı yöntemler var, şu an tüm kolonlarımız ile istatiksel modeller kurabileceğimiz Python modülü statsmodel modülündeki lojistik regresyon modeli kuracağız ve bu model bize kolonlarımız hakkında bilgi verecek. Şöyle ki eğer p value ifadesini daha önceden duyduysanız bu 178 kolon arasında p value değeri anlamlı çıkan kolonları seçiyor şeklinde özetleyebiliriz.

Eğer daha önceden bu ifadeyi duymadıysanız kısaca şöyle açıklayabiliriz. Bizim elimizdeki kolon bilgilerinin y hedef değişkenimi bulmam konusunda modelime hiç bir önemli katkısı yoktur (H0 hipotezi) ya da bu kolonlardan en az bir tanesinin benim y değişkenimi bulurken modelime anlamlı bir katkısı vardır. (H1 hipotezi). Bu p value, her kolon için hesaplandıktan sonra anlamlı ya da anlamsız diye adlandırılması için bir değer (alfa=güven aralığı) ile karşılaştırılır ve kısaca, kolonumuz için bulduğumuz p value’muz alfa değerinden küçük ise H1 hipotezi kabul edilir, bu kolon anlamlı deriz ve onu modelimizde kullanırız. Bu kısımlar istatistik bilgisine girdiği için fazla detaya girmeden anlatmaya çalıştım umarım kafamız karışmamıştır.

Şekil 6

Kurduğumuz Y modelinki her bir kolon için (X’ler) p değeri hesaplanır ve alfa ile kıyaslanır.

Şimdi gelelim lojistik regresyon modelimizi kurmaya ve p value’su değerli çıkan yani modelimiz için önemli bilgiler taşıdığını düşündüğümüz kolonlarımızı bulmaya.

https://giphy.com/gifs/1qYbgeTWuN4BUCVBts/fullscreen

Lojistik Regresyon Modeli Kurma

import statsmodels.api as sm
loj = sm.Logit(y, X) # X verisinden y yi öğren dedik.
loj_model = loj.fit() # Öğrenme işlemi burada yapılıyor
loj_model.summary() # Modelimizin özetini istedik

P value değeri anlamlı çıkan kolonlarımızı bulan kod;

a=len(X.columns) # X datasetinde kaç tane kolon var bilgisi
pvalues=[]
alpha=0.05 # P valuemuzun kıyaslanacağı güven aralığımız
for i in range(1,a):
if(loj_model.pvalues[i-1]<alpha): #Pvalue alfadan küçük mü bakılır
pvalues.append(loj_model.pvalues[i-1:i])#Küçük olanlar listelenir.
print(pvalues)
print(a)
#if bloğunda=Her kolonun p valuesunu alfa ile kiyaslariz alfadan küçük olanlar bizim için anlamlı olduğundan (H1 hipotezi kabul edilir) onları listede toplarız

Şekil 7
#anlamlı buldugumuz p valuelar ile tekrar stats ile model kurarız ve yine p value'ları değerli olanları alırız#ta ki x sayısı degismeyene dek bu işi tekrarlarızXsetimiz = pd.DataFrame(X,columns=[‘X5’,’X7',’X9',’X13',’X26',’X51',’X72',’X100',’X102',’X107',’X108',’X119',’X120',’X140',’X157',’X158'])loj = sm.Logit(y, Xsetimiz)
loj_model = loj.fit()
loj_model.summary()

Bu kod sonucunda belirlenen yeni ve daha anlamlı kolonlarımız yukarda Şekil 7 ‘da B bölümündedir. Şekil 7’ye baktığımız zaman 178 kolondan 7 kolona düştüğümüzü görebiliriz. Bizim modelimizi bulduğumuz bu 7 kolon ile eğitmek yeterli olacaktır, çünkü zaten hedefimizi bulma konusunda yalnızca bu 7 kolonun katkı sağladığını bulduk.

Multicollinearity

Tasarladığımız modelde her bağımsız değişkeni kullanamama sebebimiz olan bir durum daha vardır.Bu multicollinearity(çoklu bağlantı) problemidir.Nedir bu çoklu bağlantı problemi,şöyle ki bizim y bağımlı değişkenimizi bulmamız için gerekli gördüğümüz özellikler arasında birbiri içersinde doğrusal bağ bulunan özellikler olabilir.Mesela bir ev fiyatını tahminlerken evin büyüklüğü(m²) ile oda sayısı arasında doğrusal bir ilişki olabilir,evin büyüklüğü arttıkça oda sayısının da artacağına dair .Bu durumda modelimizin, bağımsız değişkenler arasındaki doğrusal ilişkiden etkilenmemesi ve yanlı bir tutum sergilememesi için yapılması gereken şey ,modelin içerisinde bu tarz birbiriyle doğrusal ilişki barındıran özelliklerden yalnızca bir tanesini kullanmamız gerekir.Dolayısıyla yukarıda p değerini anlamlı bulduğumuz kolonlar için bu çoklu doğrusallık değerlerine bakarız ve bu değer 10’dan küçükse bağımsız değişkeni modelimizde kullanabiliriz.Eğer bu değer 5’den büyük ve 10’a yakınsa burada bağımsız değişkenler birbiriyle ilişkilidir diyebiliriz.Bu durumdan modelimiz kötü anlamda etkileneceği için büyük değerli ilgili bağımsız değişkeni modelimizde kullanmayız.

import statsmodels.formula.api as smffrom patsy import dmatricesfrom statsmodels.stats.outliers_influence import variance_inflation_factory, X =dmatrices(“y ~ X13+X26+X51+X72+X102+X120+X140”, data=df, return_type= “dataframe”)vif = [variance_inflation_factor(X.values, i) for i in range(X.shape[1])]vif
Şekil 7.1— Multicollinearity Değerleri

Şimdi gelelim bu bulduğumuz “anlamlı” ve “birbiriyle ilişkisiz” kolonlarımızla modeller kurmaya ve bu modelleri kıyaslamaya.

Modelimize şu kolonlardan (X’ler) şunları (Y hedef değişkeni) öğren diyeceğimiz şekilde datayı bölelim, hazırlayalım, her yeni modele verilerimizi vermeden önce aşağıdaki “data hazırlama” kısmını çalıştırmamız lazım ki her yeni model temiz verilerle kurulsun.

Data hazırlama

Bu kısmı her yeni model kurulumundan önce 1 kez çalıştırırız ki her bir modeli birbirinden etkilenmeden temiz verilerle kuralım.

from sklearn.model_selection import train_test_split, cross_val_score, cross_val_predictdf=pd.read_csv(“Epileptic_Seizure_Recognition.csv”)df=df.copy()
df=df.dropna()
df=df.drop(“Unnamed”,axis=1)
a=len(df[‘y’])
for i in range(a):
if(df[‘y’][i] != 1):
df[‘y’][i]=”0"
y = df[‘y’]
X = df.drop([‘y’], axis = 1)
#asagidaki Xsetimizi,ard arda 2 kere model kurup en degerli p value' ya sahip olan X'leri seçerek oluşturduk (model kurduk p value'ları yüksek olanlarla tekrar model kurup tekrar en yüksek p value'ları aldık) Xsetimiz = pd.DataFrame(X,columns=‘X13’,’X26',’X51',’X72',’X102',’X120',’X140'])
X.head()
X_train,X_test,y_train,y_test=train_test_split(Xsetimiz,y,test_size=0.30,random_state=42)

Seçilen kolonların önem derecesine göre sıralayabiliriz.

Şekil 8

Soldaki görseli elde etmek için önce model kurulur ama ben burada örnek olması açısından yalnızca görseli (şekil 8 ve şekil 9) veren kodu paylaşıyorum, modellerimizi de kuracağız.

Importance = pd.DataFrame({“Importance”: rf_tuned.feature_importances_*100 }, index = X_train.columns)
Importance
Importance.sort_values(by = “Importance”, axis =0, ascending =True).plot(kind = “barh”, color =”r”)
plt.xlabel (“Değişken Önem Düzeyleri”)
Şekil 9

Model Değerlendirme — Kıyaslama Teknikleri

from sklearn.metrics import confusion_matrix, accuracy_score, classification_report

Şimdi kuracağımız birkaç modelden hangisinin daha iyi ya da hangisinin datamıza daha uygun olduğunu anlamamız için bir takım metrikler mevcut. Bu metriklerin başında Confusion Matrix (cm) dediğimiz bir matrix’ten yola çıkarak yapılan hesaplamalar var. Bu Confusion Matrix kısaca, verinin içinde “hasta” olarak etiketlenen veriyi benim kurduğum modelimin“hasta” olarak tahmin etmesi yada “hasta değil” olarak tahmin etmesi yada “hasta değil” verisini “hasta” yada “hasta değil” olarak tahmin etmesi gibi sonuçların bir tabloya aktarılması ve bunlar üzerinden modelin başarımının yorumlanmasıdır. Tablonun hesaplanması ve açıklaması aşağıda şekil 10’da gösterilmiştir.

Şekil 10 Confusion matrix

Konu Anlatımı: Bir modelin, elimdeki hedef değişkenin bizdeki gibi ikilik sistemden oluştuğunu varsaydığımızda epilepsi hastası olup olmamasını tahmin etme becerisini değerlendirmek üzere sadece accuracy’sine (modelin genel başarısına) bakmak yeterli değildir. “F-score, overall, recall” gibi diğer değerlere de bakmak gereklidir. Yukardaki tabloda “positive” diye geçen kısımlar aşağıda “yes”, “negative”ler aşağıda “no” olarak ele alındı. Gelin bunların ne demek olduklarına birlikte bakalım…

Accuracy : Genel olarak, sınıflandırıcı ne sıklıkla doğrudur?

= (TP+TN) / total = (100+50) / 165 = 0.91

Misclassification rate : Genel olarak, ne sıklıkta yanlıştır?

= (FP+FN) / total = (10+5) / 165 = 0.09

True Positive (TP) Rate (Recall) : Gerçekte evet olan veriyi, ne sıklıkta evet olarak tahmin ediyor? sorusunun cevabıdır.Yani evet olarak tahmin ettiklerimin ,gerçekten evet olanlara oranıdır.

= TP/actual yes(TP+FN) = 100/105 = 0.95

Precision: Evet diye tahmin ettiklerimin kaçı gerçekten evet,bilgisidir.

= TP / predicted yes(TP +FP) = 100/110 = 0.91

F1 Score: True positive rate ve precision’ın ortalamasıdır.

= (TP rate+Precision )/2= ((100/105)+(100/110))/2=0,93

#benim icin 1 leri (kişinin epilepsi olması) tahmin etmek mi önemli yoksa 0’ları (epilepsi hastası olmaması) tahmin etmek mi, ona göre bu yukardaki metrikler hangi modelde daha yüksek değer üretiyorsa o modeli seçerim. Üretilen değerler 1’e ne kadar yakınsa model o kadar iyidir dememizde bi mahsur yoktur. (ezberleme olayı hariç)

Model Tuning

Kurduğumuz modeli iyileştirme işlemine model tuning denir.Burada da çeşitli alternatifler olup biz şimdi grid search olarak isimlendirilen tekniği uygulayacağız.Grid search çalışma mantığı,modeli kurarken parametrelerin yalnızca bir değer ile kurmak yerine ,parametrelere farklı değerler/ aralıklar vererek parametrelerin birbiriyle olan her bir kobinasyonları için bir model kurulur ve bu modelin başarısı hesaplanır.En sonunda,bu kombinasyonlarla elde edilen modeller arasında en iyi model bulunur ve bu en iyi modeli bize veren en iyi parametreleri(best_parameter ) elde ederiz.

Bulduğumuz en iyi parametrelerle tekrar modelimizi kurarak,bizim verdiğimiz parametre kombinasyonu aralığımızdaki en başarılı/optimum modelimizi bulmuş oluruz.

Grid search de kullanılan parametreler,modeli kurmamıza yarayan parametrelerdir.Bunlara kendimiz değer girebiliriz yada default değerlerini kullanabiliriz.Örnek olarak “?RandomForestClassifier “ diyerek parametrelerin detaylarına bakalım;

Criterion : Düğümlere bölmenin kalitesini ölçme işlevi. Yani ilgili düğümde hangi bağımsız değişkeni koyacağımıza karar verme kriteridir.Desteklenen kriterler ,Gini safsızlığı için “gini” ve bilgi kazanımı için “entropi” dir.Gini yada entropi değeri daha uygun çıkan bağımsız değişken düğüme seçilir.Bir sonraki yapraklar bu düğümden oluşur.

Max_depth(default=None): Ağacın maksimum ne kadar derinlikte(aşağı doğru ilerlemesi)olacağı bilgisidir.Ağacı ,entropi 0 olana kadar ilerletirsek ezberleyebilir buna engel olmak adına bir noktada ağacın derinliğini kesebiliriz.

max_leaf_nodes:Bir düğümün maksimum kaç tane yaprağa bölüneceği

max_features: En iyi ayrımı ararken kaç tane bağımsız değişken (kolonlarımız) kullanacağı bilgisidir “Auto” deyince tüm bağımsız değişkenleri kullanır.

Min_samples_split(default=2): Modelin ,ilgili kolonu kaça bölerek ilerleyeceğimiz /kırılıma uğrayacağımız bilgisidir.

Mesela bir kişinin gelirini yaş bilgisine göre aciklamaya calisiyorum ve min_sample_split=2 dersem, elimdeki yaş verisini minimum ikiye bölüyor ve bunun üstünde kalanlar altında kalanlar şeklinde ilerliyor. Algoritma optimum bölme sayisini kendisi buluyor “yaş bilgisini kaça bölersem optimum bir ağaç kurarım “ gibi düşünebiliriz.

Şekil 11-min_sample_split=3 seçilmiş

Min_samples_leaf(default=1): En az 1 yaprak üret diyorum .Yani böldüğüm düğümlerin ucunda kaç tane sonuç yaprağı olacağını söylüyorum.

N_jobs= Paralel olarak çalıştırılacak iş sayısı.

Random_state=değer atarsak, atadığımız bu sayi indeksinde model kurulurken üretilen hep aynı random sayiları üretiriz.

Verbose=Eğitimde ve tahmin etme aşamasında ekrana ayrıntıyı basar.

N_estimators=Kaç tane ağaç kurulacağı bilgisidir.

Cv;Her yeni model kurma aşamasında tüm veri setini eğitim ve test olarak ayırmak üzere kaça böleceği bilgisidir.Mesela cv=10 demek, tüm veri setini rastgele 10 parçaya böler ve her 10 parçadan biri,modeli test etmek için kullanılırken geri kalan 9 parça ise eğitim verisi olarak kullanılır.Bu dağıtıma göre ilk model kurulduktan sonra eğitim için ayrılan 9 parçadan bir tanesi bu sefer yeni modelde test için kullanılır ve eski test parçası da dahil olmak üzere geri kalan 9 parça eğitim için kullanılır.Bu şekil de 10'a bölünmüş olan her parça ile hem eğitim hem test yapılmış olur.Bu yöntem modeli, verinin hep aynı parçasıyla eğitip hep aynı parçasıyla test etmesine engel olur, eğitim ve test veri çeşitliliğini artırarak ezberlemenin (overfitting) önüne geçmeye yarar.Aşağıda Şekil 11’de scikit-learn’ün kendi sayfasında paylaştığı görselde cv=5 seçilmiş.

Şekil 12

Şimdi bu bilgiler ışığında modellerimizi kurabiliriz.

1-) Decision Tree Algoritması

Hedef değişken ile özellik değişkenleri arasındaki ilişkiye tek tek bakar.

Root: Bağımsız değişkenlere göre verinin hiç parçalanmamış olduğu düğümdür.

Node: Bağımsız değişkenlerin farklı kombinasyonları icin sonuç değişkeniyle ilgili istatistikler bulunduran karar düğümleridir.

Amaç;en iyi ayrılmış yapraği bulmaktır.Yapraktaki entropiyi (belirsizliği) en düşük orana indiren yani sınıfların çok net biçimde ayrıştığı (%90 ,1 sınıfına ait veri var. %10 ,0 sınıfına ait veri var) yaprağı bulmayı hedefler.

Sklearn’un bize sundugu Decision tree classifier kütüphanesini import ederiz.from sklearn.tree import DecisionTreeClassifierfrom sklearn.metrics import confusion_matrix, accuracy_score, classification_reportcart = DecisionTreeClassifier()cart_model = cart.fit(X_train, y_train)cart_model #Modelin parametreleri hakkında bilgi verirDecisionTreeClassifier(class_weight=None, criterion=’gini’, max_depth=None,max_features=None, max_leaf_nodes=None,min_impurity_decrease=0.0, min_impurity_split=None,min_samples_leaf=1, min_samples_split=2,min_weight_fraction_leaf=0.0, presort=False, random_state=None,splitter=’best’)>y_pred = cart_model.predict(X_test) #yukarda default secilen parametreler ile modeli kurduk burda ise test verisini tahminletiyoruz.accuracy_score(y_test, y_pred) #default parametrelerle kurduğumuz modelin accuracysi (genel başarısı)0.9240579710144927print (classification_report (y_test, y_pred)) #default parametrelerle kurulan modelin diğer metrik bilgileri

“Criterion “ parametresine baktığımızda görüyoruz ki ana kökten bir alt düğümlere ayrılmak için karar mekanizması olarak gini kullanmış çünkü cart algoritması gini kullanır ve ana düğümden yalnızca iki tane yaprak /düğüm çıkmasına izin verir.

Şekil 13
confusion_mat = confusion_matrix(y_test, y_pred)accuracy = accuracy_score(y_test, y_pred)print(“Confusion matrix: \n”,confusion_mat)print(“\n Accuracy: “,accuracy)
Şekil 14
#Bu metrikleri biz kendimiz de pratik yapmak adına hesaplayabiliriz.print(“Acuracy:”,(567+2625)/3450)=0,9252 # Accuracy : (TP+TN) / total ,modelin genel dogruğuprint(“Misclasification”,(127+131)/3450) = # Missclassification rate(recall yada sensivity) : (FP+FN) / totalprint(“True positive rate”,567/(567+131))=0,812 # TP Rate : TP/actual yes (tp +fn)print(“precision”,567/(567+127))=0,817 # Precision: TP / predicted yes(tp+fp)print(“F score”,((567/(567+131))+(567/(567+127)))/2)=0,814 # (Tp rate+Precision)/2#benim icin 1 leri mi tahmin etmek önemli yoksa 0 larımı ona göre bu parametrelerden hangisi iyiyse onu seçerim#ilk yorumlama aşamasında bi accuracy'e bakarız

Model Tuning

Kurduğumuz modeli iyileştirme işlemine model tuning denir.Burada da çeşitli alternatifler olup biz şimdi grid search olarak isimlendirilen tekniği uygulayacağız.Grid search çalışma mantığı,modelin yukardaki cart_model yazdığımızda çıkan parametrelerini yalnızca bir değer ile denemek yerine parametrelere farklı değerler/ aralıklar vererek parametrelerin birbiriyle olan her bir kobinasyonları için bir model kurulur ve bu modelin başarısı hesaplanır.En sonunda,bu kombinasyonlarla elde edilen modeller arasında en iyi model bulunur ve bu en iyi modeli bize veren en iyi parametreleri (best_parameter ) elde ederiz.

Bulduğumuz en iyi parametrelerle tekrar modelimizi kurarak,bizim verdiğimiz kombinasyon aralığımızdaki en başarılı/optimum modelimizi bulmuş oluruz.

cart_grid = {“max_depth”: range(1,10), #1 den 10 a kadar olan değerleri alarak tek tek model kurar“min_samples_split”: list(range(2,50))} #2 ile 50 arasındaki değerler ile tek tek model kurarcart_ = DecisionTreeClassifier()cart_cv = GridSearchCV (cart, cart_grid, cv=10, n_jobs = -1, 
verbose =2)

#10 tane farklı train-test gruplarıyla eğitir n_jobs=-1 bu modelleri paralel çalışarak kur demektir.
cart_cv_model =cart_cv.fit (X_train, y_train)print(“En iyi parametreler:” + str(cart_cv_model.best_params_))En iyi parametreler:{‘max_depth’: 9, ‘min_samples_split’: 34}

Yani bu modeli max_depth:9 ve min_samples_split:34 olacak şekilde kurarsak bu modelin en iyi halini elde etmiş oluruz. O halde en iyi parametrelerle modelimizi tekrar kuralım.

cart = tree.DecisionTreeClassifier(max_depth= 9, min_samples_split =30) # en iyi parametreler ile tekrar modeli kuruyoruzcart_tuned =cart.fit(X_train, y_train)
Şekil 15

İki modelin accuracy değerine ve Şekil 13 ile şekil 15 arasındaki farka baktığımızda modelimizin en iyi parametrelerle tekrar kurulduğunda iyileştiğini görüyoruz. Yani öğrenmesi daha iyi olduğu için artık daha iyi tahminliyor.

2- Random Forest Algoritması

Hedef değişkenim kategorikse de numerikse de olabilir.
Regresyon (tahmin) ve sınıflandırma yapılabilir.
Y‘mizi açıklayabilecek en iyi x olasılıklarını kullanır.
Eksik datayla başa çıkabilir.
1 tane model ile yetinmez, onun zayıflığını kullanmaz, bir sürü (biz belirleriz) ağaç kurar en iyi modeli bulur.

Bagging tekniği kullanır; veri kümesinin farklı alt kümelerinde ağaçlar kurar. Veri setinden, model kurarken kaç tane örnek alsın, kaç model kursun vb. parametrelerini biz veririz böylece tahminin varyansını azaltmak için kullanılır.

Kayıp verileri tahmin icin kullanılır; model kurarken seçtiği eğitim kümesini, tüm veri kümesinden parça parça seçtiği için (10da birini alması gibi mesela) outlier’ı farklı ağaçlar kurarak kullanır ve outlier’ın etkisini azaltmış olur yani çektiği örneklerden (tüm verisetinden aldığı bir kısım veri kümesi ) kimisine outlier denk gelirken, diğer modele örneklerine outlier denk gelmez ve en iyi ağacı (modeli) böylece bulur.

Dengesiz (Unbalaced) hedef değişkenimiz varsa (0 sınıfından 5 bin tane örnek, 1 sınıfından 20 tane örnek gibi) da kullanılabilir.

Kod yazımının tekrarından kaçınmak adına “data hazırlama” kısmındaki kodları tekrar çalıştıralım ve dataframe’imizi temiz bir şekilde tekrar oluşturalım.

from sklearn.ensemble import RandomForestClassifier#gerekli kütüphaneyi import ettikrf_model = RandomForestClassifier().fit(X_train, y_train)#modelimizi eğitiyoruzrf_model #modelin aldığı parametrelerRandomForestClassifier(bootstrap=True, class_weight=None, criterion=’gini’,max_depth=None, max_features=’auto’, max_leaf_nodes=None,min_impurity_decrease=0.0, min_impurity_split=None,min_samples_leaf=1, min_samples_split=2,min_weight_fraction_leaf=0.0, n_estimators=10, n_jobs=None,oob_score=False, random_state=None, verbose=0,warm_start=False)
Şekil 16

Model Tuning

rf_params = {“max_depth”: [2,5,8,10],“max_features”:[2,5,7],“n_estimators”:[10,50,100],“min_samples_split”:[2,5,10]}rf_model =RandomForestClassifier()rf_cv_model =GridSearchCV (rf_model, rf_params, cv=10, n_jobs =-1, verbose =5)rf_cv_model.fit(X_train, y_train)print(“En iyi parametreler: “+ str (rf_cv_model.best_params_))
Şekil 17 modelimizi grid search ile tekrar eğitirken bu sekilde bilgiler ekrana basılıyor.bizim bu eğitimimiz mesela 4.8 dakikada bitmis orada yazdığı üzere .
print(“En iyi parametreler: “+ str (rf_cv_model.best_params_)) #en iyi parametreleri buldukrf_tuned = RandomForestClassifier (max_depth = 10, max_features= 2, min_samples_split = 5, n_estimators = 50)rf_tuned.fit(X_train, y_train)#en iyi parametrelerle tekrar model kuruyoruz
Şekil 18

Şekil 16 ile şekil 18'i kıyasladığımızda en iyi parametrelerle kurulan modelin, default parametrelerle kurulan modelden biraz daha iyi olduğunu görüyoruz. Recall değerinin 1 verisi için yaptığı tahminleme, en iyi parametrelerde %83 iken default parametrelerdede daha iyi olduğunu (%84) görüyoruz bunun sebebi, modeli eğitirken cv parametresi “10” olarak setlendiği için tüm veri setinin rastgele 10'da birini test verisi, geri kalan 10’da 9'unu ise eğitim verisi olarak kullanıyor ve bir sonraki modeli kurarken bu sefer verinin test için kullanmadığı diğer 10’da birlik kısmını test verisi, geri kalanını ise eğitim verisi olarak kullanıyor yani buradaki rastgele olarak seçilen 10’da 1’lik eğitim verisi o anlık daha iyi sonuç vermiş olabilir buna takılmıyoruz.

3-) Gradient Boosting Algoritması

Boosting; unbalanced, anomalidetection, dna datasında iyidir.

Çoklu model kurduğu icin overfitting’i (ezberlemeyi) random forest ve boosting algoritmaları engeller.

Boosting algoritması ağırlıklı ortalama alır. Yani model kurma konusunda iyi olan sample’a (veri setinden çekilen veri kümesi) ağırlık verir ve bir dahaki model kurulumunda iyi olan sample’ları seçerek onun başarım ortalamasını alır .

Kod yazımının tekrarından kaçınmak adına “data hazırlama” kısmındaki kodları tekrar çalıştıralım ve dataframe’mizi temiz bir şekilde tekrar oluşturalım.

from sklearn.ensemble import GradientBoostingClassifier #sklearnden gerekli kütüphaneyi aldikgbm_model = GradientBoostingClassifier ().fit (X_train, y_train)y_pred = gbm_model.predict(X_test)accuracy_score(y_test, y_pred)0.9460869565217391
Şekil 19

Model Tuning

gbm_params= {“learning_rate”: [0.0001, 0.01, 0.1, 0.05],“n_estimators”: [10,50,100],“max_depth”: [3,5,10],“min_samples_split”: [2,5,10]}#Tüm bu parametre değerlerinin kombinasyonlarıyla tek tek model kurulur ve en başaralı modeli veren en iyi parametreleri buluruz.gbm = GradientBoostingClassifier()gbm_cv = GridSearchCV (gbm, gbm_params, cv =10, n_jobs= -1, verbose =1)print ("En iyi parametreler: " + str (gbm_cv.best_params_))En iyi parametreler: {'learning_rate': 0.1, 'max_depth': 5, 'min_samples_split': 5, 'n_estimators': 100}gbm = GradientBoostingClassifier (learning_rate = 0.1, n_estimators = 100, max_depth= 5, min_samples_split = 5)gbm_tuned = gbm.fit(X_train, y_train)
Şekil 20

Şekil 19 ile şekil 20'ye baktığımızda bu sefer en iyi parametrelerin modelimize katkısını pek göremiyoruz.Bunu aşmak için bir yol olarak, grid search’te parametrelere verdiğimiz aralıkları, değerleri genişleterek daha çok kombinasyonla model kurmasına izin vermek olabilir.

Buraya kadar olan örneklerle aslında model kurma kısmında en vakit alan ve önemli olan şeyin veriyi, modele girmesine hazırlama aşaması olduğunu görüyoruz. Veriyi hazırladıktan sonrası, modeli en iyi haline getirmek için modelin parametreleriyle oynamak.Tabii bu işin içine girmek istiyorsanız modellerin nasıl çalıştığını anlamak için işin detayına yani modellerin arkasında yatan matematiğe göz atmanızı da öneririm.

Diğer classifier kütüphaneleriyle de kendiniz deneyebilirsiniz ben yazıyı daha fazla uzatmamak adına burada bitiriyorum, umarım yararlı olmuştu.

Geri dönüşleriniz olursa sevinirim, ilk yazımı da böylece bitireyim :)

Herkese iyi okumalar dilerim.

https://giphy.com/gifs/3oEdva9BUHPIs2SkGk

Kaynak:

https://www.researchgate.net/publication/261296591_Gini_Algoritmasini_Kullanarak_Karar_Agaci_Olusturmayi_Saglayan_Bir_Yazilimin_Gelistirilmesi

--

--