1. Data Simulasi untuk Peramalan Time Series

Berikut adalah kode untuk membuat data simulasi time series dengan pola musiman dan tren:

library(caret)
## Loading required package: ggplot2
## Loading required package: lattice
library(rpart)
library(rpart.plot)
## Warning: package 'rpart.plot' was built under R version 4.4.3
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ lubridate 1.9.3     ✔ tibble    3.2.1
## ✔ purrr     1.0.2     ✔ tidyr     1.3.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ✖ purrr::lift()   masks caret::lift()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(lubridate)
# Set seed untuk reproducibility
set.seed(123)

# Membuat data time series
create_ts_data <- function(n_days = 365*3) {
  # Tanggal dari 1 Jan 2020 hingga 3 tahun ke depan
  dates <- seq(as.Date("2020-01-01"), by = "day", length.out = n_days)
  
  # Komponen tren (meningkat seiring waktu)
  trend <- seq(1, n_days) * 0.05
  
  # Komponen musiman (pola tahunan)
  seasonal <- 15 * sin(2 * pi * seq(1, n_days)/365) + 
              5 * sin(2 * pi * seq(1, n_days)/7)  # pola mingguan
  
  # Noise random
  noise <- rnorm(n_days, 0, 5)
  
  # Gabungkan komponen
  values <- trend + seasonal + noise
  
  # Buat data frame
  ts_data <- data.frame(
    date = dates,
    value = values,
    # Fitur tambahan yang mungkin berguna untuk model
    day_of_week = wday(dates),
    month = month(dates),
    is_weekend = ifelse(wday(dates) %in% c(1, 7), 1, 0),
    day_of_year = yday(dates),
    year = year(dates)
  )
  
  # Buat lag features (nilai pada hari-hari sebelumnya)
  for (i in 1:7) {
    ts_data[paste0("lag_", i)] <- c(rep(NA, i), head(ts_data$value, -i))
  }
  
  # Hapus baris dengan NA
  ts_data <- ts_data[8:nrow(ts_data),]
  
  return(ts_data)
}

# Buat data
ts_data <- create_ts_data()

# Plot data
ggplot(ts_data, aes(x = date, y = value)) +
  geom_line() +
  labs(title = "Data Time Series Simulasi", 
       x = "Tanggal", 
       y = "Nilai") +
  theme_minimal()

# Target variable: nilai pada hari berikutnya
ts_data$target <- c(ts_data$value[-1], NA)
ts_data <- ts_data[-nrow(ts_data),]  # Hapus baris terakhir karena target NA

# Tampilkan beberapa baris data
head(ts_data)
##          date      value day_of_week month is_weekend day_of_year year
## 8  2020-01-08 0.04303282           4     1          0           8 2020
## 9  2020-01-09 4.20500761           5     1          0           9 2020
## 10 2020-01-10 3.01050601           6     1          0          10 2020
## 11 2020-01-11 7.32439094           7     1          1          11 2020
## 12 2020-01-12 0.60099707           1     1          1          12 2020
## 13 2020-01-13 2.07352254           2     1          0          13 2020
##         lag_1      lag_2       lag_3       lag_4       lag_5      lag_6
## 8  4.45770170 6.51269298 -2.68872890 -0.58484034 10.88725527  4.3400763
## 9  0.04303282 4.45770170  6.51269298 -2.68872890 -0.58484034 10.8872553
## 10 4.20500761 0.04303282  4.45770170  6.51269298 -2.68872890 -0.5848403
## 11 3.01050601 4.20500761  0.04303282  4.45770170  6.51269298 -2.6887289
## 12 7.32439094 3.01050601  4.20500761  0.04303282  4.45770170  6.5126930
## 13 0.60099707 7.32439094  3.01050601  4.20500761  0.04303282  4.4577017
##         lag_7    target
## 8   1.4149795 4.2050076
## 9   4.3400763 3.0105060
## 10 10.8872553 7.3243909
## 11 -0.5848403 0.6009971
## 12 -2.6887289 2.0735225
## 13  6.5126930 4.8335051

2. Data Simulasi untuk Klasifikasi

Berikut adalah kode untuk membuat data simulasi klasifikasi dengan 3 kelas:

# Set seed untuk reproducibility
set.seed(456)

