Feature Engineering: Resep Membuat Kolom yang Bikin Model Berguna
Blog/Tips & Trik/Feature Engineering: Resep Membuat Kolom yang Bikin Model Berguna

Feature Engineering: Resep Membuat Kolom yang Bikin Model Berguna

BimaBima
·4 Oktober 2025·12 menit baca

Penulis

Bima

Bima

Founder & Data Professional

Bagikan

TL;DR

Feature engineering adalah proses bikin kolom baru dari data mentah supaya model punya sinyal yang lebih jelas buat belajar. Lima resep yang paling sering ngasih hasil: fitur dari kolom tanggal, rasio antar angka, agregat per pelanggan, encoding kolom kategori, dan binning angka jadi kelompok. Semua langkahnya harus dihitung dari data latih doang biar nggak bocor.

Feature engineering adalah proses bikin kolom baru dari data mentah supaya model punya sinyal yang lebih jelas buat dipelajari.

Di dataset latihan ngulikdata, ganti algoritma dari regresi logistik ke random forest naikin skor F1 dari 0,612 ke 0,647. Nambah 13 kolom turunan naikin skornya ke 0,741, pakai algoritma yang sama persis kayak awal.

Selisihnya jelas. Dan kolom turunan itu bikinnya nggak butuh teori berat, cuma butuh tahu apa yang penting di bisnisnya.

Apa itu feature engineering?

Feature engineering adalah kegiatan mengubah, menggabungkan, atau menurunkan kolom baru dari data mentah supaya pola yang relevan jadi lebih gampang ditangkap model. Contohnya ngubah kolom tanggal jadi jumlah hari sejak transaksi terakhir, atau ngubah dua kolom angka jadi satu kolom rasio.

Datanya nggak nambah. Yang nambah cuma cara nyajiin informasi yang udah ada.

Model nggak punya pengetahuan bisnis. Dia nggak tahu bahwa pelanggan yang belanja tiap 7 hari lalu tiba-tiba absen 40 hari itu tanda bahaya, kecuali kamu bikinin kolomnya.

Kenapa kolom turunan sering lebih ngefek daripada ganti algoritma?

Karena algoritma cuma bisa belajar dari informasi yang tersedia di kolom. Kalau sinyalnya kesimpan dalam bentuk selisih atau rasio yang belum dihitung, model harus nemuin sendiri lewat kombinasi aturan yang rumit. Bikinin kolomnya langsung, dan pekerjaan model jadi jauh lebih ringan.

Ini kelihatan jelas di model linear. Regresi logistik nggak bisa bikin pembagian antar kolom sendiri, jadi rasio harus kamu siapkan.

Di model berbasis pohon, efeknya lebih halus tapi tetap nyata. Pohon bisa niru rasio pakai banyak potongan aturan, tapi butuh jauh lebih banyak data buat nyampe hasil yang sama.

Resep 1: gimana bikin fitur dari kolom tanggal?

Kolom tanggal mentah hampir nggak berguna buat model. Pecah jadi komponen yang punya arti bisnis: hari dalam minggu, tanggal dalam bulan, jam, dan yang paling sering ngefek, selisih hari antara dua kejadian.

import pandas as pd

df["tanggal"] = pd.to_datetime(df["tanggal"])
tanggal_acuan = pd.Timestamp("2025-09-30")

df["hari_dalam_minggu"] = df["tanggal"].dt.dayofweek
df["tanggal_dalam_bulan"] = df["tanggal"].dt.day
df["jam_pesan"] = df["tanggal"].dt.hour
df["akhir_pekan"] = (df["tanggal"].dt.dayofweek >= 5).astype(int)
df["hari_sejak_beli"] = (tanggal_acuan - df["tanggal"]).dt.days

Buat konteks Indonesia, dua kolom tambahan sering ngasih lompatan besar. Pertama, penanda tanggal kembar seperti 9.9, 10.10, dan 11.11 karena kampanye marketplace ngumpul di situ. Kedua, penanda periode gajian yaitu tanggal 25 sampai akhir bulan.

df["tanggal_kembar"] = (
    df["tanggal"].dt.day == df["tanggal"].dt.month
).astype(int)

df["periode_gajian"] = df["tanggal"].dt.day.between(25, 31).astype(int)

Kolom tanggal_kembar ini contoh fitur yang lahir dari pengetahuan pasar lokal. Nggak ada di tutorial mana pun, dan di data e-commerce Indonesia dampaknya kelihatan.

