Kuasai Scikit-learn Pipeline untuk memperlancar alur kerja machine learning Anda. Pelajari cara mengotomatisasi prapemrosesan, pelatihan model, dan penyesuaian hyperparameter.
Scikit-learn Pipeline: Panduan Utama untuk Otomatisasi Alur Kerja ML
Di dunia machine learning, membangun model sering digambarkan sebagai langkah akhir yang glamor. Namun, ilmuwan data dan insinyur ML yang berpengalaman tahu bahwa perjalanan menuju model yang kuat diaspal dengan serangkaian langkah penting, sering kali berulang, dan rawan kesalahan: pembersihan data, penskalaan fitur, penyandian variabel kategorikal, dan banyak lagi. Mengelola langkah-langkah ini secara individual untuk set pelatihan, validasi, dan pengujian dapat dengan cepat menjadi mimpi buruk logistik, yang mengarah pada bug yang halus dan, yang paling berbahaya, kebocoran data.
Di sinilah Pipeline Scikit-learn hadir untuk menyelamatkan. Ini bukan hanya kenyamanan; ini adalah alat fundamental untuk membangun sistem machine learning yang profesional, dapat direproduksi, dan siap produksi. Panduan komprehensif ini akan memandu Anda melalui semua yang perlu Anda ketahui untuk menguasai Pipeline Scikit-learn, dari konsep dasar hingga teknik tingkat lanjut.
Masalahnya: Alur Kerja Machine Learning Manual
Mari kita pertimbangkan tugas supervised learning yang khas. Bahkan sebelum Anda dapat memanggil model.fit(), Anda perlu menyiapkan data Anda. Alur kerja standar mungkin terlihat seperti ini:
- Pisahkan data: Bagi dataset Anda menjadi set pelatihan dan pengujian. Ini adalah langkah pertama dan paling penting untuk memastikan Anda dapat mengevaluasi kinerja model Anda pada data yang tidak terlihat.
- Tangani nilai yang hilang: Identifikasi dan imputasi data yang hilang dalam set pelatihan Anda (misalnya, menggunakan mean, median, atau konstanta).
- Enkode fitur kategorikal: Konversikan kolom non-numerik seperti 'Negara' atau 'Kategori Produk' menjadi format numerik menggunakan teknik seperti One-Hot Encoding atau Ordinal Encoding.
- Skala fitur numerik: Bawa semua fitur numerik ke skala yang serupa menggunakan metode seperti Standardisasi (
StandardScaler) atau Normalisasi (MinMaxScaler). Ini sangat penting untuk banyak algoritma seperti SVM, Regresi Logistik, dan Jaringan Neural. - Latih model: Terakhir, sesuaikan model machine learning pilihan Anda pada data pelatihan yang telah diproses sebelumnya.
Sekarang, ketika Anda ingin membuat prediksi pada set pengujian Anda (atau data baru yang tidak terlihat), Anda harus mengulangi langkah-langkah prapemrosesan yang sama persis. Anda harus menerapkan strategi imputasi yang sama (menggunakan nilai yang dihitung dari set pelatihan), skema penyandian yang sama, dan parameter penskalaan yang sama. Melacak semua transformer yang disesuaikan ini secara manual sangat membosankan dan merupakan sumber utama kesalahan.
Risiko terbesar di sini adalah kebocoran data. Ini terjadi ketika informasi dari set pengujian secara tidak sengaja bocor ke dalam proses pelatihan. Misalnya, jika Anda menghitung mean untuk imputasi atau parameter penskalaan dari seluruh dataset sebelum pemisahan, model Anda secara implisit belajar dari data pengujian. Hal ini menyebabkan perkiraan kinerja yang terlalu optimis dan model yang gagal total di dunia nyata.
Memperkenalkan Pipeline Scikit-learn: Solusi Otomatis
Pipeline Scikit-learn adalah objek yang merangkai beberapa langkah transformasi data dan estimator akhir (seperti pengklasifikasi atau regressor) menjadi satu objek terpadu. Anda dapat menganggapnya sebagai jalur perakitan untuk data Anda.
Ketika Anda memanggil .fit() pada Pipeline, ia secara berurutan menerapkan fit_transform() ke setiap langkah perantara pada data pelatihan, meneruskan output dari satu langkah sebagai input ke langkah berikutnya. Akhirnya, ia memanggil .fit() pada langkah terakhir, estimator. Ketika Anda memanggil .predict() atau .transform() pada Pipeline, ia hanya menerapkan metode .transform() dari setiap langkah perantara ke data baru sebelum membuat prediksi dengan estimator akhir.
Manfaat Utama Menggunakan Pipeline
- Pencegahan Kebocoran Data: Ini adalah manfaat yang paling penting. Dengan mengenkapsulasi semua prapemrosesan di dalam pipeline, Anda memastikan bahwa transformasi dipelajari hanya dari data pelatihan selama validasi silang dan diterapkan dengan benar ke data validasi/pengujian.
- Kesederhanaan dan Organisasi: Seluruh alur kerja Anda, dari data mentah hingga model yang terlatih, diringkas menjadi satu objek. Ini membuat kode Anda lebih bersih, lebih mudah dibaca, dan lebih mudah dikelola.
- Reproduktibilitas: Objek Pipeline mengenkapsulasi seluruh proses pemodelan Anda. Anda dapat dengan mudah menyimpan objek tunggal ini (misalnya, menggunakan `joblib` atau `pickle`) dan memuatnya nanti untuk membuat prediksi, memastikan bahwa langkah-langkah yang sama persis diikuti setiap saat.
- Efisiensi dalam Pencarian Grid: Anda dapat melakukan penyetelan hyperparameter di seluruh pipeline sekaligus, menemukan parameter terbaik untuk langkah-langkah prapemrosesan dan model akhir secara bersamaan. Kita akan menjelajahi fitur canggih ini nanti.
Membangun Pipeline Sederhana Pertama Anda
Mari kita mulai dengan contoh dasar. Bayangkan kita memiliki dataset numerik dan kita ingin menskalakan data sebelum melatih model Regresi Logistik. Inilah cara Anda membangun pipeline untuk itu.
Pertama, mari kita siapkan lingkungan kita dan buat beberapa contoh data.
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipeline
from sklearn.metrics import accuracy_score
# Generate some sample data
X, y = np.random.rand(100, 5) * 10, (np.random.rand(100) > 0.5).astype(int)
# Split data into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
Sekarang, mari kita definisikan pipeline kita. Sebuah pipeline dibuat dengan menyediakan daftar langkah. Setiap langkah adalah tuple yang berisi nama (string pilihan Anda) dan objek transformer atau estimator itu sendiri.
# Create the pipeline steps
steps = [
('scaler', StandardScaler()),
('classifier', LogisticRegression())
]
# Create the Pipeline object
pipe = Pipeline(steps)
# Now, you can treat the 'pipe' object as if it were a regular model.
# Let's train it on our training data.
pipe.fit(X_train, y_train)
# Make predictions on the test data
y_pred = pipe.predict(X_test)
# Evaluate the model
accuracy = accuracy_score(y_test, y_pred)
print(f"Pipeline Accuracy: {accuracy:.4f}")
Itu saja! Hanya dalam beberapa baris, kita telah menggabungkan penskalaan dan klasifikasi. Scikit-learn menangani semua logika perantara. Ketika pipe.fit(X_train, y_train) dipanggil, ia pertama-tama memanggil StandardScaler().fit_transform(X_train) dan kemudian meneruskan hasilnya ke LogisticRegression().fit(). Ketika pipe.predict(X_test) dipanggil, ia menerapkan scaler yang sudah disesuaikan menggunakan StandardScaler().transform(X_test) sebelum membuat prediksi dengan model regresi logistik.
Menangani Data Heterogen: ColumnTransformer
Dataset dunia nyata jarang sederhana. Mereka sering mengandung campuran tipe data: kolom numerik yang perlu diskalakan, kolom kategorikal yang perlu dienkode, dan mungkin kolom teks yang perlu di-vektorisasi. Pipeline sekuensial sederhana tidak cukup untuk ini, karena Anda perlu menerapkan transformasi yang berbeda ke kolom yang berbeda.
Di sinilah ColumnTransformer bersinar. Ini memungkinkan Anda untuk menerapkan transformer yang berbeda ke subset kolom yang berbeda dalam data Anda dan kemudian menggabungkan hasilnya secara cerdas. Ini adalah alat yang sempurna untuk digunakan sebagai langkah prapemrosesan dalam pipeline yang lebih besar.
Contoh: Menggabungkan Fitur Numerik dan Kategorikal
Mari kita buat dataset yang lebih realistis dengan fitur numerik dan kategorikal menggunakan pandas.
import pandas as pd
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder
from sklearn.impute import SimpleImputer
# Create a sample DataFrame
data = {
'age': [25, 30, 45, 35, 50, np.nan, 22],
'salary': [50000, 60000, 120000, 80000, 150000, 75000, 45000],
'country': ['USA', 'Canada', 'USA', 'UK', 'Canada', 'USA', 'UK'],
'purchased': [0, 1, 1, 0, 1, 1, 0]
}
df = pd.DataFrame(data)
X = df.drop('purchased', axis=1)
y = df['purchased']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Identify numerical and categorical columns
numerical_features = ['age', 'salary']
categorical_features = ['country']
Strategi prapemrosesan kita adalah:
- Untuk kolom numerik (
age,salary): Imputasi nilai yang hilang dengan median, lalu skala mereka. - Untuk kolom kategorikal (
country): Imputasi nilai yang hilang dengan kategori yang paling sering, lalu enkode satu-panas (one-hot encode) mereka.
Kita dapat mendefinisikan langkah-langkah ini menggunakan dua mini-pipeline terpisah.
# Create a pipeline for numerical features
numeric_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='median')),
('scaler', StandardScaler())
])
# Create a pipeline for categorical features
categorical_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='most_frequent')),
('onehot', OneHotEncoder(handle_unknown='ignore'))
])
Sekarang, kita menggunakan `ColumnTransformer` untuk menerapkan pipeline ini ke kolom yang benar.
# Create the preprocessor with ColumnTransformer
preprocessor = ColumnTransformer(
transformers=[
('num', numeric_transformer, numerical_features),
('cat', categorical_transformer, categorical_features)
])
`ColumnTransformer` mengambil daftar `transformer`. Setiap transformer adalah tuple yang berisi nama, objek transformer (yang dapat berupa pipeline itu sendiri), dan daftar nama kolom untuk diterapkan padanya.
Akhirnya, kita dapat menempatkan `preprocessor` ini sebagai langkah pertama dalam pipeline utama kita, diikuti oleh estimator akhir kita.
from sklearn.ensemble import RandomForestClassifier
# Create the full pipeline
full_pipeline = Pipeline(steps=[
('preprocessor', preprocessor),
('classifier', RandomForestClassifier(random_state=42))
])
# Train and evaluate the full pipeline
full_pipeline.fit(X_train, y_train)
print("Model score on test data:", full_pipeline.score(X_test, y_test))
# You can now make predictions on new raw data
new_data = pd.DataFrame({
'age': [40, 28],
'salary': [90000, 55000],
'country': ['USA', 'Germany'] # 'Germany' is an unknown category
})
predictions = full_pipeline.predict(new_data)
print("Predictions for new data:", predictions)
Perhatikan betapa elegannya ini menangani alur kerja yang kompleks. Parameter `handle_unknown='ignore'` dalam `OneHotEncoder` sangat berguna untuk sistem produksi, karena mencegah kesalahan ketika kategori baru yang tidak terlihat muncul dalam data.
Teknik Pipeline Tingkat Lanjut
Pipeline menawarkan lebih banyak kekuatan dan fleksibilitas. Mari kita jelajahi beberapa fitur tingkat lanjut yang penting untuk proyek machine learning profesional.
Membuat Transformer Kustom
Terkadang, transformer Scikit-learn bawaan tidak cukup. Anda mungkin perlu melakukan transformasi khusus domain, seperti mengekstrak logaritma dari fitur atau menggabungkan dua fitur menjadi yang baru. Anda dapat dengan mudah membuat transformer kustom Anda sendiri yang terintegrasi dengan mulus ke dalam pipeline.
Untuk melakukan ini, Anda membuat kelas yang mewarisi dari `BaseEstimator` dan `TransformerMixin`. Anda hanya perlu mengimplementasikan metode `fit()` dan `transform()` (dan `__init__()` jika diperlukan).
Mari kita buat transformer yang menambahkan fitur baru: rasio `salary` terhadap `age`.
from sklearn.base import BaseEstimator, TransformerMixin
# Define column indices (can also pass names)
age_ix, salary_ix = 0, 1
class FeatureRatioAdder(BaseEstimator, TransformerMixin):
def __init__(self):
pass # No parameters to set
def fit(self, X, y=None):
return self # Nothing to learn during fit, so just return self
def transform(self, X):
salary_age_ratio = X[:, salary_ix] / X[:, age_ix]
return np.c_[X, salary_age_ratio] # Concatenate original X with new feature
Anda kemudian dapat memasukkan transformer kustom ini ke dalam pipeline pemrosesan numerik Anda:
numeric_transformer_with_custom = Pipeline(steps=[
('imputer', SimpleImputer(strategy='median')),
('ratio_adder', FeatureRatioAdder()), # Our custom transformer
('scaler', StandardScaler())
])
Tingkat penyesuaian ini memungkinkan Anda untuk mengenkapsulasi semua logika rekayasa fitur Anda di dalam pipeline, membuat alur kerja Anda sangat portabel dan dapat direproduksi.
Penyetelan Hyperparameter dengan Pipeline menggunakan GridSearchCV
Ini bisa dibilang salah satu aplikasi Pipeline yang paling kuat. Anda dapat mencari hyperparameter terbaik untuk seluruh alur kerja Anda, termasuk langkah-langkah prapemrosesan dan model akhir, sekaligus.
Untuk menentukan parameter mana yang akan disetel, Anda menggunakan sintaks khusus: `step_name__parameter_name`.
Mari kita perluas contoh sebelumnya dan setel hyperparameter untuk imputer di prapemroses kita dan `RandomForestClassifier`.
from sklearn.model_selection import GridSearchCV
# We use the 'full_pipeline' from the ColumnTransformer example
# Define the parameter grid
param_grid = {
'preprocessor__num__imputer__strategy': ['mean', 'median'],
'classifier__n_estimators': [50, 100, 200],
'classifier__max_depth': [None, 10, 20],
'classifier__min_samples_leaf': [1, 2, 4]
}
# Create the GridSearchCV object
grid_search = GridSearchCV(full_pipeline, param_grid, cv=5, verbose=1, n_jobs=-1)
# Fit it to the data
grid_search.fit(X_train, y_train)
# Print the best parameters and score
print("Best parameters found: ", grid_search.best_params_)
print("Best cross-validation score: ", grid_search.best_score_)
# The best estimator is already refitted on the whole training data
best_model = grid_search.best_estimator_
print("Test set score with best model: ", best_model.score(X_test, y_test))
Perhatikan baik-baik kunci dalam `param_grid`:
'preprocessor__num__imputer__strategy': Ini menargetkan parameter `strategy` dari langkah `SimpleImputer` bernama `imputer` di dalam pipeline numerik bernama `num`, yang sendiri berada di dalam `ColumnTransformer` bernama `preprocessor`.'classifier__n_estimators': Ini menargetkan parameter `n_estimators` dari estimator akhir bernama `classifier`.
Dengan melakukan ini, `GridSearchCV` dengan benar mencoba semua kombinasi dan menemukan set parameter optimal untuk seluruh alur kerja, sepenuhnya mencegah kebocoran data selama proses penyetelan karena semua prapemrosesan dilakukan di dalam setiap lipatan validasi silang.
Memvisualisasikan dan Memeriksa Pipeline Anda
Pipeline yang kompleks dapat menjadi sulit untuk dipahami. Scikit-learn menyediakan cara yang bagus untuk memvisualisasikannya. Mulai dari versi 0.23, Anda bisa mendapatkan representasi HTML interaktif.
from sklearn import set_config
# Set display to 'diagram' to get the visual representation
set_config(display='diagram')
# Now, simply displaying the pipeline object in a Jupyter Notebook or similar environment will render it
full_pipeline
Ini akan menghasilkan diagram yang menunjukkan aliran data melalui setiap transformer dan estimator, beserta nama mereka. Ini sangat berguna untuk debugging, berbagi pekerjaan Anda, dan memahami struktur model Anda.
Anda juga dapat mengakses langkah-langkah individual dari pipeline yang disesuaikan menggunakan nama mereka:
# Access the final classifier of the fitted pipeline
final_classifier = full_pipeline.named_steps['classifier']
print("Feature importances:", final_classifier.feature_importances_)
# Access the OneHotEncoder to see the learned categories
onehot_encoder = full_pipeline.named_steps['preprocessor'].named_transformers_['cat'].named_steps['onehot']
print("Categorical features learned:", onehot_encoder.categories_)
Kesalahan Umum dan Praktik Terbaik
- Menyesuaikan pada Data yang Salah: Selalu, selalu sesuaikan pipeline Anda pada data pelatihan SAJA. Jangan pernah menyesuaikannya pada seluruh dataset atau set pengujian. Ini adalah aturan utama untuk mencegah kebocoran data.
- Format Data: Perhatikan format data yang diharapkan oleh setiap langkah. Beberapa transformer (seperti yang ada dalam contoh kustom kita) mungkin bekerja dengan array NumPy, sementara yang lain lebih nyaman dengan Pandas DataFrames. Scikit-learn umumnya pandai menangani ini, tetapi ini adalah sesuatu yang perlu diperhatikan, terutama dengan transformer kustom.
- Menyimpan dan Memuat Pipeline: Untuk menerapkan model Anda, Anda perlu menyimpan pipeline yang disesuaikan. Cara standar untuk melakukan ini dalam ekosistem Python adalah dengan `joblib` atau `pickle`. `joblib` seringkali lebih efisien untuk objek yang membawa array NumPy besar.
import joblib # Save the pipeline joblib.dump(full_pipeline, 'my_model_pipeline.joblib') # Load the pipeline later loaded_pipeline = joblib.load('my_model_pipeline.joblib') # Make predictions with the loaded model loaded_pipeline.predict(new_data) - Gunakan Nama Deskriptif: Beri langkah-langkah pipeline Anda dan komponen `ColumnTransformer` nama yang jelas dan deskriptif (misalnya, 'numeric_imputer', 'categorical_encoder', 'svm_classifier'). Ini membuat kode Anda lebih mudah dibaca dan menyederhanakan penyetelan hyperparameter dan debugging.
Kesimpulan: Mengapa Pipeline Tidak Dapat Dinegosiasikan untuk ML Profesional
Pipeline Scikit-learn bukan hanya alat untuk menulis kode yang lebih rapi; mereka mewakili perubahan paradigma dari scripting manual yang rawan kesalahan ke pendekatan sistematis, kuat, dan dapat direproduksi untuk machine learning. Mereka adalah tulang punggung praktik rekayasa ML yang baik.
Dengan mengadopsi pipeline, Anda mendapatkan:
- Ketahanan: Anda menghilangkan sumber kesalahan paling umum dalam proyek machine learning—kebocoran data.
- Efisiensi: Anda memperlancar seluruh alur kerja Anda, dari rekayasa fitur hingga penyetelan hyperparameter, menjadi satu unit yang kohesif.
- Reproduktibilitas: Anda membuat objek serial yang tunggal yang berisi seluruh logika model Anda, sehingga mudah diterapkan dan dibagikan.
Jika Anda serius tentang membangun model machine learning yang bekerja dengan andal di dunia nyata, menguasai Pipeline Scikit-learn bukanlah opsional—itu penting. Mulai gabungkan mereka ke dalam proyek Anda hari ini, dan Anda akan membangun model yang lebih baik dan lebih andal lebih cepat dari sebelumnya.