Berikut adalah kode untuk membuat data simulasi time series dengan pola musiman dan tren:
## Loading required package: ggplot2
## Loading required package: lattice
## Warning: package 'rpart.plot' was built under R version 4.4.3
## ── 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
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()
## 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
# 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
## 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")
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.
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.
Mudah diinterpretasi - menunjukkan aturan keputusan yang jelas.
Dapat menangani variabel numerik dan kategorikal.
Tidak memerlukan scaling data.
Menangani dengan baik nilai yang hilang.
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.