Tahap akhir sebuah alur analisis biasanya adalah model: prediksi total penjualan dari jumlah dan jenis produk, atau klasifikasi pelanggan dari perilaku belanja. scikit-learn adalah library machine learning standar Python, dan sejak awal library ini dirancang menerima DataFrame pandas sebagai input. Keuntungan besaranya terasa saat model selesai dilatih: nama kolom DataFrame tersimpan di dalam model, sehingga kita bisa melacak fitur mana yang dipakai. Pada Chapter ini kita menyusun pipeline prediksi total penjualan yang menggabungkan kolom kategori dan kolom numerik dalam satu alur.
Kontrak DataFrame dan scikit-learn #
Konvensi scikit-learn memisahkan dua peran: X berisi kolom fitur (prediktor) dan y berisi kolom target (nilai yang diprediksi). Keduanya diambil langsung dari DataFrame dengan seleksi kolom biasa — tidak perlu konversi ke array manual:
| Istilah | Artinya di pandas | Di contoh kita |
|---|---|---|
| fitur (feature) | kolom-kolom input, disimpan di X | kota, produk, jumlah |
| target (label) | satu kolom output, disimpan di y | total |
| estimator | objek yang punya fit() dan predict() | LinearRegression |
| transformer | objek yang punya fit() dan transform() | OneHotEncoder |
Manfaat memberi X berupa DataFrame (bukan ndarray) adalah atribut feature_names_in_: setelah fit(), model mengingat nama-nama kolomnya, dan peringatan “fitur tidak cocok” muncul bila urutan kolom berubah saat prediksi.
Menyiapkan Fitur dan Melatih Pipeline #
Kolom kota dan produk bertipe teks sehingga harus di-encode; kolom jumlah numerik boleh lewat begitu saja. ColumnTransformer menjalankan perlakuan berbeda per kolom, dan make_pipeline menyambungkannya ke model dalam satu objek:
import numpy as np
import pandas as pd
from sklearn.compose import ColumnTransformer
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import OneHotEncoder
penjualan = pd.DataFrame({
"kota": ["Jakarta", "Jakarta", "Jakarta", "Jakarta",
"Bandung", "Bandung", "Bandung", "Bandung",
"Surabaya", "Surabaya", "Surabaya", "Surabaya"],
"produk": ["Beras", "Minyak", "Gula", "Kopi",
"Beras", "Minyak", "Gula", "Kopi",
"Beras", "Minyak", "Gula", "Kopi"],
"jumlah": [40, 25, 30, 20, 32, 22, 27, 18, 36, 19, 25, 21],
"harga": [68000, 35000, 18000, 26000, 67500, 34500, 17500, 25500, 67000, 34000, 17200, 25000],
})
penjualan["total"] = penjualan["jumlah"] * penjualan["harga"]
fitur = ["kota", "produk", "jumlah"]
X = penjualan[fitur]
y = penjualan["total"]
X_latih, X_uji, y_latih, y_uji = train_test_split(
X, y, test_size=0.25, random_state=42
)
print("baris latih:", len(X_latih), "| baris uji:", len(X_uji))
print()
preprocessor = ColumnTransformer([
("kategori", OneHotEncoder(drop="first"), ["kota", "produk"]),
("angka", "passthrough", ["jumlah"]),
])
model = make_pipeline(preprocessor, LinearRegression())
model.fit(X_latih, y_latih)
print("feature_names_in_ :", model.feature_names_in_.tolist())
print("get_feature_names_out :", preprocessor.get_feature_names_out().tolist())
print()
prediksi = model.predict(X_uji)
print("prediksi:", np.round(prediksi, 0).astype(int).tolist())
print("aktual :", y_uji.tolist())
print("R^2 uji :", round(model.score(X_uji, y_uji), 3))Output yang Dihasilkan:
baris latih: 9 | baris uji: 3
feature_names_in_ : ['kota', 'produk', 'jumlah']
get_feature_names_out : ['kategori__kota_Jakarta', 'kategori__kota_Surabaya', 'kategori__produk_Gula', 'kategori__produk_Kopi', 'kategori__produk_Minyak', 'angka__jumlah']
prediksi: [77650, 295550, 2778100]
aktual : [430000, 646000, 2720000]
R^2 uji : 0.922Mari kita telaah baris-baris pentingnya:
- Baris 21-23 (
fitur = [...],X = ...,y = ...): pemisahan fitur dan target dilakukan dengan seleksi kolom pandas murni;Xtetap DataFrame sehingga nama kolom ikut terbawa. - Baris 25-27 (
train_test_split(...)): 12 baris diacak menjadi 9 baris latih dan 3 baris uji; argumenrandom_state=42membuat hasil acakan tetap sama setiap kali skrip dijalankan. - Baris 31-34 (
ColumnTransformer([...])): transformator bernamakategorimenerapkanOneHotEncoder(drop="first")padakotadanproduk, sementaraangkameneruskanjumlahtanpa diubah ("passthrough"). - Baris 35-36 (
make_pipeline(...),model.fit(...)): pipeline menyambungkan preprocessor danLinearRegression; satu panggilanfit()meng-latih seluruh rantai pada data latih. - Baris 38-39:
feature_names_in_membuktikan DataFrame yang melatih model, danget_feature_names_out()menampilkan enam kolom hasil transformasi: dua dummy kota, tiga dummy produk, dan satu kolomjumlah. - Baris 42-45 (
model.predict(X_uji)): prediksi dilakukan langsung terhadap DataFrame uji; perbandinganprediksidenganaktuallalu skorR^2mengukur ketepatan model pada data yang belum pernah dilihat.
Cara membaca hasil: model memprediksi baris uji cukup dekat (misalnya 2.778.100 untuk nilai aktual 2.720.000) meski belum persis, terlihat dari R² 0,922 pada tiga baris uji. Ketidaktepatan itu wajar — hubungan total = jumlah × harga bersifat interaktif, sedangkan regresi linear murni aditif. Untuk data latih yang jauh lebih besar, pola pipeline yang sama persis inilah yang dipakai, tinggal mengganti estimatornya.
Model sudah mampu memprediksi dari tabel yang hidup di memori. Pertanyaan berikutnya adalah menyimpan dan mengambil tabel itu sendiri dari tempat yang lebih permanen — database — dan itulah peran SQLAlchemy pada Chapter berikutnya.
Referensi resmi untuk pendalaman: dokumentasi scikit-learn dan panduan dasar-dasar pandas .