1. Install dan memanggil package

packages <- c(
  "tidyverse",
  "readr",
  "caret",
  "randomForest",
  "gbm",
  "e1071",
  "scales"
)

for (p in packages) {
  if (!require(p, character.only = TRUE)) {
    install.packages(p)
    library(p, character.only = TRUE)
  }
}
## Loading required package: tidyverse
## Warning: package 'tidyverse' was built under R version 4.5.3
## Warning: package 'ggplot2' was built under R version 4.5.3
## Warning: package 'tidyr' was built under R version 4.5.3
## Warning: package 'purrr' was built under R version 4.5.3
## Warning: package 'dplyr' was built under R version 4.5.3
## Warning: package 'forcats' was built under R version 4.5.1
## Warning: package 'lubridate' was built under R version 4.5.3
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.2.1     ✔ readr     2.1.5
## ✔ forcats   1.0.1     ✔ stringr   1.5.1
## ✔ ggplot2   4.0.3     ✔ tibble    3.2.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
## Loading required package: caret
## Warning: package 'caret' was built under R version 4.5.3
## Loading required package: lattice
## 
## Attaching package: 'caret'
## 
## The following object is masked from 'package:purrr':
## 
##     lift
## 
## Loading required package: randomForest
## Warning: package 'randomForest' was built under R version 4.5.3
## randomForest 4.7-1.2
## Type rfNews() to see new features/changes/bug fixes.
## 
## Attaching package: 'randomForest'
## 
## The following object is masked from 'package:dplyr':
## 
##     combine
## 
## The following object is masked from 'package:ggplot2':
## 
##     margin
## 
## Loading required package: gbm
## Warning: package 'gbm' was built under R version 4.5.3
## Loaded gbm 2.3.1
## This version of gbm is no longer under development. Consider transitioning to gbm3, https://github.com/gbm-developers/gbm3
## Loading required package: e1071
## Warning: package 'e1071' was built under R version 4.5.1
## 
## Attaching package: 'e1071'
## 
## The following object is masked from 'package:ggplot2':
## 
##     element
## 
## Loading required package: scales
## 
## Attaching package: 'scales'
## 
## The following object is masked from 'package:purrr':
## 
##     discard
## 
## The following object is masked from 'package:readr':
## 
##     col_factor
library(tidyverse)
library(readr)
library(caret)
library(randomForest)
library(gbm)
library(e1071)
library(scales)

set.seed(123)

2. Import dataset

datatugasmpml <- read_delim(
  "C:/Users/Hype G12/Downloads/datatugasmpml.csv",
  delim = ";",
  show_col_types = FALSE
)

View(datatugasmpml)

dim(datatugasmpml)
## [1] 2392   15
names(datatugasmpml)
##  [1] "StudentID"         "Age"               "Gender"           
##  [4] "Ethnicity"         "ParentalEducation" "StudyTimeWeekly"  
##  [7] "Absences"          "Tutoring"          "ParentalSupport"  
## [10] "Extracurricular"   "Sports"            "Music"            
## [13] "Volunteering"      "GPA"               "GradeClass"
str(datatugasmpml)
## spc_tbl_ [2,392 × 15] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
##  $ StudentID        : num [1:2392] 1001 1002 1003 1004 1005 ...
##  $ Age              : num [1:2392] 17 18 15 17 17 18 15 15 17 16 ...
##  $ Gender           : num [1:2392] 1 0 0 1 1 0 0 1 0 1 ...
##  $ Ethnicity        : num [1:2392] 0 0 2 0 0 0 1 1 0 0 ...
##  $ ParentalEducation: num [1:2392] 2 1 3 3 2 1 1 4 0 1 ...
##  $ StudyTimeWeekly  : chr [1:2392] "19.833.722.807.854.700" "1.540.875.605.584.670" "421.056.976.881.226" "10.028.829.473.958.200" ...
##  $ Absences         : num [1:2392] 7 0 26 14 17 0 10 22 1 0 ...
##  $ Tutoring         : num [1:2392] 1 0 0 0 1 0 0 1 0 0 ...
##  $ ParentalSupport  : num [1:2392] 2 1 2 3 3 1 3 1 2 3 ...
##  $ Extracurricular  : num [1:2392] 0 0 0 1 0 1 0 1 0 1 ...
##  $ Sports           : num [1:2392] 0 0 0 0 0 0 1 0 1 0 ...
##  $ Music            : num [1:2392] 1 0 0 0 0 0 0 0 0 0 ...
##  $ Volunteering     : num [1:2392] 0 0 0 0 0 0 0 0 1 0 ...
##  $ GPA              : chr [1:2392] "2.929.195.591.667.680" "3.042.914.833.436.370" "0.1126022544661815" "20.542.181.397.029.400" ...
##  $ GradeClass       : num [1:2392] 2 1 4 3 4 1 2 4 2 0 ...
##  - attr(*, "spec")=
##   .. cols(
##   ..   StudentID = col_double(),
##   ..   Age = col_double(),
##   ..   Gender = col_double(),
##   ..   Ethnicity = col_double(),
##   ..   ParentalEducation = col_double(),
##   ..   StudyTimeWeekly = col_character(),
##   ..   Absences = col_double(),
##   ..   Tutoring = col_double(),
##   ..   ParentalSupport = col_double(),
##   ..   Extracurricular = col_double(),
##   ..   Sports = col_double(),
##   ..   Music = col_double(),
##   ..   Volunteering = col_double(),
##   ..   GPA = col_character(),
##   ..   GradeClass = col_double()
##   .. )
##  - attr(*, "problems")=<externalptr>
if (ncol(datatugasmpml) != 15) {
  stop("Jumlah kolom tidak sesuai. Periksa kembali delimiter dataset.")
}

