PYTHON İLE MAKİNE ÖĞRENMESİ ÖN İŞLEMLERİ (IV)

MODELLER İÇİN ÖZELLİK SEÇİMİ

ÖZELLİK SEÇİMİ

Bir modelle ilgili özelikleri belirledikledikten sonra bu özellikler üzerine düşünmekte fayda vardır. Özelliklerin hepsine ihtiyacımız var mı? Modeli nasıl etkileyeceklerini biliyor muyuz? gibi sorulara cevap bulmamız gerekebilir.

Özellik seçimi, seçilen özellikler arasında, model için kullanılacak olanların ayrıştırılmasıdır. Özellik mühendisliğinden farklıdır, çünkü burada yeni bir özellik yaratılmaz; mevcut özellikler arasından seçim yapılır. Özellik seçiminin en önemli amacı modelin performansını daha iyi bir hale getirmektir.

Çalışmakta olduğunuz modele seçtiğiniz özelliklerin sayısı çok fazla olabilir, ya da seçtiğiniz bazı özellikler gerçekten gerekli olmayabilir. Özellik seçimini gerçekleştirmek için pek çok yöntem vardır. Bunu otomatik olarak paymak mümkündür. scikit-learn paketi varyans baremi, tek değişkenli istatistiksel analiz gibi pek çok özellik seçme yöntemi içerir. Fakat bunları başka eğitimlerde göreceğiz. Modeli eğitmeden önce veri setini iyice anlamak çok önemli olduğundan, bu bölümde göreceğimiz yöntemler genel olarak manuel yöntemler olacak:

Kurmaya çalıştığımız model için tamamen gereksiz olduğunu düşündüğümüz özellikleri çıkarabiliriz.
Birbirleriyle istatistiksel olarak anlamlı bir şekilde korelasyon olan ve bu nedenle bazı modellerin varsayımlarına uymayan özellikler arasında seçim yapabiliriz.
Metin özelliklerle çalışıyorsak, hangi metin kümeleri üzerine modeli eğiteceğimize karar vermek için tf-idf vektörleri kullanmak isteyebiliriz,
Eğer çok fazla sayıda özellik varsa, genel varyansı da azaltan ve veri setindeki özellikleri birleştirip sayısını azaltan boyut azaltma yöntemleri yararlı olabilir.

GEREKSİZ VE ETKİSİZ ÖZELLİKLER

Özellik seçimi sürecinin en önemli katkısı, gereksiz ve etkisiz olan ve modelde sadece hata yaratabilecek özelliklerin modelden çıkarılmasıdır. Bu özellikler modelde sadece kalabalık ve tahminlerde hata yaratır. Bu noktada gereksiz ve etkisiz özelliklerden bahsetmemiz gerekir.

Örneğin, bir özellik başka bir formda başka bir özelliğin içinde bulunuyorsa, ya da iki özellik arasında güçlü bir korelasyon varsa, bu durumlar özelliklerden bazılarının gereksiz ve katkısız olduğunu gösterir.

Özellik mühendisliği sırasında mevcut özellikleri kullanarak yeni özellikler yaratırız. Bunu yaparken aslında bir şekilde mevcut özellikleri kopyalamış oluruz. Kopyaladığımız özellikler yeni özelliklerin yanında gereksiz ve katkısız özellikler haline dönüşür.

Dolayısıyla, gereksiz ve katkısız özelikleri manuel olarak, veri setini iyi anlama yoluyla bulabiliriz. Fakat belirtmek gerekir ki, makine öğrenmesi sürecinin tamamında olduğu gibi, özellik seçimi de döngüsel bir süreçtir. Bazı özellikleri sadece modeli iyileştirip iyileştirmediğini anlamak için çıkarabiliriz.

Bu bölümde Kaggle'dan "Crowdedness at the Campus Gym" veri setini kullanacağız. Bu veri setinde bir üniversite fitness salonundaki kişi sayısı 10 dakikada bir ölçülüp bu salonun, havanın ve zamanın özellikleri, özellikler olarak veri setine dahil edilmiştir:

In [1]:
# `pandas` paketinin oturuma yüklenmesi:
import pandas as pd
# `fitness.csv` veri setinin oturuma yüklenmesi:
fitness = pd.read_csv("/Users/ulcay/Desktop/Python/2020-08/06.08.2020/fitness.csv", sep=";")
# `fitness` veri setine göz atılması:
fitness.head()
Out[1]:
number_people date timestamp day_of_week is_weekend is_holiday temperature is_start_of_semester is_during_semester month hour
0 37 2015-08-14 17:00:11-07:00 61211 4 0 0 71.76 0 1 8 17
1 45 2015-08-14 17:20:14-07:00 62414 4 0 0 71.76 0 1 8 17
2 40 2015-08-14 17:30:15-07:00 63015 4 0 0 71.76 0 1 8 17
3 44 2015-08-14 17:40:16-07:00 63616 4 0 0 71.76 0 1 8 17
4 45 2015-08-14 17:50:17-07:00 64217 4 0 0 71.76 0 1 8 17

