BAB I PENDAHULUAN

1.1 Latar Belakang

Perkembangan machine learning mendorong penggunaan data yang semakin besar, beragam, dan kompleks untuk mendukung prediksi serta pengambilan keputusan. Sejalan dengan perkembangan tersebut, feature engineering tidak lagi dipandang hanya sebagai tahap awal pembersihan data, tetapi sebagai bagian strategis dari pipeline machine learning yang mencakup transformasi, konstruksi, seleksi, dan reduksi fitur. Tinjauan terbaru menunjukkan adanya pergeseran dari feature engineering manual menuju pendekatan otomatis dan adaptif berbasis AutoML. Pendekatan tersebut dikembangkan untuk mengurangi ketergantungan pada keahlian domain, mempercepat eksperimen, dan mengolah data heterogen dalam skala besar. Namun, otomatisasi belum sepenuhnya menyelesaikan persoalan kualitas fitur karena aspek skalabilitas, interpretabilitas, fairness, reproduktibilitas, dan perubahan distribusi data masih menjadi tantangan penting (Koukaras & Tjortjis, 2025; Mumuni & Mumuni, 2025).

Permasalahan tersebut muncul karena fitur mentah sering kali mengandung informasi yang redundan, tidak relevan, berskala berbeda, tidak seimbang, atau belum merepresentasikan pola yang dibutuhkan oleh algoritma. Akibatnya, model dapat mengalami peningkatan kompleksitas, waktu komputasi yang lebih besar, overfitting, dan penurunan kemampuan generalisasi. Sejumlah penelitian memperlihatkan bahwa rekayasa fitur dapat memberikan peningkatan kinerja yang substansial. Sebagai contoh, Zhang & Wang (2023) menggabungkan seleksi fitur mRMR, SMOTE, dan optimasi hyperparameter pada deteksi intrusi jaringan; pada klasifikasi biner berbasis dataset NSL-KDD, pendekatan tersebut mencapai akurasi 99,2623% dan F1-score 99,4280%. Meskipun demikian, kinerja tinggi tidak selalu menunjukkan bahwa model benar-benar mempelajari pola yang dapat digunakan pada kondisi nyata. Starcke et al. (2025) menunjukkan bahwa ketika fitur yang secara langsung mengindikasikan diagnosis dimasukkan, kinerja model dapat terlihat sangat tinggi akibat data leakage. Setelah fitur-fitur tersebut dikeluarkan untuk mensimulasikan deteksi dini, model mengalami masalah generalisasi dan gagal membedakan kasus positif serta kontrol secara andal. Dengan demikian, feature engineering yang tidak dirancang secara hati-hati dapat menghasilkan estimasi performa yang terlalu optimistis dan keputusan yang keliru pada tahap penerapan.

Penelitian terdahulu juga belum memberikan kesimpulan yang seragam mengenai metode feature engineering yang paling baik untuk semua algoritma dan karakteristik data. Noroozi et al. (2023), misalnya, membandingkan 16 metode seleksi fitur dari kategori filter, wrapper, dan evolutionary pada tujuh algoritma machine learning untuk prediksi penyakit jantung. Hasilnya menunjukkan bahwa metode berbasis filter dapat meningkatkan akurasi hingga 2,3 poin persentase pada kombinasi tertentu, tetapi seleksi fitur juga menurunkan kinerja pada beberapa algoritma lain. Temuan ini menunjukkan bahwa efektivitas feature engineering bersifat kontekstual dan dipengaruhi oleh interaksi antara karakteristik data, metode transformasi atau seleksi, algoritma prediksi, serta skema validasi. Di sisi lain, tinjauan terbaru menekankan perlunya pipeline yang lebih reproducible, leakage-safe, interpretable, dan adaptif terhadap data drift (Koukaras & Tjortjis, 2025). Oleh karena itu, masih terdapat research gap berupa kebutuhan untuk mengevaluasi feature engineering secara sistematis, bukan hanya berdasarkan satu metrik akurasi atau satu model, melainkan juga berdasarkan kemampuan generalisasi, stabilitas, efisiensi komputasi, dan keterjagaan validitas proses pembentukan fitur.

Feature engineering menjadi penting dilakukan karena kualitas fitur berpengaruh langsung terhadap kualitas informasi yang diterima model machine learning. Secara akademik, penelitian ini dapat memperkaya pemahaman mengenai hubungan antara teknik preprocessing, konstruksi fitur, seleksi fitur, karakteristik data, dan performa berbagai algoritma. Penelitian ini juga dapat memberikan bukti empiris mengenai kondisi ketika suatu teknik feature engineering membantu model dan kondisi ketika teknik tersebut justru meningkatkan risiko overfitting atau kebocoran data. Secara praktis, hasil penelitian dapat digunakan untuk merancang pipeline machine learning yang lebih akurat, efisien, transparan, dan dapat direproduksi. Dengan menerapkan pemisahan proses pembentukan fitur pada data training dan data pengujian, membandingkan beberapa metode secara konsisten, serta melaporkan metrik yang relevan seperti precision, recall, F1-score, AUC, waktu komputasi, dan stabilitas validasi, penelitian ini diharapkan dapat menjembatani kebutuhan antara pengembangan metodologi feature engineering dan penerapannya pada permasalahan nyata.

