veri bilimi · türkçe
Hakkımda🗺️ Haritam
AnasayfaTüm İçerikler
Ana sayfarehber

Scikit-learn Pipeline'ları

2025 · 20 dakika okuma · scikit-learn 1.4+

Çoğu ML kodu şöyle başlar: veriyi yükle, eksik değerleri doldur, ölçeklendir, encode et, modeli eğit. Çalışır. Ama tekrar kullanılamaz, test verisine yanlışlıkla uygulanır ve GridSearchCV'ye giremiyor.

Pipeline, bu adımları tek bir nesne altında birleştirir. Bir fitçağrısıyla hepsi sırayla çalışır. Veri sızıntısını önler, kodu temizler, production'a taşımayı kolaylaştırır.

Tipik bir pipeline akışı:

📋Ham Veri
🩹Imputer
⚖️Scaler
🔤Encoder
🤖Model
Tahmin

Pipeline olmadan ne olur?

Klasik hata: StandardScaler'ı tüm veri üzerinde fit edip sonra train/test split yapmak. Test verisindeki istatistikler modele sızdı — sonuçlar gerçekten iyi görünür, production'da berbat çalışır.

# ❌ Yanlış — veri sızıntısı var
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)          # test verisi de burada!

X_train, X_test, y_train, y_test = train_test_split(X_scaled, y)

model = LogisticRegression()
model.fit(X_train, y_train)
# Test istatistikleri scale işlemine karıştı → iyimser sonuç

# ✅ Doğru — Pipeline ile
from sklearn.pipeline import Pipeline

pipeline = Pipeline([
    ('scaler', StandardScaler()),
    ('model',  LogisticRegression()),
])

X_train, X_test, y_train, y_test = train_test_split(X, y)
pipeline.fit(X_train, y_train)   # scaler sadece X_train'e fit olur
pipeline.score(X_test, y_test)   # X_test transform edilir, hiç fit olmaz

Temel yapı

Pipeline bir adımlar listesi alır. Her adım bir(isim, transformer) demetidir. Son adım model (estimator), öncekiler transformer olmak zorundadır.

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression

# Her adım: ('isim', nesne)
pipeline = Pipeline([
    ('scaler', StandardScaler()),
    ('model',  LogisticRegression(max_iter=1000)),
])

# Tüm sklearn API'si geçerli
pipeline.fit(X_train, y_train)
y_pred  = pipeline.predict(X_test)
y_prob  = pipeline.predict_proba(X_test)
score   = pipeline.score(X_test, y_test)

# Ara adıma erişim
fitted_scaler = pipeline.named_steps['scaler']
print(fitted_scaler.mean_)            # fit sonrası öğrenilen mean

make_pipeline — kısa yol

İsim vermek istemiyorsan make_pipeline class adını küçük harfe çevirerek otomatik atar.

from sklearn.pipeline import make_pipeline

# Uzun hali
Pipeline([('standardscaler', StandardScaler()), ('logisticregression', LogisticRegression())])

# make_pipeline kısa yolu — aynı sonuç
pipe = make_pipeline(StandardScaler(), LogisticRegression())

# Adım isimlerine erişim
pipe.named_steps.keys()
# dict_keys(['standardscaler', 'logisticregression'])

ColumnTransformer — karışık veri tipleri

Gerçek veriler karışık gelir: bazı sütunlar numerik, bazıları kategorik.ColumnTransformer, farklı sütun gruplarına farklı transformer uygulamanı sağlar.

from sklearn.compose    import ColumnTransformer
from sklearn.pipeline   import Pipeline
from sklearn.impute     import SimpleImputer
from sklearn.preprocessing import StandardScaler, OneHotEncoder

# Sütun grupları
numerik    = ['yas', 'gelir', 'toplam_siparis']
kategorik  = ['sehir', 'meslek', 'urun_kategorisi']

# Numerik pipeline
num_pipe = Pipeline([
    ('imputer', SimpleImputer(strategy='median')),
    ('scaler',  StandardScaler()),
])

# Kategorik pipeline
cat_pipe = Pipeline([
    ('imputer', SimpleImputer(strategy='most_frequent')),
    ('encoder', OneHotEncoder(handle_unknown='ignore', sparse_output=False)),
])

# ColumnTransformer ile birleştir
preprocessor = ColumnTransformer([
    ('numerik',    num_pipe, numerik),
    ('kategorik',  cat_pipe, kategorik),
])

# Tam pipeline
pipeline = Pipeline([
    ('preprocessor', preprocessor),
    ('model',        LogisticRegression(max_iter=1000)),
])

handle_unknown='ignore'olmadan, test verisinde eğitimde görmediğin bir kategori değeri gelirse OneHotEncoder hata fırlatır. Production'da bu mutlaka olur — parametreyi unutma.

Pipeline oluşturucu

Hangi adımları kullanacağını seç, kod otomatik oluşsun. Kopyalayıp projena yapıştırabilirsin.

🔧Pipeline Oluşturucuseçimlerini yap, kodu al
📋Ham Veri
🩹Imputer
⚖️Scaler
🔤Encoder
🤖Model
Tahmin
NUMERİK ÖNIŞLEM
KATEGORİK ÖNIŞLEM
MODEL
ÜRETİLEN KOD
from sklearn.pipeline import Pipeline, make_pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.ensemble import RandomForestClassifier

# Sütun listelerini tanımla
numerik_sutunlar = ['yas', 'gelir', 'skor']
kategorik_sutunlar = ['sehir', 'meslek', 'kategori']