Detail cara ngolah tanggal di pandas ada di artikel accessor dt di pandas.

Resep 2: kapan rasio lebih berguna dari angka mentah?

Rasio lebih berguna waktu ukuran mutlak nggak sebanding antar baris. Belanja Rp 500.000 dari pelanggan yang biasa belanja Rp 2 juta itu penurunan, sementara angka yang sama dari pelanggan baru itu lonjakan. Rasio yang bikin dua kasus itu kebaca beda.

df["rasio_diskon"] = df["nilai_diskon"] / df["nilai_kotor"]
df["belanja_per_pesanan"] = df["total_belanja"] / df["jumlah_pesanan"]
df["rasio_batal"] = df["pesanan_batal"] / df["jumlah_pesanan"]
df["ongkir_per_belanja"] = df["total_ongkir"] / df["total_belanja"]

Satu hal yang wajib: lindungi dari pembagian nol.

import numpy as np

df["belanja_per_pesanan"] = np.where(
    df["jumlah_pesanan"] > 0,
    df["total_belanja"] / df["jumlah_pesanan"],
    0
)

Rasio juga bikin nilai ekstrem lebih jinak. Pelanggan grosir yang belanja Rp 40 juta bakal jadi outlier di kolom total belanja, tapi rasio diskonnya bisa jadi normal aja.

Resep 3: gimana bikin fitur agregat per pelanggan?

Kelompokkan data transaksi per pelanggan, hitung ringkasannya, lalu tempelkan balik ke tiap baris. Fitur agregat ngasih konteks perilaku yang nggak kelihatan dari satu baris transaksi.

Tiga angka yang paling sering kepakai di ritel: kapan terakhir belanja, seberapa sering belanja, dan berapa nilainya.

agg = (
    trx.groupby("customer_id")
       .agg(
           jumlah_pesanan=("order_id", "nunique"),
           total_belanja=("nilai_bersih", "sum"),
           rata_belanja=("nilai_bersih", "mean"),
           std_belanja=("nilai_bersih", "std"),
           pesanan_pertama=("tanggal", "min"),
           pesanan_terakhir=("tanggal", "max"),
           jumlah_kategori=("kategori", "nunique"),
       )
       .reset_index()
)

agg["umur_pelanggan_hari"] = (
    agg["pesanan_terakhir"] - agg["pesanan_pertama"]
).dt.days

agg["jeda_rata_hari"] = (
    agg["umur_pelanggan_hari"] / agg["jumlah_pesanan"].clip(lower=1)
)

Kolom jeda_rata_hari itu salah satu fitur paling kuat di prediksi pelanggan berhenti belanja. Dia nangkap ritme belanja tiap orang, bukan cuma jumlahnya.

Fitur turunan berikutnya bandingin jeda terakhir sama jeda biasanya.

agg["hari_sejak_terakhir"] = (
    tanggal_acuan - agg["pesanan_terakhir"]
).dt.days

agg["rasio_jeda"] = (
    agg["hari_sejak_terakhir"] / agg["jeda_rata_hari"].clip(lower=1)
)

Nilai rasio_jeda di atas 3 artinya pelanggan itu udah absen tiga kali lebih lama dari kebiasaannya. Kolom ini yang paling banyak nyumbang di contoh kasus di bawah.

Kalau kamu mau nempelin hasil agregat ke tiap baris tanpa merge, pakai pola di artikel groupby transform.

Resep 4: gimana nangani kolom kategori?

Pilih metodenya berdasarkan jumlah nilai unik. Di bawah 15 nilai, pakai one hot encoding yang bikin satu kolom nol dan satu per kategori. Di atas itu, pertimbangkan frequency encoding atau target encoding supaya jumlah kolomnya nggak meledak.

Jumlah nilai unikMetodeCatatan
2Ubah jadi 0 dan 1Nggak perlu kolom tambahan
3 sampai 15One hot encodingPaling aman dan gampang dijelaskan
15 sampai 50Frequency encodingGanti kategori dengan jumlah kemunculannya
Di atas 50Target encodingHitung di dalam lipatan cross validation
Punya urutanOrdinal encodingContoh: kecil, sedang, besar
from sklearn.preprocessing import OneHotEncoder

enc = OneHotEncoder(handle_unknown="ignore", sparse_output=False)
kolom_kategori = ["kanal", "metode_bayar", "tipe_pelanggan"]