3. Pengecekan dan persiapan data

datatugasmpml <- distinct(datatugasmpml)

variabel_kategori <- c(
  "Gender",
  "Ethnicity",
  "ParentalEducation",
  "Tutoring",
  "ParentalSupport",
  "Extracurricular",
  "Sports",
  "Music",
  "Volunteering"
)

datatugasmpml[variabel_kategori] <- lapply(
  datatugasmpml[variabel_kategori],
  as.factor
)

datatugasmpml$GradeClass <- factor(
  datatugasmpml$GradeClass,
  levels = 0:4
)

colSums(is.na(datatugasmpml))
##         StudentID               Age            Gender         Ethnicity 
##                 0                 0                 0                 0 
## ParentalEducation   StudyTimeWeekly          Absences          Tutoring 
##                 0                 0                 0                 0 
##   ParentalSupport   Extracurricular            Sports             Music 
##                 0                 0                 0                 0 
##      Volunteering               GPA        GradeClass 
##                 0                 0                 0
str(datatugasmpml)
## tibble [2,392 × 15] (S3: tbl_df/tbl/data.frame)
##  $ StudentID        : num [1:2392] 1001 1002 1003 1004 1005 ...
##  $ Age              : num [1:2392] 17 18 15 17 17 18 15 15 17 16 ...
##  $ Gender           : Factor w/ 2 levels "0","1": 2 1 1 2 2 1 1 2 1 2 ...
##  $ Ethnicity        : Factor w/ 4 levels "0","1","2","3": 1 1 3 1 1 1 2 2 1 1 ...
##  $ ParentalEducation: Factor w/ 5 levels "0","1","2","3",..: 3 2 4 4 3 2 2 5 1 2 ...
##  $ StudyTimeWeekly  : chr [1:2392] "19.833.722.807.854.700" "1.540.875.605.584.670" "421.056.976.881.226" "10.028.829.473.958.200" ...
##  $ Absences         : num [1:2392] 7 0 26 14 17 0 10 22 1 0 ...
##  $ Tutoring         : Factor w/ 2 levels "0","1": 2 1 1 1 2 1 1 2 1 1 ...
##  $ ParentalSupport  : Factor w/ 5 levels "0","1","2","3",..: 3 2 3 4 4 2 4 2 3 4 ...
##  $ Extracurricular  : Factor w/ 2 levels "0","1": 1 1 1 2 1 2 1 2 1 2 ...
##  $ Sports           : Factor w/ 2 levels "0","1": 1 1 1 1 1 1 2 1 2 1 ...
##  $ Music            : Factor w/ 2 levels "0","1": 2 1 1 1 1 1 1 1 1 1 ...
##  $ Volunteering     : Factor w/ 2 levels "0","1": 1 1 1 1 1 1 1 1 2 1 ...
##  $ GPA              : chr [1:2392] "2.929.195.591.667.680" "3.042.914.833.436.370" "0.1126022544661815" "20.542.181.397.029.400" ...
##  $ GradeClass       : Factor w/ 5 levels "0","1","2","3",..: 3 2 5 4 5 2 3 5 3 1 ...
dim(datatugasmpml)
## [1] 2392   15

