Curah hujan merupakan parameter meteorologi penting yang memiliki pengaruh signifikan terhadap berbagai sekto. Namun, data curah hujan sering mengandung pencilan dan distribusi kelas yang tidak seimbang, yang berpotensi menurunkan kinerja model klasifikasi berbasis pembelajaran mesin (Naufal dkk., 2026). metode Synthetic Minority Over-Sampling (SMOTE) efektif dalam menangani ketidakseimbangan data (Srivani dkk., 2024). Peningkatan penggunaan teknik pembelajaran mesin (Machine Learning) untuk mengidentifikasi dan meramalkan tren di berbagai industri adalah hasil dari perkembangan teknologi yang terus-menerus dan cepat (Bertolini dkk., 2021). Salah satu aspek penting dalam pembangunan model prediktif melibatkan teknik Feature Engineering yaitu sebuah teknik merekayasa fitur-fitur, karena sangat diperlukan untuk menciptakan representasi data yang sesuai untuk model pembelajaran (Rajoub,, 2020). Feature engineering merupakan langkah krusial dalam machine learning yang mencakup proses pembuatan, pemilihan, serta transformasi fitur dari data mentah dengan tujuan meningkatkan kinerja model (Firman dkk., 2025)
Feature Engineering dengan cermat merancang, membuat, dan memilih fitur berdasarkan pengetahuan dalam bidang tertentu serta analisis data. Pemilihan fitur menggunakan metode seperti Recursive Feature Elimination (RFE) dapat memberikan manfaat (Herdian dkk.,2024). Berikut beberapa jenis feature engineering yaitu:
Metode FS adalah teknik yang digunakan untuk meningkatkan kinerja dengan menyaring karakteristik yang digunakan dalam machine learning. Teknik feature selection (FS) berperan dalam menyaring atribut paling relevan selama pelatihan model, dengan memprioritaskan fitur yang memiliki daya pembeda signifikan (Firman dkk., 2025). Proses ini tidak hanya meningkatkan presisi model melalui pemilihan fitur esensial, tetapi juga mengoptimalkan efisiensi komputasi dengan memangkas dimensi data yang tidak informatif.Tujuannya adalah mengurangi beban pemrosesan dengan mengurangi jumlah fitur serta meningkatkan akurasi klasifikasi (Lee dkk.,2017)
Missing values atau missing data, terjadi ketika tidak ada data / tidak ada nilai yang tersimpan untuk observasi tertentu dalam suatu variabel. Missing data 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 (Fransiska, 2026)
Splitting data merupakan strategi fundamental dalam machine learning untuk membagi himpunan data menjadi bagian terpisah: data training dan data testing. Pembagian ini krusial untuk membangun model yang robust dan dapat digeneralisasi dengan baik pada data baru (Muraina, 2022).
Teknik feature engineering pada program RStudio diterapkan melalui beberapa tahapan pengolahan data. Missing value ditangani melalui penghapusan data, forward fill, mean imputation, median imputation, dan interpolasi. Pada tahap kardinalitas, dilakukan binning untuk mengurangi jumlah kategori. Pembagian data dilakukan menggunakan metode non-shuffle, shuffle, dan stratified. Selanjutnya, outlier diidentifikasi berdasarkan metode IQR dan ditangani melalui trimming atau capping. Pen-skala-an variabel numerik dilakukan dengan standard scaling dan robust scaling. Variabel kategorik kemudian ditransformasikan menggunakan One-Hot Encoding dan Ordinal Encoding. Tahap terakhir dilakukan dengan menerapkan SMOTE untuk menangani ketidakseimbangan dat (Fransiska, 2026)
Sumber data yang digunakan dalam penelitian ini yaitu data sekunder yang diperoleh secara tidak langsung melalui perantara (diperoleh dan dicatat oleh pihak lain). Data sekunder yang dimaksud adalah dari modul praktikum Machine Learning and Modern Prediction.
Pada penelitian ini, variabel yang digunakan terdiri atas variabel prediktor dan variabel target. Variabel target yang digunakan yaitu Hujan, sedangkan variabel prediktor terdiri atas Suhu, Kelembapan, Keadaan Cuaca, dan Kecepatan Angin. Variabel Hujan merupakan nilai curah hujan yang diamati, Suhu merupakan nilai suhu udara, Kelembapan menunjukkan tingkat kelembapan udara, Keadaan Cuaca menunjukkan kondisi cuaca, sedangkan Kecepatan Angin merupakan nilai kecepatan angin yang diamati.
Langkah-langkah analisis dalam praktikum ini adalah sebagai berikut:
##
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
##
## as.Date, as.Date.numeric
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.2.1 ✔ readr 2.2.0
## ✔ forcats 1.0.1 ✔ stringr 1.6.0
## ✔ ggplot2 4.0.3 ✔ tibble 3.3.1
## ✔ lubridate 1.9.5 ✔ tidyr 1.3.2
## ✔ purrr 1.2.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
##
## Attaching package: 'e1071'
##
## The following object is masked from 'package:rsample':
##
## permutations
##
## The following object is masked from 'package:ggplot2':
##
## element
##
## Attaching package: 'gridExtra'
##
## The following object is masked from 'package:dplyr':
##
## combine
##
## Attaching package: 'recipes'
##
## The following object is masked from 'package:stringr':
##
## fixed
##
## The following object is masked from 'package:stats':
##
## step
## Loading required package: lattice
##
## Attaching package: 'caret'
##
## The following objects are masked from 'package:DescTools':
##
## MAE, RMSE
##
## The following object is masked from 'package:rsample':
##
## calibration
##
## The following object is masked from 'package:purrr':
##
## lift
data <- read_excel("D:/Materi Statistika/MATERI SEMESTER 7/Machine Learning & Modern Prediction/LAPRAK ML & MP/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
## 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 ...
## Hujan Suhu Kelembapan Keadaan_Cuaca
## Min. :1.000 Min. :22.60 Min. : 52.00 Min. : 1.00
## 1st Qu.:2.000 1st Qu.:24.30 1st Qu.: 75.00 1st Qu.: 2.00
## Median :2.000 Median :26.00 Median : 86.00 Median : 2.00
## Mean :1.779 Mean :26.54 Mean : 83.88 Mean :15.11
## 3rd Qu.:2.000 3rd Qu.:28.90 3rd Qu.: 94.00 3rd Qu.:15.00
## Max. :2.000 Max. :32.00 Max. :100.00 Max. :97.00
## NAs :9
## Kecepatan_Angin
## Min. : 2.000
## 1st Qu.: 4.000
## Median : 6.000
## Mean : 6.655
## 3rd Qu.: 9.000
## Max. :21.000
## NAs :314
Analisis deskriptif dilakukan untuk memberikan gambaran umum mengenai karakteristik data sebelum dilakukan tahap preprocessing. Informasi mengenai pemusatan dan penyebaran data dapat dilihat melalui nilai minimum, kuartil, median, rata-rata, dan maksimum, serta digunakan untuk mengetahui kondisi awal data. Dari hasil tersebut diketahui bahwa data memiliki nilai yang bervariasi pada setiap variabel. Selain itu, terdapat 9 missing value pada Keadaan_Cuaca dan 314 missing value pada Kecepatan_Angin. Hasil ini menunjukkan kondisi awal data yang perlu diperhatikan sebelum dilakukan tahap preprocessing selanjutnya.
## Hujan Suhu Kelembapan Keadaan_Cuaca Kecepatan_Angin
## 0 0 0 9 314
## Hujan Suhu Kelembapan Keadaan_Cuaca Kecepatan_Angin
## 0.00000000 0.00000000 0.00000000 0.01211306 0.42261104
## # A tibble: 9 × 5
## Hujan Suhu Kelembapan Keadaan_Cuaca Kecepatan_Angin
## <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 2 26 92 NA NA
## 2 1 23.8 98 NA 5
## 3 1 23.3 97 NA NA
## 4 2 28.8 79 NA 12
## 5 2 24.6 92 NA NA
## 6 1 22.8 98 NA 4
## 7 2 25.5 96 NA NA
## 8 2 27 80 NA 4
## 9 2 31 57 NA 6
# Penanganan Missing Value - Mode Imputation (Kecepatan_Angin)
df_imp1 <- data
get_mode <- function(x) {
ux <- unique(na.omit(x))
ux[which.max(tabulate(match(x, ux)))]
}
mode_value <- get_mode(df_imp1$Kecepatan_Angin)
df_imp1$Kecepatan_Angin[is.na(df_imp1$Kecepatan_Angin)] <- mode_value
colSums(is.na(df_imp1)) ## Hujan Suhu Kelembapan Keadaan_Cuaca Kecepatan_Angin
## 0 0 0 9 0
Hasil pengecekan menunjukkan bahwa Keadaan_Cuaca memiliki 9 missing value (1,21%), sedangkan Kecepatan_Angin memiliki 314 missing value (42,26%). Variabel lainnya tidak memiliki data yang hilang.
Missing value pada Kecepatan_Angin ditangani menggunakan mode imputation. Setelah dilakukan imputasi, jumlah missing value pada Kecepatan_Angin menjadi 0, sedangkan 9 missing value pada Keadaan_Cuaca akan ditangani pada tahap interpolasi.
df_imp4 <- df_imp1
df_imp4$Keadaan_Cuaca <- na.approx(
df_imp4$Keadaan_Cuaca,
na.rm = FALSE
)
colSums(is.na(df_imp4)) ## Hujan Suhu Kelembapan Keadaan_Cuaca Kecepatan_Angin
## 0 0 0 0 0
Hasil interpolasi menunjukkan bahwa 9 data pada variabel Keadaan_Cuaca yang sebelumnya hilang telah terisi berdasarkan nilai pada pengamatan sebelum dan sesudahnya. Setelah proses ini, seluruh variabel memiliki 0 missing value, sehingga data telah lengkap untuk tahap analisis selanjutnya.
set.seed(200)
split_stratify <- initial_split(
df_imp4,
prop = 0.8,
strata = Hujan
)
X_train <- training(split_stratify) %>% select(-Hujan)
X_test <- testing(split_stratify) %>% select(-Hujan)
y_train <- training(split_stratify)$Hujan
y_test <- testing(split_stratify)$Hujan
dim(X_train)## [1] 594 4
## [1] 149 4
Hasil stratify splitting membagi data menjadi 594 data training dan 149 data testing. Dengan demikian, sebanyak 80% data digunakan sebagai data training dan 20% sebagai data testing. Pembagian dilakukan berdasarkan variabel Hujan untuk mempertahankan proporsi kelas pada data training dan testing.
list_num <- c("Suhu", "Kelembapan", "Kecepatan_Angin")
# Capping
X_train_capped <- X_train
X_test_capped <- X_test
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_val <- Q3 - Q1
lower_bound <- Q1 - 1.5 * IQR_val
upper_bound <- Q3 + 1.5 * IQR_val
X_train_capped[[col]] <- Winsorize(
X_train[[col]],
val = c(lower_bound, upper_bound)
)
X_test_capped[[col]] <- Winsorize(
X_test[[col]],
val = c(lower_bound, upper_bound)
)
}
# Plot Before dan After Capping
diagnostic_plots <- function(df, variable) {
p1 <- ggplot(df, aes(x = .data[[variable]])) +
geom_histogram(bins = 30, fill = "#008080", color = "black") +
ggtitle(paste(variable, "- Histogram")) +
theme_minimal()
p2 <- ggplot(df, aes(y = .data[[variable]])) +
geom_boxplot(fill = "#008080") +
ggtitle(paste(variable, "- Boxplot")) +
theme_minimal()
grid.arrange(p1, p2, ncol = 2)
}
for (col in list_num) {
cat("\n", col, "- Before Capping\n")
print(diagnostic_plots(X_train, col))
cat("\n", col, "- After Capping\n")
print(diagnostic_plots(X_train_capped, col))
}##
## Suhu - Before Capping
## TableGrob (1 x 2) "arrange": 2 grobs
## z cells name grob
## 1 1 (1-1,1-1) arrange gtable[layout]
## 2 2 (1-1,2-2) arrange gtable[layout]
##
## Suhu - After Capping
## TableGrob (1 x 2) "arrange": 2 grobs
## z cells name grob
## 1 1 (1-1,1-1) arrange gtable[layout]
## 2 2 (1-1,2-2) arrange gtable[layout]
##
## Kelembapan - Before Capping
## TableGrob (1 x 2) "arrange": 2 grobs
## z cells name grob
## 1 1 (1-1,1-1) arrange gtable[layout]
## 2 2 (1-1,2-2) arrange gtable[layout]
##
## Kelembapan - After Capping
## TableGrob (1 x 2) "arrange": 2 grobs
## z cells name grob
## 1 1 (1-1,1-1) arrange gtable[layout]
## 2 2 (1-1,2-2) arrange gtable[layout]
##
## Kecepatan_Angin - Before Capping
## TableGrob (1 x 2) "arrange": 2 grobs
## z cells name grob
## 1 1 (1-1,1-1) arrange gtable[layout]
## 2 2 (1-1,2-2) arrange gtable[layout]
##
## Kecepatan_Angin - After Capping
## TableGrob (1 x 2) "arrange": 2 grobs
## z cells name grob
## 1 1 (1-1,1-1) arrange gtable[layout]
## 2 2 (1-1,2-2) arrange gtable[layout]
Hasil capping pada variabel Suhu, Kelembapan, dan Kecepatan_Angin
menunjukkan perubahan pada nilai yang berada di luar batas IQR.
Perubahan terlihat pada histogram dan terutama pada boxplot, sementara
sebagian besar pola distribusi data tetap dipertahankan. Hal ini
menunjukkan bahwa capping membatasi nilai pencilan tanpa menghapus
pengamatan dari data.
mean_val <- sapply(X_train_capped[list_num], mean, na.rm = TRUE)
sd_val <- sapply(X_train_capped[list_num], sd, na.rm = TRUE)
# Data training
for (col in list_num) {
X_train_capped[[col]] <- (X_train_capped[[col]] - mean_val[col]) / sd_val[col]
}
# Data testing (memakai mean dan sd dari data training)
for (col in list_num) {
X_test_capped[[col]] <- (X_test_capped[[col]] - mean_val[col]) / sd_val[col]
}
X_train_scale <- X_train_capped
X_test_scale <- X_test_capped
head(X_train_scale)## # A tibble: 6 × 4
## Suhu Kelembapan Keadaan_Cuaca Kecepatan_Angin
## <dbl> <dbl> <dbl> <dbl>
## 1 -1.39 0.973 5 -0.693
## 2 -1.00 0.540 1 -0.693
## 3 0.0947 -0.585 1 -0.693
## 4 1.19 -1.88 2 -1.03
## 5 1.66 -2.40 1 0.646
## 6 1.50 -2.32 3 1.32
## Suhu Kelembapan Kecepatan_Angin
## Min. :-1.5477 Min. :-2.7493 Min. :-1.0273
## 1st Qu.:-0.8732 1st Qu.:-0.7582 1st Qu.:-0.6926
## Median :-0.2182 Median : 0.1941 Median :-0.6926
## Mean : 0.0000 Mean : 0.0000 Mean : 0.0000
## 3rd Qu.: 0.9159 3rd Qu.: 0.8867 3rd Qu.: 0.6464
## Max. : 2.1281 Max. : 1.4062 Max. : 2.6548
Hasil Standard Scaler menunjukkan bahwa variabel numerik pada data training telah distandardisasi menggunakan rata-rata dan standar deviasi data training. Hal ini terlihat dari nilai mean sebesar 0 pada ketiga variabel numerik, yaitu Suhu, Kelembapan, dan Kecepatan_Angin. Hasil standardisasi pada enam pengamatan pertama menunjukkan bahwa nilai setiap variabel telah berada pada skala standar. Nilai negatif menunjukkan bahwa pengamatan berada di bawah rata-rata, sedangkan nilai positif menunjukkan posisi di atas rata-rata. Pada Suhu -1,39 menunjukkan bahwa Suhu pengamatan pertama berada di bawah rata-ratanya, sedangkan nilai Kelembapan 0,973 berada di atas rata-ratanya.
## y_train
## 1 2
## 131 463
train_full <- X_train_scale %>%
mutate(Hujan = y_train)
train_full$Hujan <- factor(train_full$Hujan)
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_smote <- bake(
resep_smote_prep,
new_data = NULL
)
table(train_full$Hujan)##
## 1 2
## 131 463
##
## 1 2
## 463 463
## [1] 594 5
## [1] 926 5
## # A tibble: 6 × 5
## Suhu Kelembapan Keadaan_Cuaca Kecepatan_Angin Hujan
## <dbl> <dbl> <dbl> <dbl> <fct>
## 1 -1.39 0.973 5 -0.693 1
## 2 -1.00 0.540 1 -0.693 1
## 3 0.0947 -0.585 1 -0.693 1
## 4 1.19 -1.88 2 -1.03 1
## 5 1.66 -2.40 1 0.646 1
## 6 1.50 -2.32 3 1.32 1
Sebelum SMOTE, data training memiliki 131 data kelas 1 dan 463 data kelas 2, sehingga terdapat ketidakseimbangan kelas. Setelah SMOTE, masing-masing kelas menjadi 463 data, sehingga jumlah data meningkat dari 594 menjadi 926 observasi. Dengan demikian, SMOTE berhasil menyeimbangkan proporsi kedua kelas tanpa mengurangi jumlah data pada kelas mayoritas. Jumlah variabel tetap 5 kolom, sehingga penambahan data tidak mengubah struktur variabel pada data.
Berdasarkan hasil preprocessing data curah hujan, 9 missing value pada Keadaan_Cuaca berhasil ditangani dengan interpolasi, sedangkan 314 missing value pada Kecepatan_Angin ditangani dengan mode imputation. Data kemudian terbagi menjadi 594 data training dan 149 data testing melalui stratify splitting. Pencilan pada Suhu, Kelembapan, dan Kecepatan_Angin ditangani menggunakan capping, kemudian ketiga variabel tersebut distandardisasi dengan Standard Scaler.
Hasil SMOTE menunjukkan bahwa data yang semula terdiri dari 131 kelas 1 dan 463 kelas 2 menjadi 463 data pada masing-masing kelas, sehingga data training menjadi seimbang. Jumlah observasi meningkat dari 594 menjadi 926, dengan jumlah variabel tetap 5 kolom.
Bertolini, M., Mezzogori, D., Neroni, M., & Zammori, F. (2021). Machine learning for industrial applications: A comprehensive literature review. Expert Systems with Applications, 175, 114820. https://doi.org/10.1016/j.eswa.2021.114820
Firman, M. A., Djamalilleil, S. A. F., Zega, W., Efrizoni, L., & Rahmaddeni. (2025). Model klasifikasi IPK mahasiswa menggunakan algoritma decision tree dan random forest berbasis feature engineering. Techno.Com, 24(2), 391–404. https://doi.org/10.62411/tc.v24i2.12384
Herdian, C., Kamila, A., & Budidarma, I. G. A. M. (2024). Studi kasus feature engineering untuk data teks: Perbandingan label encoding dan one-hot encoding pada metode linear regresi. Technologia: Jurnal Ilmiah, 15(1), 93–108. https://doi.org/10.31602/tji.v15i1.13457
Lee, J., Park, D., & Lee, C. (2017). Feature selection algorithm for intrusions detection system using sequential forward search and random forest classifier. KSII Transactions on Internet and Information Systems, 11(10), 5132–5148. https://doi.org/10.3837/tiis.2017.10.024
Rajoub, B. (2020). Characterization of biomedical signals: Feature engineering and extraction. In Biomedical signal processing and artificial intelligence in healthcare (pp. 29–50). Elsevier. https://doi.org/10.1016/B978-0-12-818946-7.00002-0
Fransiska, H. (2026). Modul praktikum machine learning and modern prediction. Universitas Bengkulu.
Naufal, M. R., Erni, & Rodhiyah, M. (2026). Preliminary analysis of machine learning performance and the effect of outliers in daily rainfall classification in Jambi City. Journal of Technomaterial Physics, 8(1), 8–19. https://doi.org/10.32734/jotp.v8i1.24702
Srivani, I., Sridhar, M., Swamy, K. C. T., & Venkata Ratnam, D. (2024). Multi-class classification of ionospheric scintillations using SMOTE-Super Learner ensemble technique. Advances in Space Research, 73(7), 3845–3854. https://doi.org/10.1016/j.asr.2023.09.039