hasil = enc.fit_transform(X_train[kolom_kategori])

Parameter handle_unknown="ignore" penting banget. Tanpa itu, kode kamu bakal error di produksi begitu ketemu metode bayar baru yang belum ada waktu latihan.

Buat frequency encoding, satu baris cukup.

peta_frekuensi = X_train["kode_pos"].value_counts(normalize=True)
X_train["kode_pos_freq"] = X_train["kode_pos"].map(peta_frekuensi)
X_test["kode_pos_freq"] = X_test["kode_pos"].map(peta_frekuensi).fillna(0)

Perhatikan barisnya. Peta frekuensi dihitung dari data latih, lalu dipakai ke data uji. Kalau kamu hitung dari seluruh data, itu kebocoran.

Cara lain pakai pandas ada di artikel get_dummies.

Resep 5: kapan angka perlu dijadiin kelompok?

Kelompokkan angka jadi rentang waktu hubungannya sama target nggak lurus. Contohnya umur pelanggan, di mana kelompok 25-34 tahun bisa berperilaku beda jauh dari kelompok 18-24 dan 35-44 tanpa pola naik turun yang teratur.

df["kelompok_umur"] = pd.cut(
    df["umur"],
    bins=[0, 24, 34, 44, 54, 100],
    labels=["18-24", "25-34", "35-44", "45-54", "55+"]
)

df["tingkat_belanja"] = pd.qcut(
    df["total_belanja"], q=5,
    labels=["sangat rendah", "rendah", "sedang", "tinggi", "sangat tinggi"]
)

Fungsi cut pakai batas yang kamu tentukan. Fungsi qcut bagi rata berdasarkan jumlah baris, jadi tiap kelompok isinya sama banyak. Bedanya aku jelasin di artikel cut dan qcut.

Hati-hati satu hal: batas qcut harus dihitung dari data latih dan dipakai ulang ke data uji. Kalau dihitung ulang di data uji, kamu bocorin distribusi.

Hasil pengelompokan ini juga sering langsung kepakai buat segmentation di sisi marketing.

Gimana cara tahu fitur baru kamu beneran ngebantu?

Latih model dua kali dengan pembagian data yang sama, sekali tanpa fitur baru dan sekali dengan fitur baru, lalu bandingin skornya pakai cross validation. Kalau kenaikannya lebih kecil dari simpangan baku antar lipatan, fitur itu belum terbukti ngebantu.

from sklearn.model_selection import cross_val_score

skor_lama = cross_val_score(pipe, X_dasar, y, cv=5, scoring="f1")
skor_baru = cross_val_score(pipe, X_lengkap, y, cv=5, scoring="f1")

print(f"tanpa fitur baru: {skor_lama.mean():.3f} +/- {skor_lama.std():.3f}")
print(f"dengan fitur baru: {skor_baru.mean():.3f} +/- {skor_baru.std():.3f}")

Buat lihat kontribusi tiap kolom, pakai permutation importance yang ngukur seberapa turun skor kalau satu kolom diacak.

from sklearn.inspection import permutation_importance

hasil = permutation_importance(
    model, X_test, y_test, n_repeats=10, random_state=42
)

urutan = hasil.importances_mean.argsort()[::-1]
for i in urutan[:10]:
    print(f"{X_test.columns[i]:25s} {hasil.importances_mean[i]:.4f}")

Daftar teknik transformasi lain yang tersedia ada di dokumentasi preprocessing scikit-learn.

Contoh kasus: toko_berkah, dari 11 kolom jadi 24

Dataset latihan ngulikdata punya 4.180 pelanggan toko_berkah dengan 11 kolom mentah. Targetnya prediksi pelanggan berhenti belanja dalam 90 hari.

Aku uji tiga skenario pakai cross validation 5 lipatan dan metrik F1.

SkenarioJumlah kolomSkor F1Simpangan
Kolom mentah, regresi logistik110,6120,028
Kolom mentah, random forest110,6470,031
Kolom turunan, regresi logistik240,7410,024

Ganti algoritma naikin 0,035 poin. Nambah 13 kolom turunan naikin 0,129 poin, hampir empat kali lipatnya.

Tiga kolom yang paling banyak nyumbang menurut permutation importance:

  1. rasio_jeda, yaitu jeda belanja terakhir dibagi jeda rata-rata pelanggan itu.
  2. jumlah_kategori, yaitu berapa kategori produk berbeda yang pernah dia beli.
  3. rasio_diskon, yaitu porsi diskon dari nilai belanja kotor.

