Kolom numerik dalam satu tabel sering berskala jauh berbeda: nilai_transaksi diukur dalam ratusan ribu hingga jutaan rupiah, sementara berat_paket hanya beberapa kilogram. Perhitungan yang mengandalkan jarak atau magnitudo, misalnya model machine learning dan analisis kemiripan antar baris, akan didominasi kolom dengan angka terbesar. Dua teknik penyeimbangan yang paling umum adalah min-max normalization, yang memetakan data ke rentang 0 sampai 1, dan z-score standardization, yang membuat rata-rata menjadi 0 dan simpangan baku menjadi 1. Keduanya hanya membutuhkan aritmetika kolom pandas, tanpa library tambahan.

Normalisasi Min-Max ke Rentang 0-1 #

Rumus min-max normalization untuk setiap nilai x adalah x' = (x - min) / (max - min), dengan min dan max diambil per kolom. Skrip berikut menghitungnya untuk dua kolom sekaligus dengan method .sub() dan .div(), lalu menghitung z-score dengan pola yang sama. Jalankan dan amati kedua tabel hasil beserta statistik di bagian akhir.

python
import pandas as pd

pesanan = pd.DataFrame({
    "id_pesanan": ["PSN-001", "PSN-002", "PSN-003", "PSN-004",
                   "PSN-005", "PSN-006", "PSN-007", "PSN-008"],
    "nama_pelanggan": ["Budi", "Siti", "Dewi", "Andi",
                       "Rina", "Tono", "Lina", "Sari"],
    "kota": ["Jakarta", "Bandung", "Surabaya", "Jakarta",
             "Medan", "Bandung", "Jakarta", "Surabaya"],
    "pembayaran": ["QRIS", "Transfer", "QRIS", "Kartu Kredit",
                   "COD", "Transfer", "QRIS", "COD"],
    "nilai_transaksi": [250_000, 1_800_000, 750_000, 2_400_000,
                        480_000, 1_200_000, 320_000, 980_000],
    "berat_paket": [1.2, 4.5, 0.8, 7.0, 2.5, 3.0, 1.0, 5.5],
})

fitur = pesanan[["nilai_transaksi", "berat_paket"]]

rentang = fitur.max() - fitur.min()
skala_minmax = fitur.sub(fitur.min()).div(rentang)
print(skala_minmax.round(3))
print()

z = fitur.sub(fitur.mean()).div(fitur.std())
print(z.round(3))
print()

print("min :", fitur.min().tolist())
print("max :", fitur.max().tolist())
print("mean:", fitur.mean().tolist())
print("std :", fitur.std().round(2).tolist())
print("mean z-score terbesar:", round(z.mean().abs().max(), 6))
print("std z-score :", z.std().round(6).tolist())

Output yang Dihasilkan:

text
   nilai_transaksi  berat_paket
0            0.000        0.065
1            0.721        0.597
2            0.233        0.000
3            1.000        1.000
4            0.107        0.274
5            0.442        0.355
6            0.033        0.032
7            0.340        0.758

   nilai_transaksi  berat_paket
0           -1.023       -0.870
1            1.029        0.574
2           -0.361       -1.045
3            1.824        1.668
4           -0.718       -0.301
5            0.235       -0.082
6           -0.930       -0.957
7           -0.056        1.012

min : [250000.0, 0.8]
max : [2400000.0, 7.0]
mean: [1022500.0, 3.1875]
std : [755375.97, 2.29]
mean z-score terbesar: 0.0
std z-score : [1.0, 1.0]

Mari kita telaah apa yang terjadi pada kode di atas:

  1. Baris 17 (fitur = pesanan[["nilai_transaksi", "berat_paket"]]): kita menyekalakan dua kolom numerik sekaligus; setiap kolom diproses terpisah oleh pandas.
  2. Baris 19 (rentang = fitur.max() - fitur.min()): pengurangan dua Series menghasilkan Series berisi rentang tiap kolom: 2.150.000 untuk nilai_transaksi dan 6,2 untuk berat_paket.
  3. Baris 20 (fitur.sub(fitur.min()).div(rentang)): DataFrame.sub() mengurangi setiap kolom dengan minimumnya, lalu DataFrame.div() membagi tiap kolom dengan rentangnya. Pandas menyelaraskan berdasarkan nama kolom, sehingga kita tidak perlu loop manual.
  4. Hasil pertama: nilai minimum tiap kolom menjadi 0.000 dan maksimum menjadi 1.000. Baris PSN-004 bernilai 1.000 di kedua kolom karena memiliki transaksi terbesar sekaligus paket terberat.
  5. Baris 24 (z = fitur.sub(fitur.mean()).div(fitur.std())): rumus z-score z = (x - mean) / std diterapkan dengan pola .sub() dan .div() yang sama. Hasilnya kolom dengan rata-rata mendekati 0 dan simpangan baku tepat 1,0, tercetak di baris 32-33.
  6. Baris 28-31: cetakan min, max, mean, dan std per kolom menampilkan parameter transformasi. Angka-angka inilah yang nantinya harus disimpan bila transformasi diterapkan ke data baru.

Memilih Teknik dan Menjaga Konsistensi #

AspekMin-MaxZ-Score
Rentang hasil0 sampai 1Tanpa batas tetap (rata-rata 0, simpangan baku 1)
Pengaruh outlierBesar, karena min/max ikut bergeserLebih kecil, karena mean/std lebih stabil
Data baru di luar data latihHasil bisa di luar 0-1z tetap terdefinisi
Pemakaian umumNeural network, data citraRegresi, PCA, clustering

Pilih min-max bila alur kerja membutuhkan rentang pasti dan data tidak memiliki nilai ekstrem. Pilih z-score bila sebaran data mendekati normal atau model sensitif terhadap skala relatif antar kolom. Detail statistiknya, termasuk definisi simpangan baku, dapat dibaca di dokumentasi NumPy yang menjadi dasar perhitungan pandas. Hal yang lebih penting dari pilihan teknik adalah konsistensi penerapannya pada data baru.

Dengan kolom kategori yang sudah di-encode dan kolom numerik yang sudah disekalakan, dataset pesanan kini siap untuk analisis lanjutan. Langkah berikutnya bukan lagi mengubah isi kolom, melainkan merangkum tabel per kelompok: berapa rata-rata transaksi per kota atau total pembelian per metode pembayaran. Section berikutnya, Groupby dan Agregasi, membahas pola kerja persis seperti itu.