Bu veri setini incelediğimizde number_people (insan sayısı) sütununun yanıt değişkeni, diğer değişkenlerin ise açıklayıcı değişkenler (özellikler) olduğunu görüyoruz. Veriye baktığımız anda temperature (sıcaklık) dışındaki tüm özelliklerin date (tarih) özelliğinden türetildiğini anlıyoruz. Bu nedenle ilk aşamada date özelliğinin gereksiz ve katkısız bir özellik haline dönüştüğünü söylemek mümkündür.

Benzer şekide timestamp özelliğinin günün başlangıç anından gözlem anına kadar geçen zamanın saniye olarak ifadesi olduğunu ve bu bilginin hour (saat) özelliğinde bir şekilde zaten bulunduğunu düşünürsek, bu özelliğin de gereksiz ve katkısız olduğuna karar vermek mümkündür.

Ayrıca is_start_of_semester (dönem başı mı?) ve is_during_semester (dönem içi mi?) özellikleri de bir durumun iki farklı yüzünü gösterdiğinden birinin çıkarılması uygun olacaktır. Dönem başı ya da değil iki farklı dummy özellik olarak modele giremez. Dummy özelliklerde her zaman dummy sayısının bir eksiği kadar değişken modele alınmalıdır. Aksi takdirde dummy özellik tuzağı denilen bir hataya düşmüş oluruz. Bu durumda biri 1 (0) iken diğer 0 (1) olan, dolayısıyla birbiriyle mükemmel bir şekilde korelasyonlu (pearson korelasyon katsayısı 1 ya da -1) olan iki değişkeni modele sokmuş oluruz. Bu da aynı değişkeni modele iki kez dahil etmekle aynı şeydir:

In [2]:
# `numpy` paketinin oturuma yüklenmesi:
import numpy as np
# `is_start_of_semester` ve `is_during_semester` özellikleri arasındaki korelasyon katsayısının bulunması
korelasyon = np.corrcoef(fitness.is_start_of_semester,fitness.is_during_semester)[0,1]
print("`is_start_of_semester` ve `is_during_semester` arasındaki korelasyon katsayısı: {:0.2f}".format(korelasyon))
`is_start_of_semester` ve `is_during_semester` arasındaki korelasyon katsayısı: -1.00

date, timestamp ve is_during_semester özelliklerini veri setinden çıkaralım:

In [3]:
# `date` özelliğinin veri setinden çıkarılması:
fitness = fitness.drop(["date","timestamp","is_during_semester"], axis = 1)
# kontrol
fitness.head()
Out[3]:
number_people day_of_week is_weekend is_holiday temperature is_start_of_semester month hour
0 37 4 0 0 71.76 0 8 17
1 45 4 0 0 71.76 0 8 17
2 40 4 0 0 71.76 0 8 17
3 44 4 0 0 71.76 0 8 17
4 45 4 0 0 71.76 0 8 17

Bu veri setinde kalan özelliklerin gereksiz ve katkısızlığı hakkında söylenebilecek daha başka şeyler de bulunuyor. Örneğin day_of_week (haftanın günü) özelliği ile is_weekend özelliği birbiriyle oldukça ilişki. İkisinden biri hakkında, bu özelliklerin ayrı ayrı model performansına katkısına göre karar verilmeli.

BOYUT AZALTIMI

Özellik sayısını azaltmanın biraz daha az manuel bir yöntemi boyut azaltımı yöntemidir. Boyut azaltımı yöntemi bir çeşit gözetimsiz öğrenme (unsupervised learning) yöntemidir. Doğrusal ya da doğrusal olmayan bir şekilde yapılabilir ve bir özellik çıkarma yöntemidir. Mevcut özelliklerden daha az sayıda yeni özellikler çıkarır. Veri yeni ve farklı özelliklere dönüştürülür.

Bu kısımda göreceğimiz boyut azaltımı yöntemi temel bileşen analizi (principal component analysis - PCA) dir. PCA doğrusal dönüştürme yöntemini kullanarak, özellikleri, birbirleriyle tamamen ilişkisiz oldukları (korelasyonları "sıfır" olan) bir uzaya yansıtır. Özelliklerin sayısı azalırken, modelin kurulmasına yarayan değişkenlik bilgisi bileşenlerin içinde saklanır.

PCA manuel olarak eleyemediğimiz ve çok sayıda özelliğin olduğu durumlarda çok işe yarayan bir yöntemdir.

Bir veri setinin PCA ile dönüştürmek, scikit-learn paketi ile kolayca yapılabilir. Bu kısımda [Kaggle]CarPrice_Assignment.csv'dan CarPrice_Assignment.csv isimli veri setini kullanacağız. Veri setinde araba fiyatını etkileyen değişkenler ve değişik modellerin fiyatları yer alıyor:

In [4]:
# `CarPrice_Assignment.csv` veri setinin oturuma yüklenmesi:
car = pd.read_csv("/Users/ulcay/Desktop/Python/2020-08/06.08.2020/CarPrice_Assignment.csv")
# `car` veri setine göz atılması:
car.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 205 entries, 0 to 204
Data columns (total 26 columns):
 #   Column            Non-Null Count  Dtype  
---  ------            --------------  -----  
 0   car_ID            205 non-null    int64  
 1   symboling         205 non-null    int64  
 2   CarName           205 non-null    object 
 3   fueltype          205 non-null    object 
 4   aspiration        205 non-null    object 
 5   doornumber        205 non-null    object 
 6   carbody           205 non-null    object 
 7   drivewheel        205 non-null    object 
 8   enginelocation    205 non-null    object 
 9   wheelbase         205 non-null    float64
 10  carlength         205 non-null    float64
 11  carwidth          205 non-null    float64
 12  carheight         205 non-null    float64
 13  curbweight        205 non-null    int64  
 14  enginetype        205 non-null    object 
 15  cylindernumber    205 non-null    object 
 16  enginesize        205 non-null    int64  
 17  fuelsystem        205 non-null    object 
 18  boreratio         205 non-null    float64
 19  stroke            205 non-null    float64
 20  compressionratio  205 non-null    float64
 21  horsepower        205 non-null    int64  
 22  peakrpm           205 non-null    int64  
 23  citympg           205 non-null    int64  
 24  highwaympg        205 non-null    int64  
 25  price             205 non-null    float64
dtypes: float64(8), int64(8), object(10)
memory usage: 41.8+ KB
In [5]:
car.head()
Out[5]:
car_ID symboling CarName fueltype aspiration doornumber carbody drivewheel enginelocation wheelbase ... enginesize fuelsystem boreratio stroke compressionratio horsepower peakrpm citympg highwaympg price
0 1 3 alfa-romero giulia gas std two convertible rwd front 88.6 ... 130 mpfi 3.47 2.68 9.0 111 5000 21 27 13495.0
1 2 3 alfa-romero stelvio gas std two convertible rwd front 88.6 ... 130 mpfi 3.47 2.68 9.0 111 5000 21 27 16500.0
2 3 1 alfa-romero Quadrifoglio gas std two hatchback rwd front 94.5 ... 152 mpfi 2.68 3.47 9.0 154 5000 19 26 16500.0
3 4 2 audi 100 ls gas std four sedan fwd front 99.8 ... 109 mpfi 3.19 3.40 10.0 102 5500 24 30 13950.0
4 5 2 audi 100ls gas std four sedan 4wd front 99.4 ... 136 mpfi 3.19 3.40 8.0 115 5500 18 22 17450.0

5 rows × 26 columns

In [6]:
# `car` veri setinden modele girmesini istediğimiz sayısal sütunların seçilmesi:
car = car.select_dtypes(include=["int64","float64"])
In [7]:
# `car` veri setinden modele girmesini istemediğimiz `car_ID`, `symboling` sütunlarının ve `price` yanıt değişkeninin silinmesi:
car_X = car.drop(["car_ID","symboling","price"], axis = 1)
In [8]:
# `sklearn.decomposition` modülünden PCA'in oturuma yüklenmesi: 
from sklearn.decomposition import PCA
# PCA nesnesinin oluşturulması
pca = PCA()
# PCA'in `car` veri setine uygulanması:
transformed_car = pca.fit_transform(car_X)
# Bileşenlerin toplam varyansı açıklama yüzdelerinin yazdırılması:
print(pca.explained_variance_ratio_)
[6.38105142e-01 3.59775735e-01 1.56265421e-03 3.98152137e-04
 7.62189316e-05 4.81352025e-05 1.36056916e-05 1.10087057e-05
 5.69322602e-06 1.86651515e-06 1.54759766e-06 1.73640402e-07
 6.77037487e-08]

PCA'in çıktısı olarak verdiğimiz özellik sayısı kadar bileşen çıkar. Fakat explained_variance_ratio niteliğini kullanarak, her bir bileşenin modeldeki varyansı açıklama yüzdesini görebiliriz. Böylece açıklama yüzdesi belirli bir baremin altında kalan bileşenleri dışarıda bırakma şansımız vardır. Burada ilk bileşenin varyans açıklama yüzdesinin %63.8, ikinci bileşenin %36 olduğunu görüyoruz. Diğerlerinde ise bu yüzde çok düşük. Eğer baremi %60 alırsak, PCA'in bize işlem sonucu tek bileşen çıkardığını söyleyebiliriz.

PCA ile ilgili ayrıca bilmemiz gereken şeyler şunlardır:

PCA bileşenlerini yorumlamak oldukça zor olabilir, Diğer boyut azaltma yöntemlerine göre biraz daha kara kutuya benzer, Tüm özellikler dönüştürüldüğü ve yeniden şekillendirildiği için, genellikle tüm ön işlemler bittikten sonra yapılması tavsiye edilir.

PCA ve diğer boyut azaltma yöntemlerini daha genizş bir şekilde başka bir eğitimde tekrar ele alacağız.