Python Üzerinde Ridge Regresyon: İşsizlik Oranı Tahminleme

Regresyon ile alakalı daha önceki yazılarda belirli değişkenler üzerinden modeli kurma ve performansını ölçme, birkaç model arasından en iyi performans vereni seçme gibi konulardan bahsetmiştim. Bu yazıda ise farklı bir regresyon çeşidi olan “Ridge” regresyondan bahsedeceğim. Ridge regresyonun konsepti, özellikleri ve neden kullanıldığına dair teorik bilgileri yazının ilgili bölümünde anlatacağım. Fakat şimdi yazının işleyiş sürecinin nasıl olacağı hakkında genel bir bilgi vereyim. Elimdeki veri setini öncelikle her zamanki gibi ayıracağım. Fakat bu kez train, test ve validation olarak değil, “train-validation” ve “test”olarak iki ayrı veri seti oluşturacağım. Bunu yapma sebebimi de yazının ilerleyen kısımlarında anlatacağım. Daha sonra veri seti içerisindeki bir sürü değişken arasından sadece işime yarayacak olanları seçeceğim ve bu işlemin detaylarını açıklayacağım. Sonrasında Ridge regresyon işlemini gerçekleştirip bu işlemin parametrelerinin ne olduğunu ve en uygun parametreleri nasıl seçeceğimi anlatacağım. Bu noktada da yine sadece Ridge işlemine özgü olmayan, makine öğrenmesi süreçlerinde genel olarak kullanılan bir yöntemden bahsedeceğim. En optimum parametreyi bulduktan sonra, onu kullanarak artık Ridge regresyon modelini tamamlayacak ve tahminleme işlemine geçeceğim. Tabi burada çok önemli bir diğer nokta da, bu işlemleri yaparken kullandığım yazılım dili bu kez R değil, Python olacak. Bu şekilde tasarlamamın sebebi ise tek bir programa bağlı kalmadan daha esnek yazılar yazmak. Bu blogda R, Python ve daha başka programlar ile yazılar yayınlayacağım.

Artık başlayabiliriz. Öncelikle elimizdeki veri setini programa alıp inceleme işlemine başlayalım. Kullanacağım veri setini buradan indirebilir ve aynı zamanda kolonların ne anlama geldiğine de bakabilirsiniz. Aynı R’deki gibi veri setini otomatik okumak adına Python’un üzerinde çalıştığı dosya yolunu öğrenip, veriyi oraya kopyalayalım. Aşağıdaki kod bloğu ile çalışma yolunu görebilirsiniz:

import os
os.getcwd()

Veri setini buraya yapıştırdıktan sonra, programa okutma işlemine geçiyorum:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import sklearn
import scipy.stats as stats

Data = pd.read_csv('acs2015_census_tract_data.csv')
Data_pd = pd.DataFrame(data=Data)
len(Data_pd)
Data_pd_Filtered = Data.dropna(axis = 0, how = 'any')
len(Data_pd_Filtered)
Data_Last = Data_pd_Filtered.drop(['CensusTract', 'State', 'County'], axis = 1)
len(Data_pd_Filtered.columns)
len(Data_Last.columns)
Data_Last.head(n=10)

Kodun ilk kısmında, yazıda kullanacağım kütüphaneleri indirdim. Daha sonra ise “pandas” kütüphanesindeki “read_csv” komutunu kullanarak veriyi programa aldım. Veriyi “pandas” kütüphanesinin veri setlerinden olan “Data Frame” türüne çevirdim ki bu da bize aynı R’deki gibi veri üzerinde işlemler yapma konusunda kolaylık sağlayacak. Veri üzerinde bazı filtreleme işlemleri yapmadan önce satır sayısına bakalım.

1

74000 satır var. “.dropna” komutu herhangi bir satırda “NA” ya da “nan” olması durumunda o satırı veri setinden çıkaracak. “len” komutlarıyla satır sayılarını karşılaştıracak olursanız arada 1300’e yakın “nan” içeren satırın elendiğini görebilirsiniz.

3

Sonrasında veri setinden ilk 3 kolonu çıkardım. Burada kolonlar için 1 numaralı, satırlar için de 0 numaralı axis bilgisinin kullanıldığını belirteyim. Bu kolonlar nüfus sayım sistem id’si, ilçe ve bölge bilgileri idi. Nüfus sayım id’sinin bizim için bir önemi yok. İlçe ve bölge ile alakalı tüm bilgiler de verinin geri kalanında olduğundan dolayı, bunların isimleri bu senaryo için şimdilik bir şey ifade etmiyor. Biz modeli oluşturma işlemini tamamladığımızda, önümüze herhangi bir ilçe ve bölge ile alakalı sayısal bilgiler geldiğinde, biz orası için işsizlik oranını tahmin edeceğiz. En son kolon sayısını görelim:

4

3 kolon eksildiğini görüyoruz. Son olarak “head” komutu ile de ilk 10 satırı görmek istedim. Kütüphaneleri kısa adlarıyla programa aldıktan sonra sürekli o adları kullanabildiğimize ve uzun uzun yazmak gerekmediğine de dikkat çekmek istiyorum. Şimdi kodun sonucuna bakalım:

5