preprocessor = ColumnTransformer(transformers=[
    ('numerik', Pipeline([
        ('imputer', SimpleImputer(strategy='mean')),
        ('scaler', StandardScaler()),
    ]), numerik_sutunlar),
    ('kategorik', Pipeline([
        ('encoder', OneHotEncoder(handle_unknown='ignore')),
    ]), kategorik_sutunlar),
])

pipeline = Pipeline([
    ('preprocessor', preprocessor),
    ('model', RandomForestClassifier(n_estimators=100)),
])

# Eğit ve değerlendir
pipeline.fit(X_train, y_train)
y_pred   = pipeline.predict(X_test)
score    = pipeline.score(X_test, y_test)
print(f"Test skoru: {score:.3f}")

GridSearchCV entegrasyonu

Pipeline'ın en büyük gücü burada. Hyperparameter search'te hem model hem de ön-işlem adımlarının parametrelerini aynı anda arayabilirsin. Parametre isimleri adim__parametre şeklinde belirtilir.

from sklearn.model_selection import GridSearchCV

pipeline = Pipeline([
    ('imputer', SimpleImputer()),
    ('scaler',  StandardScaler()),
    ('model',   RandomForestClassifier()),
])

# 'adim__parametre' formatı
param_grid = {
    'imputer__strategy':          ['mean', 'median'],
    'model__n_estimators':        [50, 100, 200],
    'model__max_depth':           [None, 5, 10],
    'model__min_samples_split':   [2, 5],
}

grid = GridSearchCV(
    pipeline,
    param_grid,
    cv=5,
    scoring='roc_auc',
    n_jobs=-1,
)

grid.fit(X_train, y_train)

print(grid.best_params_)
print(f"En iyi CV skoru: {grid.best_score_:.4f}")
print(f"Test skoru: {grid.score(X_test, y_test):.4f}")

Custom Transformer yazmak

Sklearn'in sunmadığı bir dönüşüme ihtiyacın varsa — log transform, domain-specific feature engineering, özel imputation — kendi transformer'ını yazabilirsin. İki şartı sağlarsan Pipeline'a doğrudan girebilir.

from sklearn.base import BaseEstimator, TransformerMixin
import numpy as np

class LogTransformer(BaseEstimator, TransformerMixin):
    """Pozitif sayısal sütunlara log1p uygular (0 değerlerine güvenli)."""

    def __init__(self, epsilon=1e-8):
        self.epsilon = epsilon

    def fit(self, X, y=None):
        return self          # öğrenecek bir şey yok

    def transform(self, X):
        return np.log1p(np.maximum(X, self.epsilon))

    def inverse_transform(self, X):
        return np.expm1(X)


# Pipeline'a tak
pipe = Pipeline([
    ('log',    LogTransformer()),
    ('scaler', StandardScaler()),
    ('model',  Ridge()),
])
pipe.fit(X_train, y_train)
# Daha karmaşık örnek: özel feature engineering
class GelirYasOran(BaseEstimator, TransformerMixin):
    """Gelir/Yaş oranı özelliği ekler."""

    def __init__(self, gelir_col=0, yas_col=1):
        self.gelir_col = gelir_col
        self.yas_col   = yas_col

    def fit(self, X, y=None):
        return self

    def transform(self, X):
        X = X.copy()
        oran = X[:, self.gelir_col] / (X[:, self.yas_col] + 1)
        return np.hstack([X, oran.reshape(-1, 1)])

    def get_feature_names_out(self, input_features=None):
        base = list(input_features or [f'x{i}' for i in range(self.n_features_in_)])
        return base + ['gelir_yas_orani']

Pipeline'ı kaydetmek ve yüklemek

Fit edilmiş pipeline tek bir dosyaya kaydedilebilir — scaler'ın öğrendiği istatistikler, encoder'ın kategorileri, modelin ağırlıkları hepsi birlikte.

import joblib

# Kaydet
joblib.dump(pipeline, 'model_pipeline.pkl')

# Yükle ve tahmin et — tek satır
pipeline = joblib.load('model_pipeline.pkl')
y_pred = pipeline.predict(yeni_veri)   # scaler/encoder otomatik uygulanır

# Versiyon notı: joblib.load, modeli eğittiğin sklearn
# sürümüyle aynı veya uyumlu sürümde çalışmalı.
# Production'da sklearn versiyonunu requirements.txt'e yaz.

set_output API — DataFrame çıktısı

Sklearn 1.2'den itibaren Pipeline çıktısını otomatik DataFrame'e dönüştürebilirsin. Debug ve feature importance için çok kullanışlı.

from sklearn import set_config

set_config(transform_output='pandas')  # global ayar

pipeline = Pipeline([
    ('preprocessor', preprocessor),
    ('model',        RandomForestClassifier()),
])

# Sadece transform adımlarının çıktısı
X_transformed = pipeline[:-1].transform(X_train)
print(type(X_transformed))       # <class 'pandas.core.frame.DataFrame'>
print(X_transformed.columns)     # sütun isimli çıktı

# Feature importance ile birleştir
importances = pipeline['model'].feature_importances_
feat_imp = pd.Series(importances, index=X_transformed.columns)
feat_imp.sort_values(ascending=False).head(10)

Sık yapılan hatalar

Pipeline, prototipten production'a en temiz geçişi sağlar. Bir sonraki adım: Pipeline'ı MLflow veya BentoMLile deploy etmek — aynı Pipeline nesnesi REST endpoint'e dönüşür.

Bu içerik:

Faydalı bulduysan paylaş

X'te paylaşLinkedIn'de paylaş

💬 Yorumlar