4. Visualisasi distribusi setiap variabel

tema_grafik <- theme_minimal(base_size = 12) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5),
    axis.title = element_text(face = "bold"),
    axis.text = element_text(color = "black"),
    panel.grid.minor = element_blank(),
    legend.position = "bottom"
  )

variabel_numerik <- names(datatugasmpml)[
  sapply(datatugasmpml, is.numeric)
]

variabel_numerik <- setdiff(
  variabel_numerik,
  "StudentID"
)

for (var in variabel_numerik) {

  p <- ggplot(
    datatugasmpml,
    aes(x = .data[[var]])
  ) +
    geom_histogram(
      fill = "skyblue",
      color = "white",
      bins = 25
    ) +
    labs(
      title = paste("Distribusi", var),
      x = var,
      y = "Frekuensi"
    ) +
    tema_grafik

  print(p)
}

for (var in variabel_kategori) {

  p <- ggplot(
    datatugasmpml,
    aes(x = .data[[var]])
  ) +
    geom_bar(
      fill = "steelblue",
      color = "white"
    ) +
    coord_flip() +
    labs(
      title = paste("Distribusi", var),
      x = var,
      y = "Frekuensi"
    ) +
    tema_grafik

  print(p)
}

ggplot(
  datatugasmpml,
  aes(x = GradeClass, fill = GradeClass)
) +
  geom_bar(color = "white") +
  scale_fill_brewer(palette = "Set2") +
  labs(
    title = "Distribusi GradeClass",
    x = "GradeClass",
    y = "Frekuensi"
  ) +
  tema_grafik

5. Visualisasi hubungan variabel dengan GradeClass

for (var in variabel_numerik) {

  p <- ggplot(
    datatugasmpml,
    aes(
      x = GradeClass,
      y = .data[[var]],
      fill = GradeClass
    )
  ) +
    geom_boxplot(alpha = 0.8) +
    scale_fill_brewer(palette = "Set2") +
    labs(
      title = paste(var, "berdasarkan GradeClass"),
      x = "GradeClass",
      y = var
    ) +
    tema_grafik

  print(p)
}

for (var in variabel_kategori) {

  p <- ggplot(
    datatugasmpml,
    aes(
      x = .data[[var]],
      fill = GradeClass
    )
  ) +
    geom_bar(position = "fill", color = "white") +
    scale_fill_brewer(palette = "Set2") +
    scale_y_continuous(
      labels = percent_format()
    ) +
    labs(
      title = paste("Hubungan", var, "dengan GradeClass"),
      x = var,
      y = "Proporsi",
      fill = "GradeClass"
    ) +
    coord_flip() +
    tema_grafik

  print(p)
}

6. Statistik deskriptif

summary(datatugasmpml)
##    StudentID         Age        Gender   Ethnicity ParentalEducation
##  Min.   :1001   Min.   :15.00   0:1170   0:1207    0:243            
##  1st Qu.:1599   1st Qu.:15.00   1:1222   1: 493    1:728            
##  Median :2196   Median :16.00            2: 470    2:934            
##  Mean   :2196   Mean   :16.47            3: 222    3:367            
##  3rd Qu.:2794   3rd Qu.:17.00                      4:120            
##  Max.   :3392   Max.   :18.00                                       
##  StudyTimeWeekly       Absences     Tutoring ParentalSupport Extracurricular
##  Length:2392        Min.   : 0.00   0:1671   0:212           0:1475         
##  Class :character   1st Qu.: 7.00   1: 721   1:489           1: 917         
##  Mode  :character   Median :15.00            2:740                          
##                     Mean   :14.54            3:697                          
##                     3rd Qu.:22.00            4:254                          
##                     Max.   :29.00                                           
##  Sports   Music    Volunteering     GPA            GradeClass
##  0:1666   0:1921   0:2016       Length:2392        0: 107    
##  1: 726   1: 471   1: 376       Class :character   1: 269    
##                                 Mode  :character   2: 391    
##                                                    3: 414    
##                                                    4:1211    
## 
data_numerik <- datatugasmpml %>%
  select(where(is.numeric)) %>%
  select(-any_of("StudentID"))