Gördüğümüz gibi verinin ilk 10 satırı karşımıza gelmiş durumda. Hatırlatmak istiyorum ki amacımız işsizlik oranını tahminlemek. Bu da veri setindeki “Unemployment” kolonuna denk geliyor. Bunu yapmak için gerekli aşamalara geçmeden önce, veriyi bölme işlemini gerçekleştireceğim. Geçen yazımdan hatırlayacak olursanız, makine öğrenmesi süreçlerinde verinin bölündüğünü ve model kurma işleminin “train” set üzerinde yapıldığını söylemiştim. “Test set” ve “Validation set” hakkında da bilgiler vermiştim. Test set, model kurma ve parametre belirleme aşamalarının hiçbirinde yer almaz ve en son kurulan final modelin tahminleme performansını ölçmekte kullanılır. Validation setin ise model karmaşıklığı(hangi özelliklerin dahil edileceği), veya polinomik modellerde modelin derecesi gibi hiperparametreleri belirlemede kullanıldığını söylemiştim. Bu yazıda ise farklı bir bölme işlemi uygulayacağım. Veriyi ikiye ayırıp, ilk kısmını hem training hem validation set olarak, ikinci kısmını ise test set olarak kullanacağım. Bu şekilde yapmamın sebebi ise hiperparametreleri(bu senaryoda model karmaşıklığının derecesi ve Ridge regresyon parametresi) belirlerken “cross validation” yöntemini kullanacak olmam. Bu yöntemin detaylarını sırası geldiğinde anlatacağım. Şimdilik şunu bilmemiz yeterli; veriyi %80’i training ve validation, %20’si ise test set olacak şekilde böleceğim.

Bölme işlemini aşağıdaki kod bloğu ile gerçekleştiriyorum:

train_validation = Data_Last.sample(frac = 0.8, random_state = 200)
test = Data_Last.drop(train_validation.index)
len(train_validation)
len(test)

Verinin %80’ini train ve validation set olarak, geriye kalan %20’sini de test set olarak ayırdık. “.sample” komutunun “frac” argümanıyla nasıl bir yüzdelik dilime göre ayıracağımı belirttim. “random_state” komutu ise çoğu komut gibi yine “seed” kısmını ayarlayarak tutarlı bölmeler gerçekleşmesini sağlıyor. İkinci satırdaki “.drop” komutu ise asıl veriden train ve validation için ayırdığımız kısım dışında kalanları test setine atıyor. Son 2 satırda ise işlemin sağlamasını yapmak amacıyla satır sayılarına bakıyoruz. Train ve validation setin satır sayısı test setin satır sayısının 4 katına eşit olmalı.

2

Evet sağlamayı da yaptıktan sonra devam edelim. Ayırma aşamasından sonra, veri setindeki değişkenlerden hangileri bizim işimize yarar ve modele dahil edilebilir bunu öğrenmemiz gerekiyor. Bunu öğrenmek adına da bir dizi işlemler gerçekleştireceğim. Öncelikle değişken veya özellik seçiminde nasıl alternatifler var ondan bahsetmek istiyorum. Regresyon ile alakalı ilk yazımda bunların birini göstermiştim. Fakat orada da ilk aşamada bu sürece dahil olacak olan değişkenleri keyfi seçmiştim. Tüm olası değişkenler arasından seçme işleminde ise birden çok yöntem kullanılabilir. Bunlardan birincisi “all subsets” yani tüm alt kümeler yöntemidir. Bu yöntem kısaca şu şekilde çalışmaktadır; içinde hiç değişken olmayan bir modelden başlamak üzere (içinde hiç değişken olmayan model sadece “noise” yani önceki yazılarda bahsettiğimiz hataları temsil eden “epsilon” terimini içinde barındırır) elimizdeki değişken setinin önce tekli kombinasyonlarıyla çalışır. Yani verisetindeki her değişken için teker teker içinde sadece o değişkeni barındıran modeller kurar ve bunların hangisi en düşük training set hatasını veriyorsa, onu ilk aşamanın en iyi modeli olarak seçer. Yani elimizde 50 tane değişken varsa teker teker 50 model kurar ve en iyisini seçer. En iyisine de training set üzerindeki hatalarına bakarak karar verir. Yöntemin ikinci aşamasında ise tüm değişkenlerin ikili kombinasyonları ile modeller kurulur ve yine en iyi sonucu veren ikinci aşamanın en iyi modeli seçilir. Bu şekilde toplam değişken sayısına kadar n’in k’li kombinasyonları kurulur ve her aşama için bir en iyi model training set hatasına bakılarak belirlenir. Bu en iyi modeller arasından da hangisini kullanacağımız bu kez farklı bir biçimde seçilir. Çünkü direkt olarak en düşük training set hatasını veren modeli seçemeyiz, bunun nedenlerini de geçen yazımda anlatmıştım. Training set hatası bizim için model seçme de belirleyici bir kriter olamaz. Bunun yerine, bir validation set oluşturma yöntemiyle, cross validation yöntemiyle ya da önceden belirlenmiş herhangi bir model kriteriyle en iyi modele karar verilir. Bizim burada kullanacağımız ise üstte de bahsettiğim gibi ikinci seçenek olacak.