1.2 Rumusan Masalah

Berdasarkan latar belakang di atas dapat disimpulkan bahwa rumusan masalah sebagai berikut:

  1. Bagaimana mahasiswa mampu memahami konsep dari berbagai jenis feature engineering pada RStudio?
  2. Bagaimana mahasiswa mampu melakukan teknik feature engineering di program RStudio?

1.3 Tujuan Penelitian

Berdasarkan rumusan masalah di atas, tujuan penelitian yang dapat disimpulkan sebagai berikut:

  1. Mahasiswa dapat memahami konsep dari berbagai jenis feature engineering pada RStudio.
  2. Mahasiswa dapat melakukan teknik feature engineering di program RStudio.

1.4 Manfaat Penelitian

Adapun manfaat yang didapatkan dari penelitian ini adalah sebagai berikut:

  1. Bagi penulis
    • Memberikan informasi dan pengetahuan mengenai konsep dari berbagai jenis feature engineering dan teknik feature engineering di program RStudio.
    • Menerapkan ilmu atau wawasan baru mengenai konsep dari berbagai jenis feature engineering dan teknik feature engineering di program RStudio.
  2. Bagi pembaca
    • Menambah ilmu pengetahuan mengenai konsep dari berbagai jenis feature engineering dan teknik feature engineering di program RStudio.
    • Dapat menjadi rujukan bagi penelitian selanjutnya.

1.5 Batasan Masalah

Adapun batasan masalah pada penelitian ini yaitu, gunakan dataset data curah hujan.xlsx untuk melakukan preprocessing data. NPM ganjil menggunakan mean imputation, shuffle splitting, dan Robust Scaler, sedangkan NPM genap menggunakan mode imputation, stratify splitting, dan Standard Scaler. Keduanya melakukan interpolasi pada Keadaan_Cuaca, capping pada data numerik, serta penanganan imbalance data menggunakan SMOTE. Tampilkan dan interpretasikan setiap output!

1.6 Sistematika Penulisan

Adapun sistematika penulisan dari praktikum ini adalah sebagai berikut:

BAB I PENDAHULUAN

Bab ini merupakan bab yang memuat latar belakang penelitian, rumusan masalah, tujuan dan manfaat penelitian, batasan masalah penelitian, dan sistematika penelitian.

BAB II TINJAUAN PUSTAKA

Bab ini merupakan bab yang memuat pengertian dari teori yang diperlukan untuk rancangan penelitian pada bab-bab berikutnya.

BAB III METODE PENELITIAN

Bab ini merupakan bab yang memuat uraian mengenai jenis dan sumber penelitian, variabel penelitian, dan analisis data.

BAB IV HASIL DAN PEMBAHASAN

Bab ini merupakan bab yang memuat hasil analisis, pembahasan dari hasil yang telah diperoleh, dan interpretasi.

BAB V KESIMPULAN DAN SARAN

Bab ini merupakan bab yang memuat rangkuman dari hasil keseluruhan dan saran yang diberikan oleh penulis terhadap hasil maupun analisis yang telah dilakukan.

DAFTAR PUSTAKA

BAB II TINJAUAN PUSTAKA

2.1 Machine Learning

Machine learning merupakan pendekatan komputasional yang memungkinkan sistem mempelajari pola dari data untuk menghasilkan prediksi atau keputusan. Dalam pendekatan ini, model tidak hanya diprogram menggunakan aturan yang bersifat eksplisit, tetapi dilatih menggunakan pasangan data dan target, struktur data tanpa target, atau umpan balik tertentu. Berdasarkan proses pembelajarannya, machine learning umumnya dibedakan menjadi supervised learning, unsupervised learning, dan reinforcement learning. Pada supervised learning, model mempelajari hubungan antara variabel prediktor dan variabel respons. Pada unsupervised learning, model berusaha menemukan struktur atau pola tanpa target yang telah ditentukan.

Kinerja model machine learning dipengaruhi oleh kualitas data, representasi variabel, algoritma, parameter model, serta strategi validasi. Oleh sebab itu, pemilihan algoritma saja tidak cukup untuk menjamin model yang baik. Data perlu diubah ke dalam bentuk yang informatif, konsisten, dan sesuai dengan asumsi atau mekanisme kerja algoritma. Tahap tersebut menjadi alasan mengapa feature engineering memiliki kedudukan penting dalam pengembangan model prediktif (Koukaras & Tjortjis, 2025; Mumuni & Mumuni, 2025).

2.2 Data Preprocessing

Data preprocessing adalah rangkaian proses untuk menyiapkan data sebelum digunakan dalam pelatihan model. Tahap ini dapat mencakup pemeriksaan kualitas data, penanganan nilai hilang, deteksi pencilan, penghapusan duplikasi, pengubahan tipe data, pengodean variabel kategorik, penskalaan, serta penanganan ketidakseimbangan kelas. Tujuan utamanya adalah menghasilkan data yang lebih konsisten dan representatif tanpa menghilangkan informasi penting.

Nilai hilang dapat ditangani melalui penghapusan observasi tertentu atau imputasi menggunakan statistik seperti rata-rata, median, modus, maupun model imputasi. Pemilihan metode harus mempertimbangkan mekanisme kehilangan data dan karakteristik variabel. Sementara itu, variabel kategorik dapat diubah menjadi bentuk numerik menggunakan one-hot encoding, ordinal encoding, atau teknik berbasis target. Teknik yang dipilih perlu disesuaikan dengan skala data, tipe model, dan risiko kebocoran informasi.