summary(data_numerik)
##       Age           Absences    
##  Min.   :15.00   Min.   : 0.00  
##  1st Qu.:15.00   1st Qu.: 7.00  
##  Median :16.00   Median :15.00  
##  Mean   :16.47   Mean   :14.54  
##  3rd Qu.:17.00   3rd Qu.:22.00  
##  Max.   :18.00   Max.   :29.00
for (var in variabel_kategori) {
  cat("\nFrekuensi variabel:", var, "\n")
  print(table(datatugasmpml[[var]]))
}
## 
## Frekuensi variabel: Gender 
## 
##    0    1 
## 1170 1222 
## 
## Frekuensi variabel: Ethnicity 
## 
##    0    1    2    3 
## 1207  493  470  222 
## 
## Frekuensi variabel: ParentalEducation 
## 
##   0   1   2   3   4 
## 243 728 934 367 120 
## 
## Frekuensi variabel: Tutoring 
## 
##    0    1 
## 1671  721 
## 
## Frekuensi variabel: ParentalSupport 
## 
##   0   1   2   3   4 
## 212 489 740 697 254 
## 
## Frekuensi variabel: Extracurricular 
## 
##    0    1 
## 1475  917 
## 
## Frekuensi variabel: Sports 
## 
##    0    1 
## 1666  726 
## 
## Frekuensi variabel: Music 
## 
##    0    1 
## 1921  471 
## 
## Frekuensi variabel: Volunteering 
## 
##    0    1 
## 2016  376
cat("\nDistribusi GradeClass:\n")
## 
## Distribusi GradeClass:
print(table(datatugasmpml$GradeClass))
## 
##    0    1    2    3    4 
##  107  269  391  414 1211

7. Persiapan data untuk pemodelan

variabel_prediktor <- c(
  "Age",
  "Gender",
  "Ethnicity",
  "ParentalEducation",
  "Absences",
  "Tutoring",
  "ParentalSupport",
  "Extracurricular",
  "Sports",
  "Music",
  "Volunteering"
)

data_model <- datatugasmpml %>%
  select(all_of(variabel_prediktor), GradeClass) %>%
  na.omit()

data_model <- droplevels(data_model)

dim(data_model)
## [1] 2392   12
str(data_model)
## tibble [2,392 × 12] (S3: tbl_df/tbl/data.frame)
##  $ Age              : num [1:2392] 17 18 15 17 17 18 15 15 17 16 ...
##  $ Gender           : Factor w/ 2 levels "0","1": 2 1 1 2 2 1 1 2 1 2 ...
##  $ Ethnicity        : Factor w/ 4 levels "0","1","2","3": 1 1 3 1 1 1 2 2 1 1 ...
##  $ ParentalEducation: Factor w/ 5 levels "0","1","2","3",..: 3 2 4 4 3 2 2 5 1 2 ...
##  $ Absences         : num [1:2392] 7 0 26 14 17 0 10 22 1 0 ...
##  $ Tutoring         : Factor w/ 2 levels "0","1": 2 1 1 1 2 1 1 2 1 1 ...
##  $ ParentalSupport  : Factor w/ 5 levels "0","1","2","3",..: 3 2 3 4 4 2 4 2 3 4 ...
##  $ Extracurricular  : Factor w/ 2 levels "0","1": 1 1 1 2 1 2 1 2 1 2 ...
##  $ Sports           : Factor w/ 2 levels "0","1": 1 1 1 1 1 1 2 1 2 1 ...
##  $ Music            : Factor w/ 2 levels "0","1": 2 1 1 1 1 1 1 1 1 1 ...
##  $ Volunteering     : Factor w/ 2 levels "0","1": 1 1 1 1 1 1 1 1 2 1 ...
##  $ GradeClass       : Factor w/ 5 levels "0","1","2","3",..: 3 2 5 4 5 2 3 5 3 1 ...
cat("\nDistribusi GradeClass untuk pemodelan:\n")
## 
## Distribusi GradeClass untuk pemodelan:
print(table(data_model$GradeClass))
## 
##    0    1    2    3    4 
##  107  269  391  414 1211

