BAB I PENDAHULUAN

1.1 Latar Belakang Masalah

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)

1.2 Rumusan Masalah

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

1.3 Tujuan

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

BAB II TINJAUAN PUSTAKA

2.1 Jenis Feature Engineering

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:

2.1.1 Feature Selection

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)

2.1.2 Handling Missing Value

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)

2.1.3 Splitting Data

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).

2.2 Teknik Feature Engineering

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)

BAB III METODE PENELITIAN

3.1 Sumber Data

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.

3.2 Variabel Penelitian

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.

3.3 Langkah-langkah Analisis

Langkah-langkah analisis dalam praktikum ini adalah sebagai berikut:

  1. Mengumpulkan data curah hujan yang akan digunakan dalam proses preprocessing.
  2. Memeriksa kondisi awal data melalui struktur data, statistik deskriptif, dan missing value.
  3. Menangani missing value menggunakan mode imputation pada variabel Kecepatan_Angin dan interpolasi pada variabel Keadaan_Cuaca.
  4. Membagi data menjadi data latih sebesar 80% dan data uji sebesar 20% menggunakan metode stratify splitting berdasarkan variabel Hujan.
  5. Menangani pencilan pada variabel numerik dengan metode capping berdasarkan batas IQR.
  6. Melakukan standardisasi variabel numerik menggunakan Standard Scaler berdasarkan parameter dari data latih.
  7. Menangani ketidakseimbangan data pada data latih menggunakan metode SMOTE.
  8. Menginterpretasikan hasil dari setiap tahapan preprocessing yang telah dilakukan.

BAB IV HASIL DAN PEMBAHASAN

4.1 Library & Statistik Deskriptif

library(zoo) 
## 
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
## 
##     as.Date, as.Date.numeric
library(readxl)
library(tidyverse)
## ── 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
library(rsample)
library(e1071)
## 
## Attaching package: 'e1071'
## 
## The following object is masked from 'package:rsample':
## 
##     permutations
## 
## The following object is masked from 'package:ggplot2':
## 
##     element
library(DescTools)
library(dplyr)
library(ggplot2)
library(gridExtra)
## 
## Attaching package: 'gridExtra'
## 
## The following object is masked from 'package:dplyr':
## 
##     combine
library(recipes)
## 
## Attaching package: 'recipes'
## 
## The following object is masked from 'package:stringr':
## 
##     fixed
## 
## The following object is masked from 'package:stats':
## 
##     step
library(themis)
library(caret)
## 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
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 ...
summary(data)
##      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.

4.2 Mode Imputation

# Cek Missing Value
colSums(is.na(data)) 
##           Hujan            Suhu      Kelembapan   Keadaan_Cuaca Kecepatan_Angin 
##               0               0               0               9             314
colMeans(is.na(data)) 
##           Hujan            Suhu      Kelembapan   Keadaan_Cuaca Kecepatan_Angin 
##      0.00000000      0.00000000      0.00000000      0.01211306      0.42261104
# lihat baris yang kosong di Keadaan_Cuaca 
data %>% filter(is.na(Keadaan_Cuaca)) 
## # 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.

4.3 Interpolasi (Keadaan_Cuaca)

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.

4.4 Stratify Splitting

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
dim(X_test)
## [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.

4.5 Capping Data Numerik

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.

4.6 Standard Scaler

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
summary(X_train_scale[list_num])
##       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.

4.7 Penanganan Imbalance Data dengan SMOTE

table(y_train)
## 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
table(train_smote$Hujan)
## 
##   1   2 
## 463 463
dim(train_full)
## [1] 594   5
dim(train_smote)
## [1] 926   5
head(train_smote)
## # 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.

BAB V KESIMPULAN

5.1 Kesimpulan

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.

DAFTAR PUSTAKA

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