# Membuat data klasifikasi
create_classification_data <- function(n_samples = 1000) {
  # Buat fitur
  x1 <- rnorm(n_samples, mean = 0, sd = 1)
  x2 <- rnorm(n_samples, mean = 0, sd = 1)
  x3 <- rnorm(n_samples, mean = 0, sd = 1)
  x4 <- rnorm(n_samples, mean = 0, sd = 1)
  
  # Feature dengan sedikit noise
  x5 <- runif(n_samples, min = -2, max = 2)
  
  # Feature kategoris
  x6 <- sample(c("A", "B", "C"), n_samples, replace = TRUE)
  
  # Buat aturan untuk kelas
  # Kelas 1: x1 > 0.5 dan x2 > 0
  # Kelas 2: x1 < -0.5 dan x2 < 0
  # Kelas 3: lainnya
  class <- rep("Class_3", n_samples)
  class[x1 > 0.5 & x2 > 0] <- "Class_1"
  class[x1 < -0.5 & x2 < 0] <- "Class_2"
  
  # Tambah noise pada kelas (5% data diacak)
  noise_idx <- sample(1:n_samples, round(0.05 * n_samples))
  class[noise_idx] <- sample(c("Class_1", "Class_2", "Class_3"), length(noise_idx), replace = TRUE)
  
  # Buat dataframe
  class_data <- data.frame(
    x1 = x1,
    x2 = x2,
    x3 = x3,
    x4 = x4,
    x5 = x5,
    x6 = x6,
    target = factor(class)
  )
  
  return(class_data)
}

# Buat data
class_data <- create_classification_data()

# Plot data untuk visualisasi
ggplot(class_data, aes(x = x1, y = x2, color = target)) +
  geom_point(alpha = 0.6) +
  labs(title = "Data Klasifikasi Simulasi", 
       x = "Fitur x1", 
       y = "Fitur x2") +
  theme_minimal()

3. Penerapan Decision Tree untuk Klasifikasi

library(MLmetrics)
## Warning: package 'MLmetrics' was built under R version 4.4.3
## 
## Attaching package: 'MLmetrics'
## The following objects are masked from 'package:caret':
## 
##     MAE, RMSE
## The following object is masked from 'package:base':
## 
##     Recall
# Split data klasifikasi
set.seed(789)
train_idx <- createDataPartition(class_data$target, p = 0.7, list = FALSE)
class_train <- class_data[train_idx, ]
class_test <- class_data[-train_idx, ]

# Definisi training control
class_ctrl <- trainControl(
  method = "cv",
  number = 10,
  verboseIter = TRUE,
  classProbs = TRUE,
  summaryFunction = multiClassSummary  # untuk metrik multiclass
)

# Train model decision tree
class_dt_model <- train(
  target ~ .,
  data = class_train,
  method = "rpart",
  trControl = class_ctrl,
  tuneLength = 10,
  metric = "Accuracy"
)
## + Fold01: cp=0 
## - Fold01: cp=0 
## + Fold02: cp=0 
## - Fold02: cp=0 
## + Fold03: cp=0 
## - Fold03: cp=0 
## + Fold04: cp=0 
## - Fold04: cp=0 
## + Fold05: cp=0 
## - Fold05: cp=0 
## + Fold06: cp=0 
## - Fold06: cp=0 
## + Fold07: cp=0 
## - Fold07: cp=0 
## + Fold08: cp=0 
## - Fold08: cp=0 
## + Fold09: cp=0 
## - Fold09: cp=0 
## + Fold10: cp=0 
## - Fold10: cp=0
## Warning in nominalTrainWorkflow(x = x, y = y, wts = weights, info = trainInfo,
## : There were missing values in resampled performance measures.
## Aggregating results
## Selecting tuning parameters
## Fitting cp = 0.203 on full training set
# Plot hasil tuning
plot(class_dt_model)

# Visualisasi pohon keputusan
rpart.plot(class_dt_model$finalModel, 
           extra = 101, 
           box.palette = "auto", 
           shadow.col = "gray")

# Prediksi pada data testing
class_predictions <- predict(class_dt_model, newdata = class_test)
class_probs <- predict(class_dt_model, newdata = class_test, type = "prob")