Penskalaan diperlukan terutama ketika algoritma menggunakan jarak, gradien, atau regularisasi. Standardisasi mengubah nilai menjadi skala dengan rata-rata mendekati nol dan simpangan baku satu, sedangkan normalisasi min-max memetakan nilai ke rentang tertentu. Pada data dengan pencilan kuat, robust scaling dapat digunakan karena memanfaatkan median dan rentang antarkuartil. Studi Mohtasham et al. (2024) menunjukkan bahwa pemilihan teknik penskalaan dan seleksi fitur perlu dipertimbangkan bersama karakteristik data karena dapat memengaruhi hasil klasifikasi.

2.3 Konsep Feature Engineering

Feature engineering adalah proses mengubah variabel mentah menjadi fitur yang lebih relevan, informatif, dan sesuai untuk digunakan oleh model machine learning. Proses ini dapat dilakukan melalui transformasi fitur yang sudah tersedia, pembentukan fitur baru, pemilihan sebagian fitur, atau pengubahan ruang fitur ke dimensi yang lebih rendah. Dengan demikian, feature engineering berfungsi sebagai penghubung antara data mentah dan representasi data yang dapat dipelajari oleh algoritma.

Fitur yang baik diharapkan memiliki hubungan yang relevan dengan variabel target, tidak mengandung informasi yang tidak tersedia pada saat prediksi, tidak terlalu redundan, dan tetap stabil ketika digunakan pada data baru. Dalam konteks ini, keberhasilan feature engineering tidak hanya diukur dari peningkatan akurasi. Efisiensi komputasi, interpretabilitas, ketahanan terhadap perubahan data, dan kemampuan generalisasi juga perlu diperhatikan (Koukaras & Tjortjis, 2025).

Secara umum, feature engineering dapat dibedakan menjadi pendekatan manual, otomatis, dan hibrida. Pendekatan manual memanfaatkan pengetahuan peneliti atau ahli domain untuk menentukan transformasi dan fitur baru. Pendekatan otomatis menggunakan teknik automated machine learning untuk mencari kombinasi transformasi, seleksi fitur, dan model. Pendekatan hibrida menggabungkan pengetahuan domain dengan pencarian otomatis. Pendekatan otomatis dapat mengurangi pekerjaan berulang, tetapi tetap perlu dikendalikan agar fitur yang dihasilkan dapat dijelaskan dan tidak melanggar batasan substantif (Mumuni & Mumuni, 2025).

BAB III METODE PENELITIAN

3.1 Jenis dan Sumber Data

Jenis data pada penelitian ini adalah data numerik. Data numerik adalah jenis data yang terdiri dari angka dan dapat diukur atau dihitung secara kuantitatif. Data ini digunakan untuk merepresentasikan nilai atau ukuran tertentu dalam berbagai konteks, seperti sains, ekonomi, statistik, dan matematika. Data numerik sering digunakan untuk melakukan perhitungan, analisis, dan visualisasi data. Dalam laporan ini memakai tipe data numerik kontinu.

Dalam laporan ini sumber data yang digunakan adalah sumber data dalam wujud data sekunder, yaitu data yang telah dikumpulkan dan disusun oleh pihak lain di luar praktikan itu sendiri. Data pada praktikum ini curah hujan yang diberikan oleh asisten praktikum.

3.2 Variabel Penelitian

Variabel adalah simbol, karakteristik, atau atribut yang dapat diukur atau diamati dalam sebuah penelitian atau eksperimen. Pada laporan ini terdapat 1 batasan masalah. Variabel penelitian yang digunakan terdiri atas hujan, suhu, kelembapan, keadaan cuaca, dan kecepatan angin. Variabel hujan, suhu, kelembapan, dan kecepatan angin merupakan variabel numerik, sedangkan keadaan cuaca merupakan variabel kategorik. Kelima variabel tersebut digunakan dalam proses preprocessing data untuk mempersiapkan data sebelum dilakukan analisis selanjutnya.

3.3 Analisis Data

Langkah-langkah yang digunakan pada penelitian untuk batasan masalah adalah sebagai berikut:

  1. Menghitung distribusi kelas pada variabel target y_train.
  2. Menggabungkan data prediktor hasil encoding dengan variabel target Hujan.
  3. Mengubah variabel target Hujan menjadi tipe factor agar dapat digunakan dalam proses SMOTE.
  4. Menentukan seed untuk menjaga hasil proses tetap konsisten.
  5. Membuat recipe SMOTE dengan variabel Hujan sebagai target.
  6. Menentukan over_ratio = 1 dan jumlah tetangga (neighbors) sebanyak 5.
  7. Melakukan prep() berdasarkan data training.
  8. Menerapkan SMOTE menggunakan bake() untuk menghasilkan data training yang lebih seimbang.
  9. Menghasilkan train_balanced sebagai dataset hasil penanganan imbalanced dataset.

BAB IV HASIL DAN PEMBAHASAN

4.1 Library

