Bayangkan dua feature Toko Kopi Kita berdiri berdampingan: suhu siang bernilai 24-33, jumlah pengunjung bernilai 180-300. Bagi manusia tidak masalah, tetapi bagi model yang menghitung jarak atau gradien, kolom pengunjung terlihat “ribuan kali lebih penting” hanya karena angkanya lebih besar. Normalisasi, atau min-max scaling, menyeragamkan semua feature ke rentang [0, 1] sehingga keduanya berdiri setara di mata model. Pada chapter ini kita hitung rumusnya secara manual, bandingkan dengan MinMaxScaler dari scikit-learn, lalu uji kelemahannya yang paling terkenal: kepekaan terhadap pencilan.
Rumus Min-Max Scaling #
Normalisasi memetakan setiap nilai ke posisinya secara proporsional di dalam rentang kolomnya. Nilai terkecil menjadi 0, nilai terbesar menjadi 1, dan sisanya berdistribusi di antara keduanya:
x_baru = (x - min) / (max - min)Rumus sesederhana itu, dan kita bisa membuktikannya langsung dengan pandas sebelum memakai pustaka mana pun:
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
hari = pd.DataFrame({
"suhu": [27, 30, 24, 29, 33, 28, 26, 31],
"pengunjung": [210, 260, 180, 240, 300, 225, 195, 255],
})
manual = (hari - hari.min()) / (hari.max() - hari.min())
print("rumus manual (x - min) / (max - min):")
print(manual.round(3))
hasil = MinMaxScaler().fit_transform(hari)
print()
print("MinMaxScaler:")
print(pd.DataFrame(hasil, columns=hari.columns).round(3))
print()
print("min per kolom:", hasil.min(axis=0).round(3))
print("max per kolom:", hasil.max(axis=0).round(3))Output yang Dihasilkan:
rumus manual (x - min) / (max - min):
suhu pengunjung
0 0.333 0.250
1 0.667 0.667
2 0.000 0.000
3 0.556 0.500
4 1.000 1.000
5 0.444 0.375
6 0.222 0.125
7 0.778 0.625
MinMaxScaler:
suhu pengunjung
0 0.333 0.250
1 0.667 0.667
2 0.000 0.000
3 0.556 0.500
4 1.000 1.000
5 0.444 0.375
6 0.222 0.125
7 0.778 0.625
min per kolom: [0. 0.]
max per kolom: [1. 1.]Mari kita bedah baris per baris:
- Baris 4-7 (
hari = pd.DataFrame(...)): dua feature dengan satuan berbeda — derajat dan orang. Inilah situasi yang memicu perlunya penskalaan. - Baris 9 (
manual = (hari - hari.min()) / ...): pandas menjalankan rumus min-max pada kedua kolom sekaligus. Hari bersuhu 24 (terkecil) menjadi 0,000; hari bersuhu 33 (terbesar) menjadi 1,000; hari dengan 180 pengunjung menjadi 0,000 di kolomnya sendiri. - Baris 13 (
MinMaxScaler().fit_transform(hari)): langkahfitmempelajari min dan max tiap kolom dari data, lalutransformmenerapkan rumus yang sama. Hasilnya identik persis dengan perhitungan manual — satu konfirmasi bahwa tidak ada proses tersembunyi di balik pustaka. - Baris 18-19 (
hasil.min(axis=0),hasil.max(axis=0)): pemeriksaan kesehatan. Setiap kolom hasil kini berjalan dari 0 sampai 1, sehingga perbedaan satuan asli tidak lagi berpengaruh.
Kapan Normalisasi Dibutuhkan #
Tidak semua model memedulikan skala. Regresi linear dan pohon keputusan memproses tiap feature menurut koefisien atau ambangnya sendiri, sehingga penskalaan tidak mengubah hasilnya. Model lain sungguh memedulikan:
| Model | Alasan butuh skala setara | Normalisasi cocok? |
|---|---|---|
| Jaring saraf (MLP) | gradien bergerak lambat bila skala tak seragam | ya, masukan [0,1] lazim dipakai |
| K-Nearest Neighbors | jarak Euclidean didominasi kolom berskala besar | ya |
| K-Means clustering | centroid bergeser mengikuti kolom terbesar | ya |
| Regresi linear, pohon | tiap feature diproses terpisah | tidak wajib |
Normalisasi juga menjadi pilihan alami ketika skala memang bermakna tetap: piksel citra selalu berada di 0-255 sehingga membagi 255 (bentuk min-max dengan min tetap) membawanya ke [0,1] tanpa mengubah informasi apa pun.
Kepekaan terhadap Pencilan #
Kekuatan min-max scaling — memetakan rentang penuh ke [0,1] — sekaligus menjadi kelemahannya. Satu nilai ekstrem akan menetapkan batas rentang, dan seluruh nilai normal terhimpit ke sempit di dekat nol. Kita uji dengan menambahkan satu hari festival dengan 5.000 pengunjung:
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
hari = pd.DataFrame({"pengunjung": [210, 260, 180, 240, 300, 225, 195, 255]})
festival = pd.DataFrame({"pengunjung": [5000]})
hari_festival = pd.concat([hari, festival], ignore_index=True)
hasil = MinMaxScaler().fit_transform(hari_festival)
perbandingan = pd.DataFrame({
"pengunjung_asli": hari_festival["pengunjung"],
"ternormalisasi": hasil.ravel().round(4),
})
print(perbandingan.to_string(index=False))Output yang Dihasilkan:
pengunjung_asli ternormalisasi
210 0.0062
260 0.0166
180 0.0000
240 0.0124
300 0.0249
225 0.0093
195 0.0031
255 0.0156
5000 1.0000Mari kita baca hasilnya:
- Baris 4-5 (
festival): satu baris baru bernilai 5.000 — entah benar-benar ramai, entah salah catat. Dalam delapan hari normal, nilai tertinggi hanya 300. - Baris 7 (
pd.concat(...)): baris festival digabungkan sehingga min dan max kolom berubah drastis menjadi 180 dan 5.000. - Kolom
ternormalisasi: seluruh hari normal kini berdesit di 0,000-0,025 — nyaris tidak ada jarak di antara mereka. Informasi “hari ini ramai, kemarin sepi” yang tadinya jelas kini nyaris rata. Satu pencilan berhasil memencetkan delapan observasi bermakna ke ujung sempit garis.
Rangkuman #
- Normalisasi memetakan tiap kolom ke [0, 1] lewat rumus
(x - min) / (max - min);MinMaxScalermenghasilkan angka yang identik dengan hitungan manual. - Penskalaan dibutuhkan model berbasis jarak dan gradien — jaring saraf, KNN, K-Means — dan tidak wajib untuk regresi linear maupun pohon keputusan.
- Satu pencilan pada min atau max akan menghimpit seluruh nilai normal ke wilayah sempit; periksa pencilan atau beralih ke penskalaan yang tahan pencilan.
fitdilakukan pada data latih dantransformpada data baru — urutan yang akan kita tegaskan kembali pada chapter mencegah data leakage.
Min-max bukan satu-satunya cara menyeragamkan skala. Alternatifnya yang paling sering dipakai sebagai default justru tidak mengunci rentang [0,1], melainkan memusatkan data pada rata-rata nol — standardisasi, pembahasan chapter berikutnya.