# Evaluasi model
conf_matrix <- confusionMatrix(class_predictions, class_test$target)
print(conf_matrix)
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction Class_1 Class_2 Class_3
##    Class_1      48       0       1
##    Class_2       0      43       0
##    Class_3       1       4     202
## 
## Overall Statistics
##                                           
##                Accuracy : 0.9799          
##                  95% CI : (0.9568, 0.9926)
##     No Information Rate : 0.6789          
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.9582          
##                                           
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: Class_1 Class: Class_2 Class: Class_3
## Sensitivity                  0.9796         0.9149         0.9951
## Specificity                  0.9960         1.0000         0.9479
## Pos Pred Value               0.9796         1.0000         0.9758
## Neg Pred Value               0.9960         0.9844         0.9891
## Prevalence                   0.1639         0.1572         0.6789
## Detection Rate               0.1605         0.1438         0.6756
## Detection Prevalence         0.1639         0.1438         0.6923
## Balanced Accuracy            0.9878         0.9574         0.9715
# Plot confusion matrix
library(viridis)
## Loading required package: viridisLite
conf_data <- as.data.frame(conf_matrix$table)
conf_data$Prediction <- factor(conf_data$Prediction, levels = rev(levels(conf_data$Prediction)))

ggplot(conf_data, aes(x = Reference, y = Prediction, fill = Freq)) +
  geom_tile() +
  geom_text(aes(label = Freq), color = "white", size = 4) +
  scale_fill_viridis() +
  labs(title = "Confusion Matrix", x = "Actual", y = "Predicted") +
  theme_minimal()

# Visualisasi batas keputusan
# Buat grid untuk prediksi
x1_range <- seq(min(class_data$x1) - 0.5, max(class_data$x1) + 0.5, length.out = 100)
x2_range <- seq(min(class_data$x2) - 0.5, max(class_data$x2) + 0.5, length.out = 100)
grid <- expand.grid(x1 = x1_range, x2 = x2_range)

# Tetapkan nilai untuk fitur lain (ambil nilai rata-rata/modus)
grid$x3 <- mean(class_data$x3)
grid$x4 <- mean(class_data$x4)
grid$x5 <- mean(class_data$x5)
grid$x6 <- names(which.max(table(class_data$x6)))

# Prediksi pada grid
grid_pred <- predict(class_dt_model, newdata = grid)

# Plot batas keputusan
ggplot() +
  geom_tile(data = grid, aes(x = x1, y = x2, fill = grid_pred), alpha = 0.3) +
  geom_point(data = class_test, aes(x = x1, y = x2, color = target), size = 2) +
  labs(title = "Decision Tree: Batas Keputusan",
       x = "Fitur x1",
       y = "Fitur x2",
       fill = "Predicted Class",
       color = "Actual Class") +
  theme_minimal()

# Tampilkan variabel importance
var_imp <- varImp(class_dt_model)
plot(var_imp, main = "Variable Importance")

4. Interpretasi Hasil

Untuk Time Series:

  • Decision tree menggunakan lag features (data sebelumnya) untuk memprediksi nilai berikutnya.

  • Pohon keputusan memungkinkan kita melihat pola musiman (seperti hari dalam minggu atau bulan dalam tahun) yang memengaruhi target.

  • Performa model dapat dievaluasi dengan RMSE (root mean squared error), MAE (mean absolute error), dan R-squared.

Untuk Klasifikasi:

  • Decision tree menentukan fitur mana yang paling penting untuk memisahkan kelas. B

  • atas keputusan cenderung berbentuk kotak karena decision tree membuat split ortogonal.

  • Confusion matrix menunjukkan bagaimana model memprediksi masing-masing kelas.

  • Variable importance plot menunjukkan fitur mana yang paling berpengaruh dalam model.

5. Kelebihan dan Kekurangan Decision Tree

Kelebihan:

  • Mudah diinterpretasi - menunjukkan aturan keputusan yang jelas.

  • Dapat menangani variabel numerik dan kategorikal.

  • Tidak memerlukan scaling data.

  • Menangani dengan baik nilai yang hilang.

Kekurangan:

  • Cenderung overfitting pada data training.

  • Tidak stabil - perubahan kecil pada data dapat menghasilkan pohon yang sangat berbeda.

  • Performa seringkali tidak sebaik algoritma yang lebih kompleks.

  • Batas keputusan yang kaku (kotak).

Untuk mengatasi kekurangan ini, teknik seperti pruning (pemangkasan), setting maximum depth, atau menggunakan ensemble methods seperti Random Forest dapat diterapkan.

Dengan CARET, implementasi dan perbandingan algoritma klasik seperti Decision Tree, KNN, dan Naive Bayes menjadi jauh lebih mudah dan terstandarisasi, memungkinkan para data scientist untuk fokus pada interpretasi dan optimasi model.