Diğer alternatiflere geçmeden önce model kriterlerinden de biraz bahsedeyim. Model kriterleri alanında da birçok alternatif bulunmaktadır. Bunlar arasında AIC, AICc, BIC, Adjusted R-Squred(İlk yazımda kullandığım) gibi kriterler vardır. Adjusted R-squared’in ne olduğuna ilk yazımda değinmiştim biraz da AIC’yi anlatayım. Bu kriter, istatistiksel modellerin belirli bir veri seti üzerindeki kalitesinin bir tahmincisidir diyebiliriz. AIC her modelin diğer modellere göre kalitesini tahminler ve bir model seçme yöntemi sunar. Bir başka deyişle AIC, veri içerisindeki gerçek ilişkileri(fonksiyonları) temsil etmek için söz konusu model kullanılırsa ne kadar bilgi kaybı olacağının göreceli bir tahminini bize verir. Bu da model seçiminde bizim için değerlidir. AIC değeri en düşük olan model, en optimum modeldir çünkü en az bilgi kaybını sağlayacak olan odur. Fakat AIC, modelin gerçek kalitesi hakkında bir bilgi vermez. Eğer yarışan tüm modeller veriye iyi oturmamışsa, AIC bu konuda bizi uyarmayacaktır. Diğer kriterlerden de başka yazılarda yeri geldikçe bahsederiz, şimdi devam edelim.

Bu yöntem dışında neler kullanılır ondan bahsedelim, ilk yazımda kullandığım gibi ileri doğru veya geriye doğru değişkenler modele birer birer eklenerek yine önceden belirlenen model kriterini ya da hatayı hangisi minimize ediyorsa o en iyi model seçilebilir. Burada da yine bunu uygulamayı düşünüyorum. Fakat geçen seferki gibi teker teker değil, bu kez bir algoritma biçiminde otomatik olarak gerçekleştireceğim. Bu süreç adım adım işler ve kriter veya hata daha fazla minimize edilemediğinde durur. Böylece optimum model seçilmiş olur. Bu tarz algoritmalara da “Greedy Algorithms” denmektedir. Bir başka ve çok yaygın olan yöntem ise “Lasso Regresyon” dur. Bu yöntem de Ridge Regresyon’a benzemektedir fakat modele bazı düzeltmeler yaparak belirli noktalarda bazı değişkenlerin katsayılarını sıfıra indirger ve bunları modelden çıkarır. Bu da daha sade modellere yol açar ve bir anlamda regresyon yapılırken özellik veya değişken seçimi de otomatik olarak yapılmış olur. Lasso regresyon çok önemli ve yaygın bir yöntemdir fakat konumuz olmadığı için detaylarına burada değinmeyeceğim. Şunu da söylemeliyim ki bu yöntemler arasında en güvenilir sonucu veren aslında ilk anlattığımdır. Çünkü doğal olarak bir değişken kümesinin tüm alt kümelerini deneyip en optimumu seçmek, en doğru sonucu verecektir. Fakat elimizdeki veri setinde 1000 tane değişken olduğunu düşünün (makine öğrenmesinde belki değişken sayısı milyonları bulabilir). Bu durumda bu değişkenlerin tüm alt kümeleriyle deneme yapmak hesaplama açısından imkansız olacaktır. Bu yüzden değişken sayısı bakımından kısmen dar olan veri setleri dışında bu yöntem pek kullanılmaz. Bundan dolayıdır ki diğer yöntemler uygulanır ve makine öğrenmesinde en popülerlerinden biri de son anlattığım Lasso Regresyon’dur.

Evet algoritmayı aşağıdaki kod bloğu ile uygulamaya başlıyorum.

from sklearn.linear_model import LinearRegression
y = train_validation["Unemployment"]
x = train_validation.drop("Unemployment", axis = 1)
lr = LinearRegression()
from mlxtend.feature_selection import SequentialFeatureSelector as SFS
sfs = SFS(estimator = lr,
	      k_features = (1, 33),
	      forward = True,
	      floating = False,
	      scoring = 'mean_squared_error',
	      cv = 0)
sfs_fit = sfs.fit(X = x.values, y = y.values)
sfs_fit.subsets_

Öncelikle sklearn.linear_model modülünden LinearRegression’u “import” komutu ile alıyorum. Kullanacağımız komutlar bu kütüphane içerisinde bulunuyor. Daha sonra özellik seçimi için bağımlı ve bağımsız değişkenlerin ne olduğunu programa tanıtıyorum. “y” yani bağımlı değişken işsizlik oranı olacağı için train_validation setten işsizlik oranını filtreliyorum. Geriye kalan her şeyi ise “.drop” komutuna gerekli argümanları vererek tahmin ediciler yani bağımsız değişkenler olarak “x” objesine atıyorum. Bir alt satırda tahminlemede kullanacağım metodu “lr” objesine atıyorum. Lineer Regresyon kullanarak özellik seçimi yapacağım için bu işlemi “LinearRegression()” komutu ile gerçekleştiriyorum. Bundan sonraki aşamada ise özellik seçimi yapacağım metodu oluşturup “sfs” objesine atıyorum. Buradaki “SFS” komutu “Sequential Feature Selection” ifadesinin yani artan bir şekilde özellik seçimi yapan metodun kısaltmasıdır. Fonksiyonun argümanları içerisine tahminci olarak “lr” objesini verdikten sonra “k_features” argümanında ise belirli bir aralıktaki en iyi özellik kombinasyonunu seçmesini söylüyorum. 33 kolonum olduğu için 1’den başlayıp 33’e kadar değişkenler içerisinde en iyi kombinasyonu bulmasını istiyorum. “Forward” argümanının “True”olması ileriye dönük yani özellikleri sırayla ekleyerek seçim yapması gerektiğini söylüyor. “Floating” argümanı her adıma bir ara adım ekler ve performansı düşüren değişkenleri çıkararak algoritmaya devam eder. Bu argümanı “False” seçtik. “scoring” bize hangi ölçüyü kullanarak model performanslarına karar vereceğimizi sorar. Burada “MSE” yani “Mean Squared Error”, ortalama hatayı seçtik. Son olarak da “cv = 0” derken herhangi bir cross-validation istemediğimizi belirttik. Dikkat edelim ki bu ilk aşamada cross-validation metodunu kullanmadım. Bu da aradaki farkı net olarak görmemizi sağlayacak. Bu metodu belirledikten sonra, “sfs.fit” komutu ile işlemi başlattık. Kod bloğunun en son satırında ise her adımdaki modelleri görmek için “.subsets_” komutunu kullandık. Komutun sonucunu görelim:

6

Komutun sonucunun sadece ilk satırını aldım bu bizim için yeterli olacaktır. Gördüğünüz gibi birinci adımda train_validation setteki ortalama hatayı en düşüğe ulaştıran özellik 14. değişkenmiş. Ortalama skorun bu değişken için -19.67 civarı olduğu da “avg_score” kısmında görünüyor. Komutun en son yani 33. adımına bakarsanız 33 değişkenin tamamını modele aldığını görürsünüz. Çünkü en düşük ortalama hatayı 33 değişkenin tamamını modele eklediğinde buluyor. Böyle yapmasının sebebi ise model karmaşıklığı (yani modeldeki değişken sayısı veya polinomik ise derecesi) arttıkça training setteki hata düşecektir. Çünkü model ne kadar karmaşık olursa train sete o kadar iyi oturacaktır ve train setteki veri noktalarını o kadar iyi yakalayacaktır. Fakat bu durumun dezavantajının “overfitting” riski olduğunu geçen yazımda anlatmıştım. Şunu unutmamak gerekir ki üstte yazdığımız algoritma train setteki ortalama hatayı baz alarak bu modelleri seçti ve en düşük hatayı da doğal olarak tüm değişkenleri modele ekleyerek en karmaşık modeli elde ettiğinde buldu. Fakat yazının başında da bahsetmiştim training setteki hata miktarı bizim için model seçme kriteri olursa yanıltıcı olur. Bu yüzden farklı bir kalite metodu kullanacağımızı ve bunun da cross-validation olduğunu belirtmiştim. Training hatasının model karmaşıklığı arttıkça nasıl azaldığını bir grafikle gösterelim ve ardından da algoritmayı cross-validation kullanarak çalıştıralım. Aşağıdaki adımlarla söylediklerimizi gerçekleştireceğiz:

“.subsets_” komutu sonucunda oluşan nesnenin tipini inceleyelim.

type(sfs_fit.subsets_)

Sonuç:

7

Görüleceği üzere nesnenin tipi “dictionary”. Şimdi bu dictionary içerisinden her adımın MSE değerini çekip bunları bir grafikte göstereceğiz:

sfs_fit.subsets_DF = pd.DataFrame(sfs_fit.subsets_)
row = sfs_fit.subsets_DF.iloc[0]
row.plot(kind = 'bar')
plt.show()

Kodun ilk aşamasında elimizdeki dictionary tipindeki objeyi normal pandas data frame’ine dönüştürdüm. Görüntüsü aşağıdaki gibi:

8

Gördüğünüz üzere 3 satır ve 33 kolondan oluşan bir data frame oluşturdu. Devam edelim. Kodun 2. satırında grafiğini çizeceğim satırı “row” adında bir nesneye atıyorum. “iloc[0]” komutu ile indeksi 0 olan ilk satırı yani “avg_score” satırını seçiyorum. O nesneyi de inceleyelim:

9

“avg_score” değerleri hazır. Şimdi bunların grafiğini çizmek kaldı. Bunu da kodun 3. satırı ile “bar” grafik çizerek gerçekleştirdik. En sondaki plt.show() komutu ise çizilen grafiği ekrana getirir. Bunu ek olarak yapmamızın nedeni python’un grafiği bir obje olarak oluşturması fakat default olarak ekrana getirmemesi. Biz de bunu kendimiz yapıyoruz. Sonuca bakalım:

10

Gördüğünüz gibi modele eklenen değişken sayısı arttıkça average score da artıyor. Bu da aslında MSE’nin değişkenler modele eklendikçe düştüğünü gösteriyor. Yukarıda da bahsettiğim gibi modele değişken eklendikçe model karmaşası artar ve karmaşa arttıkça da modelin training set üzerindeki hatası (bu hata RSS, MSE veya MAE gibi metriklerle ölçülebilir) azalır. Fakat model karmaşası çok arttığında model artık training setten çok fazla öğrenmeye başlar ve güzel oturabilmek için tüm veri noktalarına yaklaşmaya çalışır. Bu da modelin aşırı öğrenme tuzağına düşmesine ve artık spesifik olarak o training sete odaklanmasına sebep olur. O training sete odaklandığında da dışarıdaki gerçek verilere uyum sağlayamaz duruma gelir ve asıl anakütleyi temsil etme yetisini kaybetmeye başlar. Yani “True Error” denen, modelin gerçek dünyadaki verilerle çalıştığında alacağı hatayı temsil eden bu değer(her ne kadar ölçemesek de) artmaya başlar. Bu yüzden üstteki grafikte gördüğümüz training hatası grafiği bizim için bir ölçüt değildir. Ölçüt olsaydı 33 değişkeni de içeren modeli seçmemiz gerekirdi. Fakat biz burada üstte kullandığımız metodu yani cross-validation metodunu uygulayarak en başarılı modeli seçeceğiz. Bunu da aşağıdaki gibi yapacağız:

sfs_CV = SFS(estimator = lr,
		 k_features = (1, 33),
		 forward = True,
		 floating = False,
		 scoring = 'mean_squared_error',
		 cv = 10)
sfs_CV_fit = sfs_CV.fit(X = x.values, y = y.values)
sfs_CV_fit.k_feature_idx_

Evet üstteki kod bloğunu açıklarken cross-validation metodunun nasıl çalıştığını da açıklayalım. Bu metod şu şekilde çalışır: elimizdeki “train_validation” seti üstte cv = 10 argümanında belirttiğimiz gibi rastgele seçilmiş 10 parçaya böler. Daha sonra 33 tane değişkenin her kombinasyonu için, bu 10 parçadan birini “validation” set seçip, geriye kalan 9 tanesini birleştirip “training” set olarak seçer. Daha sonra bu training set üzerine model kurup o tek parça olan validation set üzerinde toplam hatayı hesaplar. Daha sonra yine aynı değişken kombinasyonu için, bu kez farklı bir parçayı validation seçip geriye kalanları birleştirerek training set yapar ve yine o training sete model kurup tek parça olan validation set üzerindeki hatayı hesaplar. Bu işlemi bir döngü biçiminde 10 parçanın 10’u da validation olana kadar uygular. Daha sonra aynı döngüyü diğer değişken kombinasyonları için de uygular ve her değişken kombinasyonu için validation setlerde aldığı hataların ortalamasını bulur ve hangi değişken kombinasyonu en düşük validation hatası ortalamasını veriyorsa onu model olarak alır ve diğer değişkenleri eler. Üstteki kod bloğunda da cv = 10 argümanı dışında her şeyi aynı tuttum. En altta da “.k_feature_idx_” komutu bize final modelde bulunan değişkenleri veriyor. Komutun sonucunu görelim:

12

Evet gördüğünüz gibi 33 değişken arasından 26 tanesi algoritma tarafından seçilmiş ve geriye kalan 7 tanesi modele alınmamış. Alınan değişkenlerin indekslerini görebiliyoruz. Biz de yolumuza bu değişkenleri içeren model ile devam edeceğiz.

Evet bu kısmı geçtik ve modele alacağımız değişkenlerin neler olduğunu belirledik. Şimdi sıra geldi Ridge Regresyon’un detaylarını açıklamaya ve hiperparametresini nasıl seçeceğimize. Normal doğrusal regresyonda modelin training sete nasıl oturduğuna karar vermemize yardımcı olan en yaygın ölçütlerden birinin RSS olduğunu söylemiştik. RSS ne kadar az olursa, model training sete o kadar iyi oturmuştur deriz. Fakat birkaç kez söylediğimiz gibi, RSS’i minimize etmek adına training sete çok fazla uymaya çalışırsak bu da modelin genelleştirilebilirliğini düşüreceğinden “overfitting” problemi ile karşı karşıya kalırız. Ridge regresyon yanlılık-değişkenlik dengesini kurarak bu aşırı öğrenme problemini yok etmeyi hedefler. Yanlılık, kurduğumuz modelin, farklı training setler üzerindeki performanslarını hesapladığımızda, ortaya çıkardığı ortalama performansın, model değişkenleri arasındaki gerçek modeli ya da ilişkiyi ne kadar temsil edebildiğinin bir ölçüsüdür.

Örneğin çok sade bir model kurdunuz fakat çok kompleks bir ilişkiyi temsil etmek istiyorsunuz. Kompleks bir ilişki derken çok fazla özellik içeren bir ilişkiden bahsediyoruz. Bu durumda muhtemelen kurduğunuz o sade model bu ilişkiyi temsil etmekte yetersiz kalacaktır. Bu da model karmaşıklığını artırmamız gerektiğini bize söyler. Model karmaşıklığı arttıkça modelin yanlılığı(bias) da düşecektir. Bizim senaryomuzu düşünelim. İşsizlik oranını tahmin etmek istiyoruz ve muhtemelen buna etkiyen bir çok değişken var. Biz sadece tek veya iki değişken kullanarak bir model kursak çok yetersiz kalacaktır ve yaptığımız tahminler gerçekten uzak kalacaktır. Bu yetersiz model ile 100 farklı training set üzerinde 100 farklı tahmin yapsak hepsi de birbirinze benzer tahminler olacak fakat hepside gerçeğe yaklaşmaktan uzak kalacaktır. Fakat biz modele daha çok değişken ekledikçe, işsizlik oranına etki eden faktörleri daha çok kapsamaya başlıyoruz ve bu da tahminlerimizin gerçeğe yaklaşmasına, dolayısıyla da yanlılığın(bias) düşmesine sebep oluyor. Fakat yanlılığı düşürmek adına modele çok fazla değişken ekleyerek model karmaşasını artırdığımızda da, bu kez overfitting riski yaklaşmaya başlıyor.

