Chapter sebelumnya menegaskan bahwa kualitas fitur menentukan plafon kinerja model. Sekarang kita memegang peralatannya: teknik membangun kolom baru dari kolom yang sudah ada pada data tabular. Bahan dan alatnya sederhana — aritmetika dasar, aksesori tanggal pandas, dan pemotongan rentang — tetapi dampaknya kerap besar. Sepanjang chapter ini kita memakai satu kisah yang sama: data listing rumah dari agen properti dengan kolom tanggal_listing, harga_juta, luas_m2, dan usia_bangunan, persis seperti kebutuhan proyek prediksi harga rumah di bagian akhir Course.
Rasio, Selisih, dan Interaksi #
Rasio dipakai ketika skala absolut dua kolom menyesatkan. Rumah seharga Rp2,27 miliar terdengar mahal; tetapi bila luasnya hanya 51 m² di lokasi premium, harga per meternya 44,47 juta — cerita yang jauh lebih informatif bagi model maupun manusia. Pada kasus kampanye pemasaran, padanannya adalah profit margin: (pendapatan - biaya) / pendapatan, yang menormalkan perbedaan ukuran antar kampanye.
Selisih bermakna ketika yang relevan adalah jarak antara dua titik, bukan titiknya. Dua kolom tahun_daftar dan tahun_bangun hampir tak berguna bagi model secara terpisah; selisihnya — usia bangunan saat listing — adalah kuantitas yang benar-benar memuat sinyal harga.
Interaksi berbentuk perkalian dua fitur, dan dipakai ketika efek gabungannya berbeda dari penjumlahan efek terpisah. Luas besar menaikkan harga lebih tajam ketika lokasinya dekat pusat kota, sehingga luas_m2 * skor_lokasi menangkap efek gabungan yang sulit dilihat model linier dari dua kolom aslinya. Untuk kampanye pemasaran, jumlah_tayangan * rasio_klik adalah padanan yang lazim.
df["harga_per_m2"] = df["harga_juta"] / df["luas_m2"]
df["usia_bangunan"] = df["tahun_daftar"] - df["tahun_bangun"]
df["nilai_lokasi_luas"] = df["luas_m2"] * df["skor_lokasi"]Fitur pangkat (x², x³) menangkap hubungan melengkung dan sudah kita temui pada Chapter Regresi Polynomial lewat estimator PolynomialFeatures. Tabel berikut merangkum kapan tiap teknik paling tepat dipakai:
| Teknik | Bentuk | Paling cocok ketika |
|---|---|---|
| Rasio | a / b | Skala absolut menyesatkan; perbandingan yang bermakna |
| Selisih | a - b | Jarak antar nilai lebih informatif daripada nilai mentahnya |
| Interaksi | a * b | Efek satu fitur bergantung pada nilai fitur lainnya |
| Pangkat | a², a³ | Hubungan melengkung antara fitur dan target |
| Agregat | mean, count per entitas | Perilaku teramplas dalam suatu jendela waktu |
Fitur Turunan Tanggal dan Waktu #
Kolom bertipe datetime menyimpan satu momen waktu, sedangkan model membutuhkan angka yang bisa dibandingkan antar baris. Aksesori .dt pada pandas mengeluarkan angka-angka tersebut: .dt.month untuk bulan, .dt.dayofweek untuk hari dalam minggu (0 = Senin sampai 6 = Minggu), dan penanda turunan seperti is_weekend untuk hari ke-5 dan ke-6. Untuk data yang menyertakan jam kejadian, pengelompokan jam menjadi kelompok — pagi, siang, sore, malam — sering lebih stabil daripada jam mentahnya, karena kelompok menampung pola perilaku yang menyebar antar jam yang berdekatan.
Pola kalender seperti ini nyata pada banyak masalah: kunjungan situs berbeda antara hari kerja dan akhir pekan, dan transaksi pada dini hari punya profil risiko berbeda — tema yang dipakai berulang di Section Klasifikasi. Satu catatan teknis untuk contoh di chapter ini: tanggal acuan memakai pd.Timestamp("2026-01-15") yang tetap, bukan tanggal hari ini, sehingga output contoh selalu sama kapan pun dibaca; di sistem produksi, tanggal datang dari data dan bukan dari jam mesin.
Agregat Perilaku dan Fitur Teks Sederhana #
Dua keluarga konstruksi lain sering muncul pada data transaksi. Pertama, agregat per entitas: jumlah transaksi 30 hari terakhir per pelanggan, rata-rata nilai keranjang, atau jumlah kunjungan mingguan — pola groupby-transform yang dilatih pada Chapter *Pandas untuk Machine Learning`. Jendela waktunya wajib berakhir sebelum momen prediksi; jendela yang menjorok ke masa depan adalah kebocoran data dalam bentuk yang paling sering lolos dari review. Kedua, fitur teks sederhana: panjang karakter, jumlah kata, atau rasio angka pada kolom bebas seperti alamat dan nama produk. Vektorisasi teks utuh (bag-of-words, tf-idf) berada di luar lingkup section ini dan cukup kita sebut sebagai kelanjutannya.
Binning: Memotong Angka Menjadi Kategori #
Binning mengubah kolom numerik menjadi beberapa kelompok dengan pd.cut: usia bangunan 0–5 tahun menjadi baru, 6–15 menjadi menengah, dan 16 ke atas menjadi lama. Teknik ini tepat ketika hubungan fitur-target tidak linier dan tim pengguna model butuh bahasa yang bisa dibaca — “listing rumah baru” lebih mudah dibicarakan daripada koefisien usia mentah. Risikonya dua: informasi hilang karena usia 16 dan 40 tahun kini tidak terbedakan, dan batas bin sewenang-wenang karena usia 15,9 dan 16,1 tahun terbelah ke kategori berbeda. Praktik yang aman adalah mempertahankan kolom numerik asli berdampingan dengan kategorinya, lalu membiarkan seleksi fitur yang menentukan mana yang dipakai model.
Contoh Lengkap: Listing Rumah #
Skrip berikut membangun 12 listing sintetis dengan rng berseed, mencetak kondisi awal, lalu menurunkan lima fitur baru dari kolom mentahnya:
# Konstruksi fitur baru dari kolom mentah tabel listing rumah.
# Demonstrasi: rasio, fitur turunan tanggal, dan binning usia bangunan.
import numpy as np
import pandas as pd
rng = np.random.default_rng(42)
# 12 listing rumah: kolom sebagaimana tersimpan di database agen properti.
# Tanggal acuan tetap (bukan tanggal hari ini) agar contoh deterministik.
tanggal_listing = pd.to_datetime("2026-01-15") + pd.to_timedelta(
rng.integers(0, 60, size=12), unit="D"
)
rumah = pd.DataFrame(
{
"tanggal_listing": tanggal_listing,
"harga_juta": rng.integers(600, 2400, size=12).astype(float),
"luas_m2": rng.integers(45, 140, size=12).astype(float),
"usia_bangunan": rng.integers(0, 46, size=12),
}
)
print("SEBELUM: kolom mentah dari database")
print(rumah.to_string(index=False))
# Rasio: harga per meter persegi (menormalkan perbedaan luas antar listing).
rumah["harga_per_m2_juta"] = (rumah["harga_juta"] / rumah["luas_m2"]).round(2)
# Fitur turunan tanggal: bulan, hari dalam minggu (0 = Senin), akhir pekan.
rumah["bulan"] = rumah["tanggal_listing"].dt.month
rumah["hari_dalam_minggu"] = rumah["tanggal_listing"].dt.dayofweek
rumah["is_weekend"] = rumah["hari_dalam_minggu"] >= 5
# Binning: kelompokkan usia bangunan menjadi kategori yang mudah dibaca.
rumah["kategori_usia"] = pd.cut(
rumah["usia_bangunan"],
bins=[-1, 5, 15, 60],
labels=["baru", "menengah", "lama"],
)
kolom_turunan = [
"tanggal_listing",
"harga_per_m2_juta",
"bulan",
"hari_dalam_minggu",
"is_weekend",
"kategori_usia",
]
print("\nSESUDAH: fitur turunan siap dipakai model")
print(rumah[kolom_turunan].to_string(index=False))Output yang Dihasilkan:
SEBELUM: kolom mentah dari database
tanggal_listing harga_juta luas_m2 usia_bangunan
2026-01-20 1924.0 119.0 39
2026-03-02 1970.0 106.0 38
2026-02-23 1891.0 83.0 12
2026-02-10 2014.0 123.0 29
2026-02-09 1523.0 96.0 7
2026-03-07 830.0 87.0 34
2026-01-20 2111.0 87.0 32
2026-02-25 1410.0 66.0 16
2026-01-27 1500.0 53.0 3
2026-01-20 1267.0 97.0 44
2026-02-15 928.0 129.0 20
2026-03-14 2268.0 51.0 41
SESUDAH: fitur turunan siap dipakai model
tanggal_listing harga_per_m2_juta bulan hari_dalam_minggu is_weekend kategori_usia
2026-01-20 16.17 1 1 False lama
2026-03-02 18.58 3 0 False lama
2026-02-23 22.78 2 0 False menengah
2026-02-10 16.37 2 1 False lama
2026-02-09 15.86 2 0 False menengah
2026-03-07 9.54 3 5 True lama
2026-01-20 24.26 1 1 False lama
2026-02-25 21.36 2 2 False lama
2026-01-27 28.30 1 1 False baru
2026-01-20 13.06 1 1 False lama
2026-02-15 7.19 2 6 True lama
2026-03-14 44.47 3 5 True lamaMari kita telaah baris-baris kunci skrip di atas:
- Baris 7 (
rng = np.random.default_rng(42)): generator angka acak berseed memastikan 12 listing yang sama tercipta pada setiap eksekusi — prasyarat contoh yang deterministik. - Baris 9–13 (
tanggal_listing = ...): tanggal acuan tetap 15 Januari 2026 digeser 0–59 hari secara acak; tanpapd.Timestampyang tetap, output akan berubah mengikuti tanggal eksekusi. - Baris 14–21 (
rumah = pd.DataFrame(...)): empat kolom mentah dibangun dari angka rng — persis bentuk data yang biasa diterima dari database agen properti. - Baris 26–27 (
rumah["harga_per_m2_juta"] = ...): rasio harga terhadap luas, dibulatkan dua desimal agar tabel mudah dibaca. - Baris 29–32 (
rumah["bulan"] = ...): tiga fitur tanggal — bulan, hari dalam minggu, dan penanda akhir pekan — ditarik dari satu kolom datetime yang sama. - Baris 34–39 (
rumah["kategori_usia"] = pd.cut(...)): binning usia bangunan menjadi tiga kategori; tepi bawah-1dipilih agar usia 0 tahun masuk ke kelompokbaru. - Baris 41–50 (
kolom_turunan = ...): DataFrame bagian SEBELUM dan SESUDAH dicetak berdampingan sehingga asal tiap fitur baru bisa dilacak ke kolom mentahnya.
Bacaan pada output memperlihatkan inti konstruksi fitur. Listing 14 Maret 2026 tercatat dengan harga total tertinggi (Rp2.268 juta), tetapi justru listing 7 Maret yang paling murah per meter persegi (9,54 juta/m²) karena luasnya 87 m² — informasi yang hanya muncul setelah rasio dibentuk. Tiga baris bertanda is_weekend=True semuanya jatuh pada hari_dalam_minggu 5 dan 6, konsisten dengan Sabtu dan Minggu. Kolom kategori_usia membagi 12 listing menjadi 1 baru, 2 menengah, dan 9 lama — bentuk yang langsung bisa dibaca tim pemasaran.
Dengan fitur baru berjajar rapi, pertanyaan berikutnya muncul dengan sendirinya: tidak semua kolom hasil konstruksi membantu, dan sebagian justru saling tumpang tindih informasinya. Chapter Feature Selection dengan Metode Filter mulai memangkasnya dengan kriteria statistik yang murah dan tidak bergantung model.