Veriyi Döve Döve Konuşturmak

Daha çok veri, daha fazla öznitelik, daha komplike modeller, en şahane parametre optimizasyonu. Başarı skorlarını az daha yukarı çekmek için ne takla atılması gerekiyorsa atın. Veri biliminin laneti budur. Ekonomist Ronald Coase zamanında pek güzel söylemiş: Veriye yeterince işkence ederseniz, sonunda herşeyi itiraf eder!

Gelin hiçbir bilgi içermeyen veriyi, aslında çok da uğraşmadan, nasıl konuşturduğumu anlatayım.

Platformumuz Python. Önce sklearn veri setlerinden meme kanseri veri setini yükleyelim.

from sklearn.datasets import load_breast_cancer
import pandas as pd
from sklearn.metrics import roc_auc_score
import lightgbm as lgb
import numpy as np

data = load_breast_cancer()
X = pd.DataFrame(data.data, columns=data.feature_names)
y = pd.Series(data.target)

Sonra hedef değişkeni ortalaması orijinal veri setiyle aynı ama rastgele bir değişkenle değiştirdim.

n, p = 1, y.mean()
np.random.seed(0)
y_fake = np.random.binomial(n, p, len(y))

X_train, X_test, y_train, y_test = train_test_split(X, y_fake, random_state=42)


params = {
        'task': 'train',
        'boosting_type': 'gbdt',
        'objective': 'binary',
        'metric': 'auc',
        'eval_metric': 'auc',
        'verbose': 0,
        }

data_all = lgb.Dataset(X_train, y_train)
data_valid = lgb.Dataset(X_test, y_test)



model = lgb.train(params, data_all, num_boost_round=1000, early_stopping_rounds=100, 
                  verbose_eval= 30, valid_sets = data_valid)
pred = model.predict(X_test)
print('Test set AUC: ', roc_auc_score(y_test, pred))
# Test set AUC: 0.531

Normal olarak öğrenemedi, rastgele bir değişkeni 0.5 üzerinde AUC’yle tahmin etmek sadece şans eseri olabilir. Veriyi dövmeye yeni öznitelikler türeterek başlayalım. Mesela, veri setindeki özniteliklerden ilkinin diğerleriyle oranına bakabiliriz:

for col in X.columns:
    X['1_over_{}'.format(col)] = X.iloc[:,0] / X[col]
X_train, X_test, y_train, y_test = train_test_split(X, y_fake, random_state=42)


params = {
        'task': 'train',
        'boosting_type': 'gbdt',
        'objective': 'binary',
        'metric': 'auc',
        'eval_metric': 'auc',
        'verbose': 0,
        }

data_all = lgb.Dataset(X_train, y_train)
data_valid = lgb.Dataset(X_test, y_test)



model = lgb.train(params, data_all, num_boost_round=1000, early_stopping_rounds=100, 
                  verbose_eval= 30, valid_sets = data_valid)
pred = model.predict(X_test)
print('Test set AUC: ', roc_auc_score(y_test, pred))
# Test set AUC: 0.559

Nasıl da akıllanmaya başladı görüyor musunuz, 0.559’a geldik. Şimdi biraz da modelin parametrelerini kurcalayalım. Feature fraction, modelin verideki özniteliklerin sadece bir kısmını kullanmasını sağlıyor, fabrika ayarı 1, onu biraz düşürelim arada önemli öznitelikleri seçsin. Min data in leaf, ağaçlardaki yaprakların en az kaç gözlem içermesi gerektiğini söylüyor, fabrika ayarı 20, onu da biraz düşürelim çünkü zaten veri setimiz küçük.

X_train, X_test, y_train, y_test = train_test_split(X, y_fake, random_state=42)


params = {
        'task': 'train',
        'boosting_type': 'gbdt',
        'objective': 'binary',
        'metric': 'auc',
        'eval_metric': 'auc',
        'feature_fraction': 0.6,
        'min_data_in_leaf': 15,
        'verbose': 0,
        }

data_all = lgb.Dataset(X_train, y_train)
data_valid = lgb.Dataset(X_test, y_test)



model = lgb.train(params, data_all, num_boost_round=1000, early_stopping_rounds=100, 
                  verbose_eval= 30, valid_sets = data_valid)
pred = model.predict(X_test)
print('Test set AUC: ', roc_auc_score(y_test, pred))
# Test set AUC: 0.580

Özniteliklerin oranlarını bir de ikinci sütun için oluşturalım:

for col in X.columns:
    X['2_over_{}'.format(col)] = X.iloc[:,1] / X[col]
X_train, X_test, y_train, y_test = train_test_split(X, y_fake, random_state=42)


params = {
        'task': 'train',
        'boosting_type': 'gbdt',
        'objective': 'binary',
        'metric': 'auc',
        'eval_metric': 'auc',
        'feature_fraction': 0.6,
        'min_data_in_leaf': 15,
        'verbose': 0,
        }

