Perkembangan teknologi informasi menghasilkan data dalam jumlah yang semakin besar dan beragam. Data tersebut dapat dimanfaatkan untuk membangun model machine learning dalam melakukan prediksi maupun klasifikasi. Namun, kualitas model tidak hanya dipengaruhi oleh algoritma yang digunakan, tetapi juga oleh kualitas dan karakteristik fitur yang digunakan sebagai masukan model. Oleh karena itu, diperlukan tahapan pengolahan fitur sebelum proses pemodelan dilakukan.
Salah satu tahapan penting dalam pengolahan data adalah feature engineering. Feature engineering merupakan proses mengolah, mengubah, atau membentuk fitur dari data awal agar informasi yang digunakan oleh model menjadi lebih relevan. Teknik ini dapat dilakukan melalui berbagai proses, seperti transformasi data, pembuatan fitur baru, pengkodean variabel kategorik, normalisasi atau standardisasi, serta seleksi fitur. Proses feature engineering dapat digunakan untuk membentuk karakteristik data yang lebih sesuai dalam penerapan machine learning (Faiz, Somantri, dan Muhammad, 2022).
Selain pembentukan fitur, pemilihan fitur yang relevan juga penting karena jumlah dan karakteristik fitur dapat memengaruhi kinerja model. Jumlah fitur yang digunakan dapat memengaruhi performa beberapa algoritma machine learning (Liandana dan Susila, 2023). Penerapan feature selection berbasis korelasi dapat digunakan untuk mengidentifikasi atribut yang relevan sebelum proses klasifikasi (Priantama dan Siswa, 2022).
Berdasarkan latar belakang diatas, rumusan masalah penelitian ini yaitu:
Berdasarkan rumusan masalah diatas, tujuan dari penelitian ini yaitu:
Feature engineering adalah proses mengolah fitur yang berasal dari data awal sehingga diperoleh representasi data yang lebih sesuai untuk digunakan dalam pemodelan. Proses tersebut dapat berupa mengubah bentuk fitur, membuat fitur baru, menggabungkan beberapa fitur, maupun memilih fitur yang relevan. Feature engineering dapat diterapkan sebagai bagian dari proses persiapan data untuk meningkatkan kesesuaian fitur dengan kebutuhan model machine learning (Faiz, Somantri, dan Muhammad, 2022).
Berikut merupakan beberapa jenis feature engineering yang harus dilakukan (Fransisika, 2026):
Handling missing value adalah kejadian yang umum dan dapat berdampak signifikan pada pemodelan machine learning. Data yang tidak lengkap adalah masalah yang tidak terhindarkan dalam menangani sebagian besar sumber data.
Kardinalitas merujuk pada jumlah nilai unik, atau label, yang terdapat dalam suatu variabel kategoris.Konsep ini digunakan untuk mengukur granularitas atau keunikan data dalam sebuah fitur.
Splitting data merupakan strategi fundamental dalam machine learning untuk membagi himpunan data menjadi bagian terpisah: data training dan data testing.
Handling outlier merupakan observasi atau titik data yang menunjukkan deviasi ekstrem dan berbeda secara signifikan dari sebagian besar data lain dalam suatu set data.
Scaling data adalah salah satu langkah pra-pemrosesan dalam analisis data untuk mentransformasi variabel data ke dalam rentang skala yang sama. Tujuannya adalah untuk memastikan bahwa tidak ada satu variabel independen pun yang mendominasi proses pembelajaran hanya karena memiliki rentang nilai yang lebih besar dibandingkan variabel independen lainnya.
Feature encoding adalah proses mengubah fitur kategoris atau non numerik menjadi format numerik yang dapat digunakan sebagai input untuk algoritma machine learning.
Imbalanced dataset adalah sebuah dataset di mana distribusi kelas atau kategorinya tidak setara. Kelas-kelas yang mencakup proporsi besar dari set data disebut kelas mayoritas, sedangkan kelas-kelas yang mencakup proporsi lebih kecil disebut kelas minoritas.
Jenis data yang digunakan dalam penelitian ini berupa data kuantitatif. Sumber data yang digunakan dalam penelitian ini adalah data sekunder. Data sekunder adalah sumber data yang diperoleh secara tidak langsung melalui perantara (diperoleh dan dicatat oleh pihak lain). Pada penelitian ini data sekunder yang dimaksud adalah data yang diperoleh dari dari soal batasan masalah.
Variabel penelitian adalah suatu atribut atau sifat atau nilai dari orang, objek, organisasi, atau kegiatan yang mempunyai variasi tertentu yang ditetapkan oleh peneliti untuk dipelajari dan kemudian ditarik kesimpulannya. Pada penelitian ini menggunakan lima variabel. Variabel tersebut adalah Hujan, Suhu, Kelembapan, Keadaan Cuaca dan Kecepatan Angin.
Algoritma batasan masalah adalah sebagai berikut:
# Memanggil package
library(readxl)
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(caret)
## Loading required package: ggplot2
## Loading required package: lattice
library(tidyr)
library(zoo)
##
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
##
## as.Date, as.Date.numeric
library(themis)
## Loading required package: recipes
##
## Attaching package: 'recipes'
## The following object is masked from 'package:stats':
##
## step
library(recipes)
# Membaca dataset
data <- read_excel(
"D:/SMT 7/LAPRAK/LAPRAK ML/data curah hujan laprak 1 ml.xlsx")
# Melihat struktur dataset
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 ...
# Melihat 6 baris pertama
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
# Melihat ukuran dataset
dim(data)
## [1] 743 5
# Mengecek missing value pada setiap variabel
colSums(is.na(data))
## Hujan Suhu Kelembapan Keadaan_Cuaca Kecepatan_Angin
## 0 0 0 9 314
Hasil pemeriksaan missing value menunjukkan bahwa variabel Hujan, Suhu dan Kelembapan tidak memiliki data yang hilang. Sedangkan variabel Keadaan Cuaca dan Kecepatan Angin memiliki sebanyak 9 dan 314 data hilang. Dengan demikian, terdapat missing value yang perlu ditangani pada tahap preprocessing, khususnya melalui interpolasi pada variabel Keadaan Cuaca dan mode imputation pada data yang masih memiliki nilai hilang.
# MODE IMPUTATION
get_mode <- function(x) {
x <- x[!is.na(x)]
nilai_unik <- unique(x)
nilai_unik[
which.max(tabulate(match(x, nilai_unik)))
]
}
# Menghitung modus Kecepatan_Angin
mode_angin <- get_mode(data$Kecepatan_Angin)
cat("Modus Kecepatan_Angin:", mode_angin, "\n")
## Modus Kecepatan_Angin: 3
# Mengisi missing value menggunakan modus
data$Kecepatan_Angin[
is.na(data$Kecepatan_Angin)
] <- mode_angin
# Memeriksa hasil imputasi
colSums(is.na(data))
## Hujan Suhu Kelembapan Keadaan_Cuaca Kecepatan_Angin
## 0 0 0 9 0
Hasil pemeriksaan setelah imputasi menunjukkan bahwa variabel Kecepatan Angin sudah tidak memiliki missing value. Sementara itu, variabel Keadaan Cuaca masih memiliki 9 missing value.
# Interpolasi linear untuk mengisi missing value
data$Keadaan_Cuaca <- na.approx(
data$Keadaan_Cuaca,
na.rm = FALSE
)
# Mengisi NA pada bagian awal data
data$Keadaan_Cuaca <- na.locf(
data$Keadaan_Cuaca,
na.rm = FALSE
)
# Mengisi NA pada bagian akhir data
data$Keadaan_Cuaca <- na.locf(
data$Keadaan_Cuaca,
fromLast = TRUE,
na.rm = FALSE
)
# Memeriksa missing value setelah imputasi
cat("Missing value setelah imputasi:\n")
## Missing value setelah imputasi:
print(colSums(is.na(data)))
## Hujan Suhu Kelembapan Keadaan_Cuaca Kecepatan_Angin
## 0 0 0 0 0
Hasil pemeriksaan menunjukkan bahwa jumlah missing value pada variabel Keadaan Cuaca adalah 0. Dengan demikian, variabel Keadaan Cuaca dapat digunakan untuk tahap preprocessing selanjutnya.
# STRATIFIED SPLITTING
# Mengubah variabel target menjadi faktor
data$Hujan <- factor(data$Hujan)
set.seed(123)
# Membagi data secara stratified dengan proporsi 80:20
index_train <- createDataPartition(
data$Hujan,
p = 0.80,
list = FALSE
)
# Membentuk data training dan testing
train_data <- data[index_train, ]
test_data <- data[-index_train, ]
# Memeriksa ukuran data
cat("Jumlah data training:", nrow(train_data), "\n")
## Jumlah data training: 596
cat("Jumlah data testing:", nrow(test_data), "\n")
## Jumlah data testing: 147
# Memeriksa distribusi kelas
cat("\nDistribusi kelas data awal:\n")
##
## Distribusi kelas data awal:
print(table(data$Hujan))
##
## 1 2
## 164 579
cat("\nDistribusi kelas training:\n")
##
## Distribusi kelas training:
print(table(train_data$Hujan))
##
## 1 2
## 132 464
cat("\nDistribusi kelas testing:\n")
##
## Distribusi kelas testing:
print(table(test_data$Hujan))
##
## 1 2
## 32 115
# Memisahkan target dan prediktor
y_train <- train_data$Hujan
y_test <- test_data$Hujan
X_train <- train_data %>%
select(-Hujan)
X_test <- test_data %>%
select(-Hujan)
Hasil stratified splitting, menunjukkan sebanyak 743 data dibagi menjadi 596 data training (80%) dan 147 data testing (20%) dengan kelas 1 sebanyak 132 data training dan 32 data testing, sedangkan kelas 2 sebanyak 464 data training dan 115 data testing. Hal tersebut menunjukkan, bahwa data masih belum seimbangan karena jumlah kelas 2 jauh lebih banyak daripada kelas 1.
# Capping
# Variabel numerik kontinu yang akan di-capping
library(gridExtra)
##
## Attaching package: 'gridExtra'
## The following object is masked from 'package:dplyr':
##
## combine
list_num <- c(
"Suhu",
"Kelembapan",
"Kecepatan_Angin"
)
# Menyiapkan tabel batas capping
batas_capping <- data.frame(
Variabel = character(),
Batas_Bawah = numeric(),
Batas_Atas = numeric()
)
# Menghitung batas capping dari training
for (col in list_num) {
Q1 <- quantile(X_train[[col]], 0.25, na.rm = TRUE)
Q3 <- quantile(X_train[[col]], 0.75, na.rm = TRUE)
IQR_value <- Q3 - Q1
lower_bound <- Q1 - 1.5 * IQR_value
upper_bound <- Q3 + 1.5 * IQR_value
batas_capping <- rbind(
batas_capping,
data.frame(Variabel = col,
Batas_Bawah = lower_bound,
Batas_Atas = upper_bound
)
)
# Capping data training
X_train[[col]] <- pmax(
pmin(X_train[[col]], upper_bound),
lower_bound
)
# Capping data testing menggunakan batas training
X_test[[col]] <- pmax(
pmin(X_test[[col]], upper_bound),
lower_bound
)
}
# Menampilkan batas capping
print(batas_capping)
## Variabel Batas_Bawah Batas_Atas
## 25% Suhu 17.25 36.05
## 25%1 Kelembapan 44.00 124.00
## 25%2 Kecepatan_Angin -3.00 13.00
# Memeriksa ringkasan data setelah capping
summary(X_train[list_num])
## Suhu Kelembapan Kecepatan_Angin
## Min. :22.60 Min. : 52.00 Min. : 2.000
## 1st Qu.:24.30 1st Qu.: 74.00 1st Qu.: 3.000
## Median :26.10 Median : 86.00 Median : 3.000
## Mean :26.59 Mean : 83.66 Mean : 5.159
## 3rd Qu.:29.00 3rd Qu.: 94.00 3rd Qu.: 7.000
## Max. :32.00 Max. :100.00 Max. :13.000
# Membuat fungsi visualisasi
diagnostic_plots <- function(df, variable) {
p1 <- ggplot(df, aes(x = .data[[variable]])) +
geom_histogram(
bins = 30,
fill = "#008080",
color = "black"
) +
ggtitle(paste("Histogram", variable)) +
theme_minimal()
p2 <- ggplot(df, aes(y = .data[[variable]])) +
geom_boxplot(fill = "#008080") +
ggtitle(paste("Boxplot", variable)) +
theme_minimal()
grid.arrange(p1, p2, ncol = 2)
}
# Visualisasi setelah capping
for (col in list_num) {
diagnostic_plots(X_train, col)
}
Hasil capping menunjukkan bahwa nilai pada variabel numerik,
yaitu Suhu, Kelembapan, dan Kecepatan Angin, telah dibatasi menggunakan
metode IQR berdasarkan data training. Berdasarkan ringkasan
data setelah capping, nilai maksimum Suhu sebesar 32,00,
Kelembapan sebesar 100,00, dan Kecepatan Angin sebesar 13,00. Histogram
dan boxplot digunakan untuk melihat distribusi data serta
memeriksa keberadaan pencilan setelah proses capping.
# STANDARD SCALER
# Menghitung rata-rata dan standar deviasi training
mean_train <- sapply(
X_train[list_num],
mean,
na.rm = TRUE
)
sd_train <- sapply(
X_train[list_num],
sd,
na.rm = TRUE
)
# Memastikan tidak ada variabel dengan standar deviasi nol
if (any(sd_train == 0 | !is.finite(sd_train))) {
stop("Ada variabel dengan standar deviasi nol atau tidak valid.")
}
# Standardisasi data training
for (col in list_num) {
X_train[[col]] <- (
X_train[[col]] - mean_train[col]
) / sd_train[col]
}
# Standardisasi data testing menggunakan parameter training
for (col in list_num) {
X_test[[col]] <- (
X_test[[col]] - mean_train[col]
) / sd_train[col]
}
# Menggabungkan kembali target dan prediktor
train_scaled <- X_train %>%
mutate(Hujan = y_train) %>%
select(all_of(names(train_data)))
test_scaled <- X_test %>%
mutate(Hujan = y_test) %>%
select(all_of(names(test_data)))
# Memeriksa hasil scaling
cat("Rata-rata training setelah Standard Scaler:\n")
## Rata-rata training setelah Standard Scaler:
print(sapply(train_scaled[list_num], mean))
## Suhu Kelembapan Kecepatan_Angin
## 1.568038e-16 -9.093127e-17 3.617033e-17
cat("\nStandar deviasi training setelah Standard Scaler:\n")
##
## Standar deviasi training setelah Standard Scaler:
print(sapply(train_scaled[list_num], sd))
## Suhu Kelembapan Kecepatan_Angin
## 1 1 1
# Melihat hasil standardisasi
head(train_scaled)
## # A tibble: 6 × 5
## Hujan Suhu Kelembapan Keadaan_Cuaca Kecepatan_Angin
## <fct> <dbl> <dbl> <dbl> <dbl>
## 1 1 -1.40 0.981 5 -0.704
## 2 1 1.17 -1.87 2 -1.03
## 3 1 1.63 -2.39 1 0.600
## 4 1 1.71 -2.48 1 0.600
## 5 1 1.48 -2.31 3 1.25
## 6 2 1.40 -1.87 2 0.926
Hasil Standard Scaler menunjukkan bahwa seluruh variabel prediktor memiliki mean mendekati 0 dan standar deviasi sebesar 1. Hal ini menunjukkan bahwa proses standardisasi pada data training telah berhasil. Dengan demikian, variabel Suhu, Kelembapan, Keadaan Cuaca dan Kecepatan Angin telah berada pada skala yang seragam.
# PEMERIKSAAN IMBALANCE DATA
cat("Distribusi kelas sebelum SMOTE:\n")
## Distribusi kelas sebelum SMOTE:
print(table(train_scaled$Hujan))
##
## 1 2
## 132 464
cat("\nProporsi kelas sebelum SMOTE:\n")
##
## Proporsi kelas sebelum SMOTE:
print(prop.table(table(train_scaled$Hujan)))
##
## 1 2
## 0.2214765 0.7785235
Sebelum dilakukan SMOTE, data training terdiri dari 132 data kelas 1 (22,14765%) dan 464 data kelas 2 (77,85235%). Hal ini menunjukkan bahwa data mengalami ketidakseimbangan kelas, karena jumlah kelas 2 jauh lebih banyak dibandingkan kelas 1. Oleh karena itu, diperlukan metode SMOTE untuk menyeimbangkan distribusi kelas sebelum dilakukan pemodelan.
# SMOTE
# Memeriksa distribusi kelas sebelum SMOTE
rec_smote <- recipe(Hujan ~ ., data = train_scaled) %>%
step_smote(Hujan, over_ratio = 1)
# Melakukan preprocessing SMOTE pada data training
prep_smote <- prep(rec_smote, training = train_scaled)
# Mengambil data training setelah SMOTE
train_smote <- juice(prep_smote)
# Distribusi kelas sebelum SMOTE
cat("Distribusi kelas sebelum SMOTE:\n")
## Distribusi kelas sebelum SMOTE:
print(table(train_scaled$Hujan))
##
## 1 2
## 132 464
# Distribusi kelas setelah SMOTE
cat("\nDistribusi kelas setelah SMOTE:\n")
##
## Distribusi kelas setelah SMOTE:
print(table(train_smote$Hujan))
##
## 1 2
## 464 464
# Proporsi kelas setelah SMOTE
cat("\nProporsi kelas setelah SMOTE:\n")
##
## Proporsi kelas setelah SMOTE:
print(prop.table(table(train_smote$Hujan)))
##
## 1 2
## 0.5 0.5
# Ukuran data setelah SMOTE
cat("\nUkuran data setelah SMOTE:\n")
##
## Ukuran data setelah SMOTE:
print(dim(train_smote))
## [1] 928 5
# Distribusi kelas data testing
cat("Distribusi kelas data testing:\n")
## Distribusi kelas data testing:
print(table(test_scaled$Hujan))
##
## 1 2
## 32 115
# Melihat hasil akhir data training dan testing
head(train_smote)
## # A tibble: 6 × 5
## Suhu Kelembapan Keadaan_Cuaca Kecepatan_Angin Hujan
## <dbl> <dbl> <dbl> <dbl> <fct>
## 1 -1.40 0.981 5 -0.704 1
## 2 1.17 -1.87 2 -1.03 1
## 3 1.63 -2.39 1 0.600 1
## 4 1.71 -2.48 1 0.600 1
## 5 1.48 -2.31 3 1.25 1
## 6 1.40 -1.87 2 0.926 2
head(test_scaled)
## # A tibble: 6 × 5
## Hujan Suhu Kelembapan Keadaan_Cuaca Kecepatan_Angin
## <fct> <dbl> <dbl> <dbl> <dbl>
## 1 1 -1.01 0.549 1 -0.704
## 2 1 0.0801 -0.576 1 -0.704
## 3 2 1.67 -2.22 2 1.58
## 4 2 1.21 -1.87 2 0.600
## 5 2 0.780 -0.922 1 -0.0520
## 6 1 -0.347 0.203 2 -1.03
Setelah dilakukan SMOTE, jumlah kelas 1 dan kelas 2 menjadi sama, yaitu masing-masing 464 data (50%). Jumlah data training meningkat menjadi 928 observasi dan 5 variabel karena SMOTE menambahkan data sintetis pada kelas minoritas. Dengan demikian, ketidakseimbangan kelas berhasil diatasi.
Konsep berbagai jenis feature engineering pada RStudio dapat dipahami melalui proses pengolahan dan pembentukan fitur, seperti feature transformation, feature creation, encoding, dan feature selection untuk menghasilkan data yang lebih sesuai dalam proses pemodelan.
Teknik feature engineering dapat dilakukan pada program RStudio dengan memanfaatkan fungsi dan paket yang tersedia untuk melakukan transformasi, pembentukan, serta pemilihan fitur sesuai dengan karakteristik data.
Berdasarkan hasil preprocessing data, dapat disimpulkan bahwa data curah hujan yang terdiri dari 743 observasi dan 5 variabel telah melalui beberapa tahap pengolahan. Missing value pada variabel Keadaan Cuaca berhasil ditangani dengan interpolasi, sedangkan missing value pada variabel Kecepatan Angin ditangani menggunakan mode imputation. Selanjutnya, outlier pada variabel numerik ditangani menggunakan capping. Data kemudian dibagi menggunakan stratified splitting menjadi 596 data training dan 147 data testing dengan proporsi kelas yang tetap terjaga. Standardisasi menggunakan Standard Scaler berhasil menghasilkan mean mendekati 0 dan standar deviasi 1. Terakhir, SMOTE berhasil menyeimbangkan kelas pada data training menjadi masing-masing 464 data atau 50%.
Fransiska, H. (2026). Modul Praktikum Machine Learning and Modern Prediction. Bengkulu: Laboratorium Statistika Universitas Bengkulu.
Faiz, M. N., Somantari, O., Muhammad, A. W. (2022). Machine Learning-Based Feature Engineering to Detect DDoS Attacks. Jurnal Nasional Teknik Elektro dan Teknologi Informasi.
Priantama, Y., Siswa, T. A. Y. (2022). Optimasi Correlation-Based Feature Selection Untuk Perbaikan Akurasi Random Forest Classifier Dalam Prediksi Performa Akademik Mahasiswa. Jurnal Informatika dan Komputer. perb Liandana, M., Susila, I. M. D. (2023).Pengaruh Jumlah Fitur pada Algoritma Machine Learning dam Memprediksi Aktivitas Jatuh. Jurnal Sistem dan Informatika.