8. Fungsi evaluasi model

evaluasi_model <- function(prediksi, aktual) {

  cm <- confusionMatrix(
    prediksi,
    aktual
  )

  tab <- cm$table

  precision <- diag(tab) / rowSums(tab)
  recall <- diag(tab) / colSums(tab)

  precision[is.na(precision)] <- 0
  recall[is.na(recall)] <- 0

  f1 <- ifelse(
    (precision + recall) == 0,
    0,
    2 * precision * recall / (precision + recall)
  )

  hasil <- data.frame(
    Accuracy = as.numeric(cm$overall["Accuracy"]),
    Macro_F1 = mean(f1)
  )

  return(hasil)
}

9. Pemodelan Random Forest, Gradient Boosting, dan SVM

proporsi_training <- c(0.50, 0.75, 0.80, 0.90)

hasil_semua <- data.frame()

kontrol_cv <- trainControl(
  method = "cv",
  number = 3,
  allowParallel = FALSE
)

for (proporsi in proporsi_training) {

  cat("\n====================================\n")
  cat("Proporsi Training:", proporsi * 100, "%\n")
  cat("====================================\n")

  set.seed(123)

  indeks <- createDataPartition(
    data_model$GradeClass,
    p = proporsi,
    list = FALSE
  )

  data_train <- data_model[indeks, ]
  data_test <- data_model[-indeks, ]

  # Random Forest

  grid_rf <- expand.grid(
    mtry = c(2, 3, 4)
  )

  model_rf <- train(
    GradeClass ~ .,
    data = data_train,
    method = "rf",
    trControl = kontrol_cv,
    tuneGrid = grid_rf,
    ntree = 150,
    importance = TRUE
  )

  prediksi_rf <- predict(
    model_rf,
    newdata = data_test
  )

  evaluasi_rf <- evaluasi_model(
    prediksi_rf,
    data_test$GradeClass
  )

  hasil_semua <- rbind(
    hasil_semua,
    data.frame(
      Proporsi_Training = proporsi,
      Model = "Random Forest",
      Accuracy = evaluasi_rf$Accuracy,
      Macro_F1 = evaluasi_rf$Macro_F1
    )
  )

  # Gradient Boosting

  grid_gbm <- expand.grid(
    n.trees = c(100, 150),
    interaction.depth = c(1, 2),
    shrinkage = 0.05,
    n.minobsinnode = 10
  )

  model_gbm <- train(
    GradeClass ~ .,
    data = data_train,
    method = "gbm",
    trControl = kontrol_cv,
    tuneGrid = grid_gbm,
    verbose = FALSE
  )

  prediksi_gbm <- predict(
    model_gbm,
    newdata = data_test
  )

  evaluasi_gbm <- evaluasi_model(
    prediksi_gbm,
    data_test$GradeClass
  )

  hasil_semua <- rbind(
    hasil_semua,
    data.frame(
      Proporsi_Training = proporsi,
      Model = "Gradient Boosting",
      Accuracy = evaluasi_gbm$Accuracy,
      Macro_F1 = evaluasi_gbm$Macro_F1
    )
  )

  # Support Vector Machine

  metode_svm <- c(
    "svmLinear",
    "svmPoly",
    "svmRadial"
  )

  for (metode in metode_svm) {

    model_svm <- train(
      GradeClass ~ .,
      data = data_train,
      method = metode,
      trControl = kontrol_cv,
      preProcess = c("center", "scale"),
      tuneLength = 2
    )

    prediksi_svm <- predict(
      model_svm,
      newdata = data_test
    )

    evaluasi_svm <- evaluasi_model(
      prediksi_svm,
      data_test$GradeClass
    )

    hasil_semua <- rbind(
      hasil_semua,
      data.frame(
        Proporsi_Training = proporsi,
        Model = paste("SVM", metode),
        Accuracy = evaluasi_svm$Accuracy,
        Macro_F1 = evaluasi_svm$Macro_F1
      )
    )
  }
}
## 
## ====================================
## Proporsi Training: 50 %
## ====================================
## 
## ====================================
## Proporsi Training: 75 %
## ====================================
## 
## ====================================
## Proporsi Training: 80 %
## ====================================
## 
## ====================================
## Proporsi Training: 90 %
## ====================================