library(zoo) 
library(readxl)
library(tidyverse)
library(rsample)
library(e1071)
library(DescTools)
library(dplyr)
library(ggplot2)
library(gridExtra)
library(recipes)
library(themis)
library(caret)   
# Import Data
data <- read_excel("C:/Users/user/OneDrive/문서/data curah hujan.xlsx")
head(data)
## # A tibble: 6 × 5
##   Hujan  Suhu Kelembapan Keadaan_Cuaca Kecepatan_Angin
##   <dbl> <dbl>      <dbl>         <dbl>           <dbl>
## 1     1  23           95             5              NA
## 2     1  24           90             1              NA
## 3     1  26.8         77             1              NA
## 4     1  29.6         62             2               2
## 5     1  30.8         56             1               7
## 6     1  31           55             1               7
str(data)
## tibble [743 × 5] (S3: tbl_df/tbl/data.frame)
##  $ Hujan          : num [1:743] 1 1 1 1 1 1 1 2 2 2 ...
##  $ Suhu           : num [1:743] 23 24 26.8 29.6 30.8 31 30.4 30.9 30.2 29.7 ...
##  $ Kelembapan     : num [1:743] 95 90 77 62 56 55 57 58 62 62 ...
##  $ Keadaan_Cuaca  : num [1:743] 5 1 1 2 1 1 3 2 2 2 ...
##  $ Kecepatan_Angin: num [1:743] NA NA NA 2 7 7 9 10 8 7 ...

Fungsi head(data) menampilkan enam baris pertama dari data curah hujan, sedangkan str(data) menunjukkan bahwa data berupa tibble dengan 743 observasi dan 5 variabel, yaitu Hujan, Suhu, Kelembapan, Keadaan_Cuaca, dan Kecepatan_Angin, seluruhnya bertipe numerik (num). Pada enam baris pertama sudah terlihat nilai NA pada Kecepatan_Angin, yang mengindikasikan adanya data hilang.

4.2 Handling Missing Value

# Jumlah missing value setiap variabel
colSums(is.na(data))
##           Hujan            Suhu      Kelembapan   Keadaan_Cuaca Kecepatan_Angin 
##               0               0               0               9             314
# Persentase missing value setiap variabel
colMeans(is.na(data))
##           Hujan            Suhu      Kelembapan   Keadaan_Cuaca Kecepatan_Angin 
##      0.00000000      0.00000000      0.00000000      0.01211306      0.42261104
# Melihat baris yang memiliki missing value
data %>% filter(if_any(everything(), is.na))
## # A tibble: 319 × 5
##    Hujan  Suhu Kelembapan Keadaan_Cuaca Kecepatan_Angin
##    <dbl> <dbl>      <dbl>         <dbl>           <dbl>
##  1     1  23           95             5              NA
##  2     1  24           90             1              NA
##  3     1  26.8         77             1              NA
##  4     1  25           89             2              NA
##  5     1  24.6         90             2              NA
##  6     2  24.2         90             2              NA
##  7     2  23.9         90             2              NA
##  8     2  23.7         91             2              NA
##  9     2  23.5         92             2              NA
## 10     2  23.3         92             2              NA
## # ℹ 309 more rows
#Interpolasi
df_imp <- data

df_imp$Keadaan_Cuaca <- na.approx(
  df_imp$Keadaan_Cuaca,
  na.rm = FALSE
)

# Melihat jumlah missing setelah interpolasi
colSums(is.na(df_imp))
##           Hujan            Suhu      Kelembapan   Keadaan_Cuaca Kecepatan_Angin 
##               0               0               0               0             314
# Menghitung nilai mean Kecepatan_Angin
mean_angin <- mean(
  df_imp$Kecepatan_Angin,
  na.rm = TRUE
)

# Mengisi missing value dengan mean
df_imp$Kecepatan_Angin[
  is.na(df_imp$Kecepatan_Angin)
] <- mean_angin

# Mengecek kembali missing value
colSums(is.na(df_imp))
##           Hujan            Suhu      Kelembapan   Keadaan_Cuaca Kecepatan_Angin 
##               0               0               0               0               0

Hasil colSums(is.na(data)) menunjukkan nilai hilang pada Keadaan_Cuaca sebanyak 9 data dan Kecepatan_Angin sebanyak 314 data, sedangkan Hujan, Suhu, dan Kelembapan lengkap. Persentasenya sebesar 1,21% untuk Keadaan_Cuaca dan 42,26% untuk Kecepatan_Angin. Proporsi 42,26% tergolong sangat besar, sehingga penghapusan baris tidak dipilih karena akan membuang hampir separuh data. Tabel baris bermasalah memperlihatkan 319 baris yang memuat setidaknya satu NA, dan pola awalnya menunjukkan data hilang pada Kecepatan_Angin terkonsentrasi di awal rangkaian data. Setelah interpolasi linear (na.approx), nilai hilang Keadaan_Cuaca menjadi 0, sedangkan Kecepatan_Angin masih 314. Setelah diimputasi dengan rata-rata (sekitar 6,66, tampak pada kolom Kecepatan_Angin di baris pertama output 4.3), seluruh variabel tidak lagi memiliki nilai hilang.

4.3 Kardinalitas

