Model machine learning yang canggih sekalipun tidak bisa menyelamatkan dataset yang disiapkan asal-asalan. Kesalahan klasik seperti lupa memeriksa nilai kosong, membiarkan data uji tidak seimbang, atau melatih model tanpa baseline pembanding sering baru terasa ketika model sudah berjalan di produksi. Pada chapter ini kita menyiapkan dataset mini langkah demi langkah: pemeriksaan higiene, pembagian train/test, encoding kolom kategori, dan baseline pembanding, semuanya dengan pandas dan scikit-learn.
Konvensi X dan y #
Scikit-learn menerima data dalam dua variabel terpisah. X (huruf besar) adalah tabel fitur berbentuk DataFrame atau array dua dimensi; setiap baris adalah satu contoh data, setiap kolom adalah satu fitur. y (huruf kecil) adalah kolom target berbentuk Series atau array satu dimensi yang berisi jawaban benar untuk setiap baris pada X. Pemisahan ini bukan gaya-gayaan: hampir seluruh API scikit-learn, dari fit() sampai cross_val_score(), memakai signature fit(X, y).
Sebagai bahan kerja, kita pakai dataset fiktif 16 pelanggan toko daring beserta status berlangganan premium mereka:
import pandas as pd
df = pd.DataFrame({
"usia": [22, 25, 30, 35, 40, 45, 50, 55, 27, 32, 38, 44, 52, 58, 29, 47],
"pendapatan_juta": [4.2, 5.0, 6.5, 8.0, 9.5, None, 10.5, 12.0,
5.5, 7.2, 8.8, 10.0, 11.0, 9.0, 6.0, 9.8],
"kota": ["Bandung", "Jakarta", "Surabaya", "Bandung", "Jakarta",
"Surabaya", "Bandung", "Jakarta", "Surabaya", "Bandung",
"Jakarta", "Surabaya", "Bandung", "Jakarta", "Surabaya", "Bandung"],
"berlangganan": [0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1],
})Higiene Data Sebelum Melatih Model #
Dua pemeriksaan pertama yang wajib dijalankan pada DataFrame baru adalah jumlah nilai kosong per kolom dan tipe data tiap kolom. Nilai None atau NaN membuat sebagian besar algoritma scikit-learn menolak data, dan kolom angka yang tersimpan sebagai object hampir selalu pertanda ada data kotor:
print(df.isnull().sum())
print()
print(df.dtypes)
print()
df_bersih = df.dropna()
print(f"Jumlah baris setelah dropna: {len(df_bersih)}")Output yang Dihasilkan:
usia 0
pendapatan_juta 1
kota 0
berlangganan 0
dtype: int64
usia int64
pendapatan_juta float64
kota object
berlangganan int64
dtype: object
Jumlah baris setelah dropna: 15Hasil pemeriksaan menunjukkan satu nilai kosong pada kolom pendapatan_juta dan tipe data yang wajar untuk semua kolom. Method dropna() membuang satu baris bermasalah tersebut, menyisakan 15 baris. Pada dataset kecil, membuang baris terasa murah; pada dataset besar, alternatif yang lebih hemat adalah mengisi nilai kosong dengan median kolom, misalnya df["pendapatan_juta"].fillna(df["pendapatan_juta"].median()). Teknik pengisian ini dibahas lebih dalam pada chapter Data Cleaning dengan Pandas.
Membagi Data dengan train_test_split #
Setelah data bersih, kita pisahkan fitur dari label lalu membagi keduanya menjadi data latih dan data uji:
from sklearn.model_selection import train_test_split
X = df_bersih[["usia", "pendapatan_juta", "kota"]]
y = df_bersih["berlangganan"]
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.25, random_state=42, stratify=y
)
print(f"X_train: {X_train.shape}")
print(f"X_test : {X_test.shape}")
print(f"y_train: {y_train.shape}")
print(f"y_test : {y_test.shape}")
print(y_train.value_counts().to_string())Output yang Dihasilkan:
X_train: (11, 3)
X_test : (4, 3)
y_train: (11,)
y_test : (4,)
berlangganan
1 7
0 4Mari kita bedah argumen-argumen train_test_split():
test_size=0.25: 25 persen data menjadi data uji, 75 persen menjadi data latih. Data uji yang lebih besar membuat evaluasi lebih stabil tetapi menyisakan lebih sedikit bahan belajar.random_state=42: pembagian diacak secara deterministik. Menjalankan ulang kode dengan angka yang sama selalu menghasilkan pembagian yang sama, sehingga pembaca lain bisa mereproduksi hasil kita.stratify=y: proporsi kelas padaydijaga hampir sama di kedua sisi. Tanpa argumen ini pada dataset kecil, data uji bisa kebetulan berisi satu kelas saja dan evaluasi menjadi menyesatkan.
Output y_train.value_counts() memperlihatkan komposisi 7 banding 4. Inilah contoh dataset yang cukup seimbang; masalah serius biasanya mulai terasa ketika satu kelas mendominasi lebih dari 90 persen, situasi yang kita bedah pada chapter Training dan Evaluation.
Encoding Target Kategori #
Sebagian algoritma dan beberapa utilitas scikit-learn menghendaki label berupa angka, bukan teks. Class LabelEncoder menerjemahkan nilai kategori menjadi integer:
from sklearn.preprocessing import LabelEncoder
encoder = LabelEncoder()
df_bersih = df_bersih.copy()
df_bersih["kota_encoded"] = encoder.fit_transform(df_bersih["kota"])
print(df_bersih[["kota", "kota_encoded"]].drop_duplicates().to_string(index=False))
print(list(encoder.classes_))Output yang Dihasilkan:
kota kota_encoded
Bandung 0
Jakarta 1
Surabaya 2
['Bandung', 'Jakarta', 'Surabaya']Method fit_transform() mempelajari pemetaan Bandung menjadi 0, Jakarta menjadi 1, dan Surabaya menjadi 2, lalu langsung menerapkannya pada kolom. Atribut encoder.classes_ menyimpan urutan pemetaan tersebut sehingga angka selalu bisa diterjemahkan balik dengan encoder.inverse_transform(). Perlu dicatat: LabelEncoder memang dirancang untuk kolom target. Untuk kolom fitur kategori, encoding yang tepat adalah one-hot encoding yang kita bahas pada chapter Feature Engineering, karena angka 0, 1, 2 pada fitur akan salah dibaca model sebagai urutan besaran.
Baseline Sebelum Model Pertama #
Sebelum melatih model apa pun, hitung dulu akurasi model paling naif yang mungkin: tebak kelas mayoritas terus-menerus. Angka inilah baseline yang harus dikalahkan:
kelas_mayoritas = y_train.value_counts().idxmax()
akurasi_baseline = (y_test == kelas_mayoritas).mean()
print(f"Baseline menebak '{kelas_mayoritas}' terus-menerus: akurasi {akurasi_baseline:.2%}")Output yang Dihasilkan:
Baseline menebak '1' terus-menerus: akurasi 50.00%Model naif ini menebak kelas 1 (berlangganan) untuk semua pelanggan dan benar pada setengah data uji. Artinya, model machine learning yang kita latih pada dataset ini harus mengungguli 50 persen agar layak dianggap belajar sesuatu. Ketika data tidak seimbang, baseline seperti ini bisa mencapai 95 persen dan membuat akurasi model terdengar hebat padahal tidak menambah nilai apa pun.