10. Hasil perbandingan seluruh model

hasil_semua <- hasil_semua %>%
  arrange(
    desc(Accuracy),
    desc(Macro_F1)
  )

print(hasil_semua)
##    Proporsi_Training             Model  Accuracy  Macro_F1
## 1               0.90     SVM svmLinear 0.7383966 0.5321094
## 2               0.75 Gradient Boosting 0.7294118 0.5846636
## 3               0.90     Random Forest 0.7215190 0.5093856
## 4               0.90 Gradient Boosting 0.7172996 0.5288865
## 5               0.75     Random Forest 0.7126050 0.5448835
## 6               0.75     SVM svmLinear 0.7126050 0.4953555
## 7               0.50     SVM svmLinear 0.7018425 0.4960243
## 8               0.80 Gradient Boosting 0.6953782 0.5341483
## 9               0.50 Gradient Boosting 0.6901173 0.5503415
## 10              0.80     SVM svmLinear 0.6890756 0.4698011
## 11              0.80     Random Forest 0.6806723 0.4927170
## 12              0.50     Random Forest 0.6608040 0.4793023
## 13              0.90       SVM svmPoly 0.6540084 0.3486229
## 14              0.75       SVM svmPoly 0.6537815 0.3468657
## 15              0.75     SVM svmRadial 0.6504202 0.3600123
## 16              0.90     SVM svmRadial 0.6497890 0.3563081
## 17              0.80       SVM svmPoly 0.6386555 0.3314731
## 18              0.80     SVM svmRadial 0.6323529 0.3330138
## 19              0.50       SVM svmPoly 0.6314908 0.3218107
## 20              0.50     SVM svmRadial 0.6180905 0.3163835

11. Menentukan model terbaik

model_terbaik <- hasil_semua %>%
  arrange(
    desc(Accuracy),
    desc(Macro_F1)
  ) %>%
  slice(1)

cat("\nModel terbaik:\n")
## 
## Model terbaik:
print(model_terbaik)
##   Proporsi_Training         Model  Accuracy  Macro_F1
## 1               0.9 SVM svmLinear 0.7383966 0.5321094

12. Visualisasi perbandingan Accuracy dan Macro F1

# Grafik Accuracy

ggplot(
  hasil_semua,
  aes(
    x = factor(Proporsi_Training),
    y = Accuracy,
    fill = Model
  )
) +
  geom_col(
    position = position_dodge(width = 0.85),
    width = 0.7
  ) +
  geom_text(
    aes(label = percent(Accuracy, accuracy = 0.1)),
    position = position_dodge(width = 0.85),
    vjust = -0.5,
    size = 2.8
  ) +
  scale_y_continuous(
    labels = percent_format(),
    limits = c(0, 1.12),
    breaks = seq(0, 1, 0.2)
  ) +
  labs(
    title = "Perbandingan Accuracy Model",
    x = "Proporsi Data Training",
    y = "Accuracy",
    fill = "Model"
  ) +
  tema_grafik

# Grafik Macro F1

ggplot(
  hasil_semua,
  aes(
    x = factor(Proporsi_Training),
    y = Macro_F1,
    fill = Model
  )
) +
  geom_col(
    position = position_dodge(width = 0.85),
    width = 0.7
  ) +
  geom_text(
    aes(label = percent(Macro_F1, accuracy = 0.1)),
    position = position_dodge(width = 0.85),
    vjust = -0.5,
    size = 2.8
  ) +
  scale_y_continuous(
    labels = percent_format(),
    limits = c(0, 1.12),
    breaks = seq(0, 1, 0.2)
  ) +
  labs(
    title = "Perbandingan Macro F1 Model",
    x = "Proporsi Data Training",
    y = "Macro F1",
    fill = "Model"
  ) +
  tema_grafik

13. Analisis Random Forest

set.seed(123)

indeks_80 <- createDataPartition(
  data_model$GradeClass,
  p = 0.80,
  list = FALSE
)

data_train_80 <- data_model[indeks_80, ]
data_test_80 <- data_model[-indeks_80, ]

model_rf_80 <- randomForest(
  GradeClass ~ .,
  data = data_train_80,
  ntree = 150,
  importance = TRUE
)