# Melihat kategori unik Keadaan_Cuaca
unique(df_imp$Keadaan_Cuaca)
##  [1]  5.0  1.0  2.0  3.0 14.0 60.0 61.0 21.0 29.0 10.0 16.0 62.0 63.0 65.0 15.0
## [16] 17.0 13.0 95.0 91.0 49.0 97.0 56.0  1.5
# Membuat interval
bins <- c(
  0, 10, 20, 30, 40,
  50, 60, 70, 80, 90, 100
)

# Membuat label kategori
labels <- 0:9

# Mengurangi jumlah kategori
df_imp$Keadaan_Cuaca_reduced <- cut(
  df_imp$Keadaan_Cuaca,
  breaks = bins,
  labels = labels,
  right = TRUE,
  include.lowest = TRUE
)

# Melihat hasil
head(df_imp, 10)
## # A tibble: 10 × 6
##    Hujan  Suhu Kelembapan Keadaan_Cuaca Kecepatan_Angin Keadaan_Cuaca_reduced
##    <dbl> <dbl>      <dbl>         <dbl>           <dbl> <fct>                
##  1     1  23           95             5            6.66 0                    
##  2     1  24           90             1            6.66 0                    
##  3     1  26.8         77             1            6.66 0                    
##  4     1  29.6         62             2            2    0                    
##  5     1  30.8         56             1            7    0                    
##  6     1  31           55             1            7    0                    
##  7     1  30.4         57             3            9    0                    
##  8     2  30.9         58             2           10    0                    
##  9     2  30.2         62             2            8    0                    
## 10     2  29.7         62             2            7    0
# Membandingkan jumlah kategori
cat(
  "Jumlah kategori Keadaan_Cuaca asli :",
  length(unique(df_imp$Keadaan_Cuaca)),
  "\n"
)
## Jumlah kategori Keadaan_Cuaca asli : 23
cat(
  "Jumlah kategori Keadaan_Cuaca setelah reduksi :",
  length(unique(df_imp$Keadaan_Cuaca_reduced)),
  "\n"
)
## Jumlah kategori Keadaan_Cuaca setelah reduksi : 7
# Melihat kategori hasil reduksi
unique(df_imp$Keadaan_Cuaca_reduced)
## [1] 0 1 5 6 2 9 4
## Levels: 0 1 2 3 4 5 6 7 8 9

Variabel Keadaan_Cuaca awalnya memiliki 23 nilai unik (antara lain 1, 2, 3, 5, 10, 14, 60, 95, 97, dan 1,5), yang tergolong kardinalitas tinggi. Jika langsung di-one-hot encoding, jumlah kolom akan melonjak dan berisiko menimbulkan sparsitas. Reduksi dengan cut pada interval lebar 10 menurunkan jumlah kategori menjadi 7 level aktual (0, 1, 2, 4, 5, 6, dan 9) dari 10 level yang didefinisikan. Level 0 mencakup kode 0 sampai 10 sehingga mendominasi, seperti terlihat pada 10 baris pertama yang seluruhnya masuk kategori 0. Artinya reduksi berhasil menyederhanakan fitur, tetapi mengorbankan perbedaan antarkode di dalam satu interval.

4.4 Splitting Data

set.seed(200)

split_shuffle <- initial_split(
  df_imp,
  prop = 0.8
)

# Data training
train_data <- training(split_shuffle)

# Data testing
test_data <- testing(split_shuffle)

# Memisahkan variabel prediktor dan target
X_train <- train_data %>% select(-Hujan)
X_test  <- test_data %>% select(-Hujan)

y_train <- train_data$Hujan
y_test  <- test_data$Hujan

# Melihat ukuran data
dim(X_train)
## [1] 594   5
dim(X_test)
## [1] 149   5

Dengan set.seed(200) dan proporsi 0,8, data terbagi menjadi 594 observasi training dan 149 observasi testing, masing-masing dengan 5 kolom prediktor setelah variabel Hujan dipisahkan sebagai target (kolom prediktor termasuk Keadaan_Cuaca_reduced). Proporsi 594/743 sebesar 79,9% sesuai target 80:20. Penggunaan set.seed menjamin pembagian dapat direproduksi.

4.5 Handling Outlier

# Variabel numerik
list_num <- c(
  "Suhu",
  "Kelembapan",
  "Kecepatan_Angin"
)

# Menyiapkan wadah hasil
list_outlier <- c()
list_lower_bound <- c()
list_upper_bound <- c()

# Menghitung batas outlier dengan IQR
for (i in list_num) {
  
  Q1 <- quantile(
    X_train[[i]],
    0.25,
    na.rm = TRUE
  )
  
  Q3 <- quantile(
    X_train[[i]],
    0.75,
    na.rm = TRUE
  )
  
  IQR_val <- Q3 - Q1
  
  lower_bound <- Q1 - 1.5 * IQR_val
  upper_bound <- Q3 + 1.5 * IQR_val
  
  num_outliers_lower <- sum(
    X_train[[i]] < lower_bound,
    na.rm = TRUE
  )
  
  num_outliers_upper <- sum(
    X_train[[i]] > upper_bound,
    na.rm = TRUE
  )
  
  total_outliers <-
    num_outliers_lower + num_outliers_upper
  
  list_outlier <- c(
    list_outlier,
    total_outliers
  )
  
  list_lower_bound <- c(
    list_lower_bound,
    lower_bound
  )
  
  list_upper_bound <- c(
    list_upper_bound,
    upper_bound
  )
}