Değişkenlik ise, modelin yine farklı training setler üzerindeki performanslarından doğan tahminlerin birbirinden çok farklı ya da birbirine yakın olmasının bir ölçüsüdür diyebiliriz. Yine bizim senaryomuz üzerinden gidecek olursak, çok sade bir model kurduğumuzda (örneğin yine tek veya iki değişken kullanalım), bu sade model farklı training setlerde kurulduğunda da yine bir önceki sete oturuşuna çok benzer bir şekilde oturacak ve yine önceki training setlerdekine benzer bir tahmin ortaya koyacaktır. Fakat kompleks bir model düşünürsek, bu model training setteki veri noktalarına çok daha iyi uyacaktır ve o training sete benzer veriler karşısına geldiğinde iyi tahminler çıkaracaktır. Fakat, model kompleks olduğu için training setten fazla öğrenmiş olabilir ve bu da aslında modelin veriye oturuşunun training sete spesifik olarak uyduğunu ve farklı bir training set geldiğinde de o sete uyacağını gösterir. Bu da aslında farklı training setler üzerindeki tahminlerin birbirinden çok farklı olacağının bir işaretidir. Yani kompleks modeller eldeki veriye çok duyarlı olur ve veri değiştiğinde tahminler de değişir. Bu da değişkenliğin fazla olmasına neden olur. Bu tahminler farklı veriler üzerinde yapıldığında bunların ortalaması aslında gerçeğe çok yakın iyi bir performans verir fakat genelde elimizde sadece bir training set olacağından dolayı değişkenliği yüksek bir modelin tahminleri de güvenilmez olacaktır çünkü farklı verilere sahip değiliz ve tahminlerin ortalamasını hesaplayamıyoruz. Sonuç olarak karmaşıklığı yüksek olan modellerin değişkenliği(variance) de yüksektir fakat hatırlayalım ki bu modellerin yanlılığı düşüktü.

Genel olarak şunu söyleyebiliriz, yüksek karmaşıklığa sahip olan modeller düşük yanlılığa fakat yüksek değişkenliğe sahiptir. Tam tersi sade modellerin de değişkenliği düşüktür fakat yanlılığı yüksektir. Yanlılık yüksekse model gerçek ilişkiyi temsil etmekte yetersiz kalıyor demektir. Değişkenlik yüksekse de modelin yaptığı tahminler düzensizdir demektir(çoğu kez overfitting olmuştur). İşte Ridge regresyon bu ikisi arasındaki dengeyi kurarak hem overfittingi önlemek hem de overfittingi önleyeyim derken modeli çok sade hale getirmemek meselesine yoğunlaşır. Gelelim bunu nasıl yaptığına. Ridge bunu yaparken modelin veriye uyum ölçüsüne bir düzeltme yapar. Bu düzeltmenin asıl amacı da overfittingi ölçmek ve hata ölçütüne (maliyete) overfittingi de eklemek. Yani modelin training setteki hatasına(RSS), overfittinge düşme durumunda karşılaşacağı kaybı da ekler ve sadece hatayı değil, bunu da minimize etmeye çalışır. Dolayısıyla klasik modellerdekinin aksine minimize edilmeye çalışılan maliyet fonksiyonuna sadece RSS değil, aynı zamanda overfitting durumunda oluşan maliyet de dahil edilir. Peki overfittingin maliyeti nasıl ölçülür? Eğer bir model overfitting’e düşmüşse modelin parametrelerinin katsayılarının büyüklüğü aşırı olacaktır. Şunu da not edelim ki büyüklük derken hem pozitif, hem de negatif yöndeki büyüklüğü kastediyoruz.

İşte Ridge Regresyonun overfittingi ölçmesini sağlayan nokta da bu katsayıların büyüklüğüdür. Model aşırı öğrenme durumundan uzaklaştıkça katsayılar da makul seviyelere inecektir. Peki katsayıların büyüklüğü modelin maliyet fonksiyonuna nasıl ekleniyor? Ridge regresyon için model katsayılarının karelerinin toplamı şeklinde ekleniyor. Kareler toplamı söz konusu olduğu için, bu işleme L2 norm alma işlemi denir. Yani Ridge regresyon maliyet fonksiyonunda RSS değerine ek olarak model parametrelerinin katsayılarının L2 normunu da ekler. Bu yüzden Ridge regresyona L2 düzeltmesi de denilmektedir. Üstte bahsettiğim Lasso Regresyon da L1 düzeltmesi kullanmaktadır. Fakat bunun detaylarına burada değinmeden devam ediyorum çünkü zaten yeterince uzun oldu. Son olarak, maliyet fonksiyonu içerisinde bu model parametrelerinin L2 normunun ne kadar ağırlıklandırılacağı da bir lambda hiperparametresiyle belirlenir. Bu parametre aslında modelin veriye uyumu ve aşırı öğrenme arasındaki dengeyi sağlayan parametredir ve Ridge regresyonun amacına ulaşabilmesi için bu parametrenin doğru seçilmesi gerekmektedir. Kısaca Ridge Regresyonun maliyet fonksiyonu “RSS + λ(L2 norm)” şeklinde yazılabilir. Eğer lambda çok küçük olursa maliyet fonksiyonunun sıradan en küçük kareler regresyonunun maliyetinden bir farkı kalmaz ve overfittingin önü açılmış olur. Bu da yüksek değişkenliğe neden olacaktır. Eğer çok büyük olur ve sonsuza yaklaşırsa da katsayıların değeri sıfıra doğru ineceğinden bu kez model çok sade olur değişkenlik minimuma yaklaşır fakat yanlılık maksimuma doğru gider. İşte bize gereken de bu aralıktaki en optimum lambda değerini bulmak.