Kolom kedua ngasih temuan bisnis yang langsung kepakai. Pelanggan yang pernah beli dari 4 kategori berbeda punya tingkat berhenti belanja 8,3 persen, sementara yang cuma pernah beli 1 kategori mencapai 31,7 persen.

Selisih 23,4 poin itu jadi dasar program rekomendasi lintas kategori buat pembeli baru. Angka itu lahir dari satu kolom turunan yang bikinnya cuma satu baris kode.

Kesalahan umum di feature engineering

  1. Ngitung statistik dari seluruh dataset. Rata-rata, batas bin, dan peta frekuensi harus dihitung dari data latih doang.
  2. Bikin fitur dari kolom yang belum ada saat prediksi. Kolom tanggal pembatalan nggak boleh dipakai buat nebak pesanan bakal batal.
  3. Nambah kolom tanpa alasan bisnis. Kalau kamu nggak bisa jelasin kenapa kolom itu masuk akal, kemungkinan besar dia cuma nambah risiko overfitting.
  4. Lupa handle_unknown di encoder. Kategori baru di produksi bikin pipeline mati.
  5. Nyimpen ratusan kolom hasil one hot dari kode pos. Ganti ke frequency encoding sebelum tabelnya melebar.
  6. Nggak nyimpen kode pembuatan fiturnya. Fitur yang nggak bisa dihitung ulang di produksi sama aja nggak ada.

Poin nomor 1 dan 2 penyebab paling sering skor lompat mendadak. Selalu split dulu, baru bikin fitur.

Ringkasan dan langkah berikutnya

Lima resep yang paling sering ngasih hasil: pecah kolom tanggal, bikin rasio, hitung agregat per pelanggan, encode kategori sesuai jumlah nilai uniknya, dan kelompokkan angka yang hubungannya nggak lurus.

Urutan kerjanya selalu sama. Split dulu, bikin fitur dari data latih, ukur kontribusinya pakai cross validation, buang yang nggak terbukti ngebantu.

Kalau skormu masih goyang setelah nambah fitur, cek dulu cara evaluasinya lewat cross validation. Dan buat ngitung agregat awal dari data yang masih di spreadsheet, SUMIFS bisa jadi titik mulai sebelum pindah ke Python.

Coba Langsung

Mau praktek langsung? Mulai latihan SQL gratis

Latihan interaktif, langsung di browser.

Buka NgulikSQL →
Bagikan:
Bima
Ditulis oleh

Bima

Founder & Data Professional

Founder Ngulik Data. Passionate about making data analysis accessible for everyone.

Artikel terkait

Pandas groupby: Agregasi Data ala Pivot di Python (2026)
Tips & Trik
20 Juli 2026•9 menit baca

Pandas groupby: Agregasi Data ala Pivot di Python (2026)

groupby ngelompokin baris berdasarkan kolom, lalu ngitung ringkasan per grup kayak total atau rata-rata. Ini pivot-nya pandas.

BimaBima
Pandas to_excel: Ekspor DataFrame ke Excel (2026)
Tips & Trik
18 Juli 2026•8 menit baca

Pandas to_excel: Ekspor DataFrame ke Excel (2026)

to_excel nyimpen DataFrame pandas jadi file Excel .xlsx. Ini cara pakainya, dari satu sheet sampai banyak sheet, plus setelan yang bikin hasilnya rapi.

BimaBima
Pandas read_excel: Baca File Excel di Python
Tips & Trik
16 Juli 2026•8 menit baca

Pandas read_excel: Baca File Excel di Python

pandas read_excel baca file Excel jadi DataFrame, bisa pilih sheet tertentu dan lompatin baris judul yang berantakan. Ini cara pakai plus parameter penting dengan contoh data toko.

BimaBima
Kembali ke Blog
Ngulik Data logoNgulik Data

Platform edukasi data lengkap untuk professionals Indonesia. Belajar SQL, Data Analysis, dan lebih banyak lagi dengan praktek langsung dan feedback real-time.

© 2026 Ngulik Data. Semua hak dilindungi.

TAUTAN
BantuanHargaDatasetBlogAfiliasi
LEGAL
Syarat & KetentuanKebijakan Privasi
Ngulik Data
DatasetLeaderboardBlogStore