prediksi_rf_80 <- predict(
  model_rf_80,
  newdata = data_test_80
)

confusionMatrix(
  prediksi_rf_80,
  data_test_80$GradeClass
)
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   0   1   2   3   4
##          0   4   2   0   0   0
##          1  10  25  10   1   1
##          2   6  19  36  15   0
##          3   0   4  23  42  18
##          4   1   3   9  24 223
## 
## Overall Statistics
##                                           
##                Accuracy : 0.6933          
##                  95% CI : (0.6497, 0.7344)
##     No Information Rate : 0.5084          
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.5304          
##                                           
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: 0 Class: 1 Class: 2 Class: 3 Class: 4
## Sensitivity          0.190476  0.47170  0.46154  0.51220   0.9215
## Specificity          0.995604  0.94799  0.89950  0.88579   0.8419
## Pos Pred Value       0.666667  0.53191  0.47368  0.48276   0.8577
## Neg Pred Value       0.963830  0.93473  0.89500  0.89717   0.9120
## Prevalence           0.044118  0.11134  0.16387  0.17227   0.5084
## Detection Rate       0.008403  0.05252  0.07563  0.08824   0.4685
## Detection Prevalence 0.012605  0.09874  0.15966  0.18277   0.5462
## Balanced Accuracy    0.593040  0.70984  0.68052  0.69899   0.8817
varImpPlot(
  model_rf_80,
  main = "Variable Importance Random Forest"
)

14. Analisis Gradient Boosting

set.seed(123)

model_gbm_raw <- gbm(
  GradeClass ~ .,
  data = data_train_80,
  distribution = "multinomial",
  n.trees = 150,
  interaction.depth = 2,
  shrinkage = 0.05,
  bag.fraction = 0.8,
  n.minobsinnode = 10,
  cv.folds = 3,
  verbose = FALSE
)

jumlah_pohon <- gbm.perf(
  model_gbm_raw,
  method = "cv",
  plot.it = TRUE
)

importance_gbm <- summary(
  model_gbm_raw,
  n.trees = jumlah_pohon,
  plotit = TRUE
)

print(importance_gbm)
##                                 var    rel.inf
## Absences                   Absences 87.9258164
## ParentalSupport     ParentalSupport  5.9277324
## Tutoring                   Tutoring  2.6765965
## Sports                       Sports  0.9406630
## Extracurricular     Extracurricular  0.6823206
## Music                         Music  0.5157937
## Ethnicity                 Ethnicity  0.4455832
## ParentalEducation ParentalEducation  0.3365195
## Age                             Age  0.1965950
## Volunteering           Volunteering  0.1793017
## Gender                       Gender  0.1730781

15. Perbandingan kernel SVM

hasil_svm <- hasil_semua %>%
  filter(grepl("^SVM", Model)) %>%
  group_by(Model) %>%
  slice_max(
    order_by = Accuracy,
    n = 1,
    with_ties = FALSE
  ) %>%
  ungroup() %>%
  mutate(
    Kernel = sub("^SVM svm", "", Model),
    Kernel = tools::toTitleCase(Kernel)
  )

print(hasil_svm)
## # A tibble: 3 × 5
##   Proporsi_Training Model         Accuracy Macro_F1 Kernel
##               <dbl> <chr>            <dbl>    <dbl> <chr> 
## 1              0.9  SVM svmLinear    0.738    0.532 Linear
## 2              0.9  SVM svmPoly      0.654    0.349 Poly  
## 3              0.75 SVM svmRadial    0.650    0.360 Radial
ggplot(
  hasil_svm,
  aes(
    x = reorder(Kernel, Accuracy),
    y = Accuracy,
    fill = Kernel
  )
) +
  geom_col(
    width = 0.65,
    show.legend = FALSE
  ) +
  geom_text(
    aes(label = percent(Accuracy, accuracy = 0.1)),
    hjust = -0.15,
    size = 3.5
  ) +
  coord_flip() +
  scale_y_continuous(
    labels = percent_format(),
    limits = c(0, 1.12)
  ) +
  labs(
    title = "Perbandingan Accuracy Kernel SVM",
    x = "Kernel SVM",
    y = "Accuracy"
  ) +
  tema_grafik