Geldik bu lambda parametresinin seçimine. Aynı özellik seçiminde olduğu gibi burada da cross-validation metodunu kullanacağız ve hangi lambda en az validation set hatasını veriyorsa yola onunla devam edeceğiz. Aşağıdaki kod bloğu ile işlemi gerçekleştirelim:

x_final = x.iloc[:, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 21, 23, 24, 27, 28, 29, 30]]
alpha_range = [1e-15, 1e-10, 1e-8, 1e-4, 1e-3,1e-2, 1, 5, 10, 20]
from sklearn.linear_model import Ridge, RidgeCV
Ridge = Ridge(normalize=True)
coefs = []
for alpha in alpha_range:
     Ridge.set_params(alpha = alpha)
     Ridge.fit(x_final, y)
     coefs.append(Ridge.coef_)
np.shape(coefs)
CoefPlot = plt.gca()
CoefPlot.plot(alpha_range, coefs)
CoefPlot.set_xscale('log')
plt.axis('tight')
plt.xlabel('alpha')
plt.ylabel('weights')
plt.show()
RCV = RidgeCV(alphas = alpha_range, scoring = 'mean_squared_error', normalize = True)
RCV.fit(x_final, y)
RCV.alpha_

Kod bloğunu açıklayalım. İlk satırda, train sette sadece değişken seçiminde belirlediğimiz değişkenleri alıyoruz. Daha sonrasında deneyeceğimiz alpha değerleri için (üstte bahsettiğim lambda) bir liste oluşturuyoruz. Bu alpha değerleri arasından en iyi sonucu vereni, Ridge regresyon için kullanılacak olan hiperparametre olarak seçeceğiz. Gerekli komutları içeren paketleri kütüphanelerden indiriyoruz. Bundan sonraki birkaç satırda regresyon katsayılarının alpha değiştikçe nasıl hareket ettiklerini göstermek amacıyla grafiklerini çizmek istedim. Grafik çizmede kullanılacak olan metodu belirledikten sonra “coefs” adında boş bir liste açıyorum ve her alpha değeri için oluşacak olan regresyon katsayıları vektörünü içinde barındırmasını sağlayacağım. Sonrasında bir for döngüsüyle her alpha değeri için bir ridge regresyon modeli kuruyorum ve her model sonucunda oluşan katsayı değerlerini de boş olan “coefs” adlı listeme ekliyorum. Döngünün bitimindeki “np.shape” komutu ise en son aşamada oluşmuş olan nesnenin satır ve sütun sayısını veriyor. En son nesnede denenen alpha değeri kadar satır ve seçilen değişken sayısı kadar da sütun olmalı. Bu da 10 satır ve 26 sütun demek oluyor. Bu aşamadan sonra regresyon katsayılarının alpha değeri büyüdükçe nasıl değiştiğini göstermek için gereken grafiğin oluşmasını sağlayan kodları yazdım. Bu kodların sonucunu aşağıda inceleyeceğiz. Grafikten sonra ise sıra son aşamaya geliyor. Burada kullandığım “RidgeCV” komutu, aday alpha değerleri arasında en iyi performans göstereni MSE kriterini baz alarak cross-validation yöntemiyle buluyor ve sonucu döndürüyor. Son satırda da o alpha değerini görmek istiyoruz. Şimdi kod bloğunun sonuçlarına tek tek bakalım:

19

Evet üstte de bahsettiğimiz gibi, “coefs” nesnesinin satır sayısı alpha değerleri kadar yani 10 iken, sütun sayısı da değişken sayısı kadar yani 26. Devam edelim:

20

Grafikte de alpha büyüdükçe regresyon katsayılarının gidişatını görüyoruz. Farkedeceğiniz üzere hiperparametre büyüdükçe katsayılar sıfıra doğru yaklaşıyor bundan üstte bahsetmiştik. Fakat sıfıra ulaşmazlar. Çünkü sıfıra ulaşma durumları ancak parametre sonsuz olduğunda olacağından ve biz de sonsuza ulaşamayacağımız için katsayılar çok çok küçük değerlere kadar inecek fakat sıfıra ulaşmayacaktır. Bu yüzden de seçilen hiçbir değişken modelden elenmeyecektir. Burdan çıkarılacak sonuç ise şu: Ridge Regresyon değişken veya özellik seçimi yapmaz. Katsayıları sıfıra ulaştırarak değişken seçimi yapan regresyon tipinin Lasso olduğunu yukarıda söylemiştik. Devam edelim:

21