# Membuat tabel hasil
outliers <- data.frame(
  Kolom = list_num,
  Jumlah_Outlier = list_outlier,
  Lower_Bound = list_lower_bound,
  Upper_Bound = list_upper_bound
)

outliers
##             Kolom Jumlah_Outlier Lower_Bound Upper_Bound
## 1            Suhu              0        17.4        35.8
## 2      Kelembapan              0        46.5       122.5
## 3 Kecepatan_Angin             50         2.0        10.0

Metode IQR pada data training menghasilkan batas Suhu 17,4 sampai 35,8 dengan 0 outlier, Kelembapan 46,5 sampai 122,5 dengan 0 outlier, dan Kecepatan_Angin 2,0 sampai 10,0 dengan 50 outlier. Jadi Suhu dan Kelembapan tidak memiliki pencilan, sedangkan seluruh pencilan berada pada Kecepatan_Angin, sekitar 8,4% dari 594 observasi. Rentang antarkuartil Kecepatan_Angin yang sempit (hanya 2 sampai 10) sebagian besar disebabkan oleh imputasi rata-rata yang menumpuk banyak nilai di sekitar 6,66.

4.6 Capping

X_train_capped <- X_train
X_test_capped <- X_test

for (i in list_num) {
  
  Q1 <- quantile(
    X_train[[i]],
    0.25,
    na.rm = TRUE
  )
  
  Q3 <- quantile(
    X_train[[i]],
    0.75,
    na.rm = TRUE
  )
  
  IQR_val <- Q3 - Q1
  
  lower_bound <- Q1 - 1.5 * IQR_val
  upper_bound <- Q3 + 1.5 * IQR_val
  
  # Capping data training
  X_train_capped[[i]] <- pmin(
    pmax(
      X_train[[i]],
      lower_bound
    ),
    upper_bound
  )
  
  # Capping data testing menggunakan
  # batas dari data training
  X_test_capped[[i]] <- pmin(
    pmax(
      X_test[[i]],
      lower_bound
    ),
    upper_bound
  )
}
diagnostic_plots <- function(df, variable) {
  
  p1 <- ggplot(
    df,
    aes(x = .data[[variable]])
  ) +
    geom_histogram(
      bins = 30,
      fill = "navy",
      color = "black"
    ) +
    ggtitle("Histogram") +
    theme_minimal()
  
  p2 <- ggplot(
    df,
    aes(y = .data[[variable]])
  ) +
    geom_boxplot(
      fill = "navy"
    ) +
    ggtitle("Boxplot") +
    theme_minimal()
  
  grid.arrange(
    p1,
    p2,
    ncol = 2
  )
}

for (col in list_num) {
  
  cat(
    col,
    "- Sebelum Capping\n"
  )
  
  diagnostic_plots(
    X_train,
    col
  )
  
  cat(
    "\n",
    col,
    "- Setelah Capping\n"
  )
  
  diagnostic_plots(
    X_train_capped,
    col
  )
}
## Suhu - Sebelum Capping

## 
##  Suhu - Setelah Capping

## Kelembapan - Sebelum Capping

## 
##  Kelembapan - Setelah Capping

## Kecepatan_Angin - Sebelum Capping

## 
##  Kecepatan_Angin - Setelah Capping

Nilai di luar batas IQR dari data training dipotong ke batas terdekat, dan batas yang sama dipakai untuk data testing sehingga tidak terjadi kebocoran data. Pada pasangan histogram dan boxplot, variabel Suhu dan Kelembapan tampak identik sebelum dan sesudah capping karena memang tanpa pencilan. Untuk Kecepatan_Angin, boxplot sebelum capping menampilkan titik-titik pencilan di luar whisker, sedangkan setelah capping titik tersebut hilang dan nilai menumpuk pada batas 2 dan 10, yang tampak sebagai batang tinggi di tepi histogram. Ini menunjukkan capping berhasil menekan pengaruh nilai ekstrem tanpa membuang observasi.

4.7 Scaling Data dengan Robust Scaler

# Robust Scaling menggunakan median dan IQR
median_val <- sapply(
  X_train_capped[list_num],
  median,
  na.rm = TRUE
)

iqr_val <- sapply(
  X_train_capped[list_num],
  IQR,
  na.rm = TRUE
)

# Scaling data training
for (col in list_num) {
  
  X_train_capped[[col]] <-
    (
      X_train_capped[[col]] -
        median_val[col]
    ) /
    iqr_val[col]
}

# Scaling data testing menggunakan
# median dan IQR dari data training
for (col in list_num) {
  
  X_test_capped[[col]] <-
    (
      X_test_capped[[col]] -
        median_val[col]
    ) /
    iqr_val[col]
}

# Melihat hasil scaling
head(X_train_capped)
## # A tibble: 6 × 5
##      Suhu Kelembapan Keadaan_Cuaca Kecepatan_Angin Keadaan_Cuaca_reduced
##     <dbl>      <dbl>         <dbl>           <dbl> <fct>                
## 1 -0.500       0.579            61           0     6                    
## 2  1.09       -0.947             2           1.67  0                    
## 3  0.0870     -0.263             3          -0.828 0                    
## 4  1.15       -1.53              2           1.17  0                    
## 5  0.674      -0.421             2           0     0                    
## 6  0.391      -0.368             2          -1.83  0