data_all = lgb.Dataset(X_train, y_train)
data_valid = lgb.Dataset(X_test, y_test)



model = lgb.train(params, data_all, num_boost_round=1000, early_stopping_rounds=100, 
                  verbose_eval= 30, valid_sets = data_valid)
pred = model.predict(X_test)
print('Test set AUC: ', roc_auc_score(y_test, pred))
# Test set AUC: 0.546

Olmadı, bu sefer başarıyı azalttık. Demek parametrelerle biraz daha oynamak lazım. Öznitelik sayısı arttı, demek feature fraction biraz daha düşebilir, min data in leaf’i de neden düşürmeyelim ki?

X_train, X_test, y_train, y_test = train_test_split(X, y_fake, random_state=42)


params = {
        'task': 'train',
        'boosting_type': 'gbdt',
        'objective': 'binary',
        'metric': 'auc',
        'eval_metric': 'auc',
        'feature_fraction': 0.5,
        'min_data_in_leaf': 10,
        'verbose': 0,
        }

data_all = lgb.Dataset(X_train, y_train)
data_valid = lgb.Dataset(X_test, y_test)



model = lgb.train(params, data_all, num_boost_round=1000, early_stopping_rounds=100, 
                  verbose_eval= 30, valid_sets = data_valid)
pred = model.predict(X_test)
print('Test set AUC: ', roc_auc_score(y_test, pred))
# Test set AUC: 0.579

Yine de 0.58’i geçemedik. Demek ki ikinci sütunun oranlarında iş yokmuş, biz bir de üçüncü sütunun diğerlerine oranına bakalım:

for col in X.columns:
    X['2_over_{}'.format(col)] = X.iloc[:,2] / X[col]
X_train, X_test, y_train, y_test = train_test_split(X, y_fake, random_state=42)


params = {
        'task': 'train',
        'boosting_type': 'gbdt',
        'objective': 'binary',
        'metric': 'auc',
        'eval_metric': 'auc',
        'feature_fraction': 0.35,
        'min_data_in_leaf': 5,
        'verbose': 0,
        }

data_all = lgb.Dataset(X_train, y_train)
data_valid = lgb.Dataset(X_test, y_test)



model = lgb.train(params, data_all, num_boost_round=1000, early_stopping_rounds=100, 
                  verbose_eval= 30, valid_sets = data_valid)
pred = model.predict(X_test)
print('Test set AUC: ', roc_auc_score(y_test, pred))
# Test set AUC: 0.593

Hah şöyle. Biraz da bunun parametreleriyle oynayalım:

X_train, X_test, y_train, y_test = train_test_split(X, y_fake, random_state=42)


params = {
        'task': 'train',
        'boosting_type': 'gbdt',
        'objective': 'binary',
        'metric': 'auc',
        'eval_metric': 'auc',
        'num_leaves': 28,
        'feature_fraction': 0.35,
        'min_data_in_leaf': 4,
        'verbose': 0,
        }

data_all = lgb.Dataset(X_train, y_train)
data_valid = lgb.Dataset(X_test, y_test)



model = lgb.train(params, data_all, num_boost_round=1000, early_stopping_rounds=100, 
                  verbose_eval= 30, valid_sets = data_valid)
pred = model.predict(X_test)
print('Test set AUC: ', roc_auc_score(y_test, pred))
# Test set AUC: 0.609

Evet, 0.6’nın üstüne attık kendimizi. Dileyen bu minvalde veriyi hırpalamaya devam edebilir.

O değişkeni de alalım, bunların oranlarını koyalım, bunların farklarını koyalım, parametreleri optimize edelim diye diye daha başarılı olduğunuzu sanarak başarısız olmak gördüğünüz gibi oldukça kolay. Modern YZ algoritmaları en ufak ilişkiyi öğrenebilecek yeteneğe sahip o yüzden tesadüfi başarılar sıklıkla yakalanıyor. Bu tuzağa düşmemenin en bilindik yolu çapraz doğrulamadır, ama bazen orada bile yanılmak mümkün. Bence daha da mühimi veriye çok fazla soru sormamak. Sıradan bütün değişkenlerin oranını alırsanız, elbet birileri alakalı çıkıyor görüyorsunuz. Bunun yerine spesifik hipotezler ortaya koyup (a ile b’nin oranı sonucu etkiliyor mu) bu hipotezlerin sahadan gelen bir dayanağı olmasına özen göstermek daha güvenilir sonuçlar verecektir. Aynı veri setine yüzlerce soru sorarak yanıt buluyorsanız, çapraz doğrulama kullansanız bile, en güzeli hiç eliniz değmemiş yeni bir veri setiyle yanıtınız kontrol etmektir.

İlk yorum yapan olun

Bir yanıt bırakın

E-posta hesabınız yayımlanmayacak.


*