Evet cross-validation işlemi sonucunda en iyi sonucu veren alpha parametresi değeri 0.0001 olarak gözüküyor. Bu da demek oluyor ki en son aşamada Ridge regresyon modelinde hiperparametre olarak bu değeri kullanacağız. Belirlediğimiz alpha değeri ile regresyonu gerçekleştirelim ve test set üzerindeki performansını gözlemleyelim. İşlemi gerçekleştirelim:

RidgeReg = Ridge(alpha = RCV.alpha_, normalize = True)
RidgeReg.fit(x_final, y)
y_test = test["Unemployment"]
x_test = test.drop("Unemployment", axis = 1)
x_test_final = x_test.iloc[:, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 21, 23, 24, 27, 28, 29, 30]]
Prediction = RidgeReg.predict(x_test_final)
from sklearn.metrics import mean_squared_error
print(mean_squared_error(y_test, Prediction))

Yine kod bloğunu açıklayalım. İlk satırda cross-validation yönteminde bulduğum optimum alpha değerini Ridge regresyon metoduma hiperparametre olarak veriyorum ve metodu tanımlıyorum. Daha sonra bu modeli “train set” üzerinde kuruyorum. Unutmamak gerekir ki modelin “fitting” aşaması her zaman train set üzerinde yapılır. Daha sonra aynı “train_validation” setimde oluşturduğum gibi tahmincileri ve tahmin edilecek olan veriyi birbirinden ayırıyorum ve bunlara x_test ve y_test adlarını veriyorum. Daha sonra ise yine CV(Cross-valiation) metoduyla tespit ettiğim değişkenleri bırakıp diğerlerini çıkartıyorum ve oluşan nesneyi x_test_final nesnesine atıyorum. Artık modelin performansını test üzerinde denemenin zamanı geldi bu yüzden “predict” komutunu test set tahmincileri yani x_test_final nesnesi üzerinde kullanıyorum. Sonraki aşamada MSE değerini tespit edebilmek için gerekli metrik dosyasını yine import metoduyla indiriyorum ve “mean_squared_error” fonksiyonu ile de test set üzerindeki MSE değerini hesaplıyorum. Kodun çalışmasına bakalım:

22

Evet test üzerindeki MSE değeri 14.764623727043631 çıktı. Bunun diğer alpha değerlerinden daha iyi olduğunu göstermek için bir başka alpha ile aynı MSE’yi bir daha hesaplayalım.

RidgeReg2 = Ridge(alpha = 0.001, normalize = True)
RidgeReg2.fit(x_final, y)
y_test = test["Unemployment"]
x_test = test.drop("Unemployment", axis = 1)
x_test_final = x_test.iloc[:, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 21, 23, 24, 27, 28, 29, 30]]
Prediction2 = RidgeReg2.predict(x_test_final)
from sklearn.metrics import mean_squared_error
print(mean_squared_error(y_test, Prediction2))

Sonuca bakalım:

23

Evet çok az bir farkla da olsa bizim alpha değerimiz daha az bir MSE üretti. Aslına bakarsanız bizimkine yakın diğer alpha değerleri ile karşılaştırıldığında MSE açısından çok küçük farklar ortaya çıkıyor ve bu da pek önemli değil. “alpha_range” nesnesini daha geniş yapsaydık yani çok daha fazla alpha değeri deneseydik daha optimum bir sonuca ulaşırdık fakat ben burada süreci göstermek amacıyla çok fazla alpha denemedim.

Artık yazının son bölümüne geldik. Bu bölümde elimizde bulunan fakat daha önce hiçbir aşamada kullanmadığımız bir nüfus kayıt sistemi id’sini kullanarak onunla alakalı tahmin yapacağız. Aşağıdaki kod bloğuyla gerekli işlemleri gerçekleştirelim:

PrData = Data = pd.read_csv('PredictionData.csv')
PrData_pd = pd.DataFrame(data=PrData)
PrData_Last = PrData_pd.drop(['CensusTract', 'State', 'County'], axis = 1)
PrData_Last = PrData_Last.iloc[:, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 21, 23, 24, 27, 28, 29, 30]]
PrData_Last
PrData['Unemployment']

Öncelikle verinin tahminci kolonlarını inceleyelim:

24

Evet kolonlar bu şekilde. Kullanacağımız 26 kolonun verilerini görebiliyoruz. Şimdi de tahminlenecek olan veriyi yani işsizlik oranını görelim:

25

İşsizlik oranı 20.1 görünüyor. Bizim modelimizin ne tahminleyeceğini görelim:

RidgeReg.predict(PrData_Last)

Evet sonuç:

26

 

Evet modelimiz işsizlik oranını 24.21 olarak tahminledi. Gerçek değere yakın bir tahmin. Fakat unutmayalım ki modelde hiperparametre olarak denediğimiz alpha sayısı aslında azdı. Çok daha büyük bir alpha serisini deneseydik çok daha iyi performans veren bir alpha bulup Ridge Regresyon modelinde hiperparametre olarak da onu kullanabilirdik. Bu da bize daha da başarılı bir model sağlayabilirdi.

Python Üzerinde Ridge Regresyon: İşsizlik Oranı Tahminleme” için bir yorum

Bir Cevap Yazın

Aşağıya bilgilerinizi girin veya oturum açmak için bir simgeye tıklayın:

WordPress.com Logosu

WordPress.com hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Google fotoğrafı

Google hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Twitter resmi

Twitter hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Facebook fotoğrafı

Facebook hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Connecting to %s