Median dan IQR dihitung dari data training yang sudah di-capping, lalu rumus (x − median)/IQR diterapkan pada training dan testing. Hasilnya, nilai variabel numerik berpusat di sekitar 0 dan bernilai positif maupun negatif, misalnya Suhu −0,500 dan 1,09 serta Kelembapan 0,579 dan −0,947 pada baris-baris awal. Nilai 0 berarti sama dengan median, dan satuannya kini adalah kelipatan IQR. Karena berbasis median dan IQR, metode ini tahan terhadap sisa efek pencilan.

4.8 Encoding

list_cat <- c(
  "Keadaan_Cuaca_reduced"
)

resep_encode <- recipe(
  ~ Keadaan_Cuaca_reduced,
  data = X_train_capped
) %>%
  step_dummy(
    all_of(list_cat),
    one_hot = TRUE
  ) %>%
  prep(
    training = X_train_capped
  )

X_train_encoded <- bake(
  resep_encode,
  new_data = X_train_capped
)

X_test_encoded <- bake(
  resep_encode,
  new_data = X_test_capped
)

# Melihat hasil encoding
head(X_train_encoded)
## # A tibble: 6 × 10
##   Keadaan_Cuaca_reduced_X0 Keadaan_Cuaca_reduced_X1 Keadaan_Cuaca_reduced_X2
##                      <dbl>                    <dbl>                    <dbl>
## 1                        0                        0                        0
## 2                        1                        0                        0
## 3                        1                        0                        0
## 4                        1                        0                        0
## 5                        1                        0                        0
## 6                        1                        0                        0
## # ℹ 7 more variables: Keadaan_Cuaca_reduced_X3 <dbl>,
## #   Keadaan_Cuaca_reduced_X4 <dbl>, Keadaan_Cuaca_reduced_X5 <dbl>,
## #   Keadaan_Cuaca_reduced_X6 <dbl>, Keadaan_Cuaca_reduced_X7 <dbl>,
## #   Keadaan_Cuaca_reduced_X8 <dbl>, Keadaan_Cuaca_reduced_X9 <dbl>
head(X_test_encoded)
## # A tibble: 6 × 10
##   Keadaan_Cuaca_reduced_X0 Keadaan_Cuaca_reduced_X1 Keadaan_Cuaca_reduced_X2
##                      <dbl>                    <dbl>                    <dbl>
## 1                        1                        0                        0
## 2                        1                        0                        0
## 3                        1                        0                        0
## 4                        1                        0                        0
## 5                        1                        0                        0
## 6                        1                        0                        0
## # ℹ 7 more variables: Keadaan_Cuaca_reduced_X3 <dbl>,
## #   Keadaan_Cuaca_reduced_X4 <dbl>, Keadaan_Cuaca_reduced_X5 <dbl>,
## #   Keadaan_Cuaca_reduced_X6 <dbl>, Keadaan_Cuaca_reduced_X7 <dbl>,
## #   Keadaan_Cuaca_reduced_X8 <dbl>, Keadaan_Cuaca_reduced_X9 <dbl>

Variabel Keadaan_Cuaca_reduced diubah dengan one-hot encoding menjadi 10 kolom biner (X0 sampai X9), dengan nilai 1 pada kolom kategori yang sesuai dan 0 pada lainnya. Pada enam baris pertama training, baris pertama berkategori 6 (X6 bernilai 1) dan lima baris lainnya berkategori 0 (X0 bernilai 1). Karena recipe di-prep dengan data training, data testing ditransformasi dengan skema kolom yang sama. Beberapa kolom (misalnya X3, X7, X8) seluruhnya bernilai 0 karena kategori tersebut tidak muncul pada data.

4.9 Balancing Data dengan SMOTE

# Melihat distribusi target sebelum SMOTE
table(y_train)
## y_train
##   1   2 
## 128 466
# Menggabungkan X dan y
train_full <- X_train_encoded %>%
  mutate(
    Hujan = factor(y_train)
  )

# SMOTE
set.seed(42)

resep_smote <- recipe(
  Hujan ~ .,
  data = train_full
) %>%
  step_smote(
    Hujan,
    over_ratio = 1,
    neighbors = 5
  )

resep_smote_prep <- prep(
  resep_smote,
  training = train_full
)

train_balanced <- bake(
  resep_smote_prep,
  new_data = NULL
)

# Memisahkan kembali X dan y
X_train_balanced <- train_balanced %>%
  select(-Hujan)

y_train_balanced <-
  train_balanced$Hujan

# Melihat distribusi setelah SMOTE
table(y_train_balanced)
## y_train_balanced
##   1   2 
## 466 466

Sebelum SMOTE, target Hujan pada data training berdistribusi 128 observasi kelas 1 dan 466 observasi kelas 2, atau rasio sekitar 21,5% berbanding 78,5%, yang menunjukkan ketidakseimbangan kelas. Setelah SMOTE dengan over_ratio = 1 dan 5 tetangga, kedua kelas masing-masing berjumlah 466, sehingga total data training menjadi 932. Kelas minoritas ditambah 338 observasi sintetis tanpa mengurangi kelas mayoritas. SMOTE hanya diterapkan pada data training, sehingga data testing tetap mencerminkan distribusi asli dan evaluasi model tidak bias.

BAB V KESIMPULAN DAN SARAN

5.1 Kesimpulan

Keberhasilan model tidak hanya ditentukan oleh algoritma yang digunakan. Model membutuhkan data yang bersih, konsisten, relevan, dan berada dalam representasi yang sesuai agar pola dalam data dapat dipelajari dengan baik. Data preprocessing berperan menyiapkan kualitas dasar data, sedangkan feature engineering berperan meningkatkan keterwakilan informasi melalui transformasi, pembentukan, seleksi, atau pengubahan fitur. Ketiga konsep tersebut merupakan tahapan yang saling berkaitan dalam membangun sistem prediksi berbasis machine learning.

Dengan demikian, feature engineering dapat dipahami sebagai proses penting yang menghubungkan data mentah dengan proses pembelajaran model. Penerapannya perlu mempertimbangkan karakteristik data, tujuan analisis, jenis algoritma, interpretabilitas, efisiensi komputasi, dan kemampuan generalisasi. Feature engineering yang tepat dapat membantu model memperoleh informasi yang lebih bermakna, sedangkan penerapan yang tidak tepat dapat meningkatkan redundansi, overfitting, atau risiko data leakage. Oleh karena itu, teknik feature engineering perlu dipilih dan dievaluasi secara sistematis sesuai dengan konteks penelitian.

Hasil preprocessing terhadap 743 observasi curah hujan menunjukkan adanya nilai hilang pada variabel Keadaan_Cuaca sebanyak 9 data dan Kecepatan_Angin sebanyak 314 data. Peneliti menangani nilai hilang pada Keadaan_Cuaca menggunakan interpolasi, sedangkan nilai hilang pada Kecepatan_Angin digantikan dengan nilai rata-rata. Selanjutnya, peneliti mengelompokkan 23 kategori pada variabel Keadaan_Cuaca menjadi 7 kategori berdasarkan interval tertentu. Peneliti membagi data menjadi 594 observasi untuk data training dan 149 observasi untuk data testing. Pada variabel numerik Suhu, Kelembapan, dan Kecepatan_Angin, peneliti mendeteksi pencilan menggunakan metode Interquartile Range (IQR). Peneliti kemudian menangani pencilan dengan teknik capping berdasarkan batas IQR yang dihitung dari data training. Setelah itu, peneliti melakukan standardisasi terhadap variabel numerik menggunakan metode Robust Scaling yang memanfaatkan median dan IQR. Variabel kategorik Keadaan_Cuaca_reduced diubah menjadi variabel dummy. Distribusi target Hujan pada data training menunjukkan ketidakseimbangan kelas. Kelas 1 terdiri atas 128 observasi, sedangkan kelas 2 terdiri atas 466 observasi. Untuk mengatasi ketidakseimbangan tersebut, peneliti menerapkan metode Synthetic Minority Over-sampling Technique (SMOTE) pada data training. Setelah SMOTE diterapkan, masing-masing kelas memiliki 466 observasi. Dengan demikian, data training telah seimbang dan dapat digunakan untuk tahap pemodelan klasifikasi.

5.2 Saran

Praktikan dapat melakukan pembelajaran lebih lanjut mengenai Machine Learning and modern prediction serta cara interpretasinya agar semakin paham. Dapat dilakukan melalui sumber-sumber belajar lainnya. Dalam penulisan laporan praktikan juga diharapkan untuk selalu teliti dan memperhatikan tata cara penulisan yang baik. Penulis juga berharap kritik dan saran kepada pembaca dan asisten praktikum guna membuat laporan ini menjadi lebih baik.

DAFTAR PUSTAKA

Fransiska, H. (2026). Modul Praktikum Machine Learning. Universitas Bengkulu

Koukaras, P., & Tjortjis, C. (2025). Data Preprocessing and Feature Engineering for Data Mining: Techniques, Tools, and Best Practices. In AI (Switzerland) (Vol. 6, Number 10). https://doi.org/10.3390/ai6100257

Mohtasham, F., Pourhoseingholi, M. A., Hashemi Nazari, S. S., Kavousi, K., & Zali, M. R. (2024). Comparative analysis of feature selection techniques for COVID-19 dataset. Scientific Reports, 14(1). https://doi.org/10.1038/s41598-024-69209-6

Mumuni, A., & Mumuni, F. (2025). Automated data processing and feature engineering for deep learning and big data applications: A survey. Journal of Information and Intelligence, 3(2). https://doi.org/10.1016/j.jiixd.2024.01.002

Noroozi, Z., Orooji, A., & Erfannia, L. (2023). Analyzing the impact of feature selection methods on machine learning algorithms for heart disease prediction. Scientific Reports, 13(1). https://doi.org/10.1038/s41598-023-49962-w

Starcke, J., Spadafora, J., Spadafora, J., Spadafora, P., & Toma, M. (2025). The Effect of Data Leakage and Feature Selection on Machine Learning Performance for Early Parkinson’s Disease Detection. Bioengineering, 12(8). https://doi.org/10.3390/bioengineering12080845

Zhang, Y., & Wang, Z. (2023). Feature Engineering and Model Optimization Based Classification Method for Network Intrusion Detection. In Applied Sciences (Switzerland) (Vol. 13, Number 16). https://doi.org/10.3390/app13169363