BAB I PENDAHULUAN

1.1 Latar Belakang

Penentuan gaji (salary) pemain olahraga profesional dipengaruhi oleh banyak faktor, antara lain performa pemain pada musim berjalan, akumulasi prestasi sepanjang karier, dan lamanya pengalaman bermain. Pada olahraga baseball, performa pemain tercatat secara rinci dalam bentuk statistik seperti jumlah hits, home runs, runs batted in (RBI), dan walks. Ketersediaan data statistik tersebut memungkinkan hubungan antara performa pemain dan besarnya gaji dipelajari secara kuantitatif.

Decision tree merupakan salah satu metode pembelajaran mesin yang populer karena hasilnya mudah diinterpretasi. Metode ini membagi data secara rekursif berdasarkan variabel prediktor sehingga membentuk pohon keputusan berupa aturan “jika-maka”. Salah satu algoritma yang paling dikenal adalah CART (Classification and Regression Trees) yang dapat digunakan untuk dua jenis permasalahan: klasifikasi apabila variabel respons berupa kategori, dan regresi apabila variabel respons berupa numerik.

Pada praktikum ini digunakan dataset Hitters dari package ISLR untuk memprediksi Salary pemain baseball menggunakan Decision Tree (Regression Tree) dengan algoritma CART. Rangkaian analisis mencakup penanganan missing value, pembagian data latih dan data uji, pembentukan dan visualisasi pohon, analisis variable importance, evaluasi model menggunakan Mean Squared Error (MSE), penentuan nilai complexity parameter (CP) terbaik, pruning, dan evaluasi ulang model hasil pruning.

1.2 Rumusan Masalah

  1. Bagaimana konsep dasar Decision Tree untuk klasifikasi menggunakan metode CART (Classification and Regression Tree)?
  2. Bagaimana membangun model Classification Tree menggunakan algoritma CART?

1.3 Tujuan Penelitian

  1. Menjelaskan konsep dasar Decision Tree untuk klasifikasi menggunakan metode CART (Classification and Regression Tree).
  2. Membangun model Classification Tree menggunakan algoritma CART.

1.3 Batasan Masalah

Batasan masalah pada praktikum ini adalah gunakan dataset Hitters dari package ISLR untuk memprediksi Salary menggunakan Decision Tree (Regression Tree). Lakukan pengecekan dan penanganan missing value menggunakan na.omit(), kemudian bagi data menjadi training dan testing. Selanjutnya, bangun dan visualisasikan tree, analisis variable importance, lakukan prediksi dan evaluasi menggunakan MSE, tentukan CP terbaik, lakukan pruning, dan evaluasi kembali model menggunakan MSE.

BAB II TINJAUAN PUSTAKA

2.1 Decision Tree dan Metode CART

Decision tree adalah metode pembelajaran terawasi (supervised learning) yang membagi ruang data menjadi subkelompok yang semakin homogen melalui serangkaian aturan pemisahan (split) berdasarkan variabel prediktor. Metode CART (Classification and Regression Trees) diperkenalkan oleh Breiman et al. (1984) dan menghasilkan pohon biner, yaitu setiap simpul keputusan hanya bercabang menjadi dua simpul anak. Struktur pohon terdiri atas root node (simpul akar), internal node (simpul keputusan), dan leaf node (simpul daun) yang memuat hasil prediksi.

Pada Classification Tree, variabel respons berupa kategori dan pemisahan dipilih agar simpul anak menjadi sehomogen mungkin. Ukuran ketidakmurnian (impurity) yang umum digunakan CART adalah indeks Gini:

\[ Gini(t) = 1 - \sum_{k=1}^{K} p(k \mid t)^2 \]

dengan \(p(k \mid t)\) adalah proporsi kelas ke-\(k\) pada simpul \(t\). Nilai Gini sama dengan 0 berarti simpul sepenuhnya murni. Pemisahan terbaik adalah yang menghasilkan penurunan impuritas terbesar:

\[ \Delta Gini = Gini(t) - \left( \frac{n_L}{n_t} Gini(t_L) + \frac{n_R}{n_t} Gini(t_R) \right) \]

dengan \(t_L\) dan \(t_R\) masing-masing adalah simpul anak kiri dan kanan. Prediksi pada simpul daun adalah kelas mayoritas pada simpul tersebut.

2.2 Regression Tree

Pada Regression Tree, variabel respons berupa numerik. Ruang prediktor dibagi menjadi \(J\) wilayah \(R_1, R_2, \ldots, R_J\), dan prediksi untuk setiap observasi di wilayah \(R_j\) adalah rata-rata respons pada data latih di wilayah tersebut (\(\hat{y}_{R_j}\)). Pemisahan dipilih untuk meminimalkan jumlah kuadrat galat (residual sum of squares, RSS):

\[ RSS = \sum_{j=1}^{J} \sum_{i \in R_j} \left( y_i - \hat{y}_{R_j} \right)^2 \]

Pembentukan pohon dilakukan secara top-down dan greedy, yaitu pada setiap langkah dipilih pemisahan terbaik saat itu tanpa mempertimbangkan pemisahan di langkah berikutnya (James et al., 2013). Pada rpart, regresi dijalankan dengan method = "anova".

2.3 Variable Importance, Complexity Parameter, dan Pruning

Variable importance pada rpart dihitung dari total penurunan ukuran kesalahan (impuritas) yang disumbangkan suatu variabel, baik sebagai pemisah utama (primary split) maupun pemisah pengganti (surrogate split). Semakin besar nilainya, semakin besar kontribusi variabel tersebut dalam membentuk pohon (Therneau & Atkinson, 2023).

Pohon yang dibiarkan tumbuh terlalu besar cenderung mengalami overfitting. CART mengatasinya dengan pemangkasan berbasis cost-complexity, yaitu meminimalkan:

\[ R_{\alpha}(T) = R(T) + \alpha \, |T| \]

dengan \(R(T)\) adalah galat pohon \(T\), \(|T|\) adalah jumlah simpul daun, dan \(\alpha\) adalah parameter penalti kompleksitas. Pada rpart, penalti ini dinyatakan sebagai complexity parameter (CP), yaitu sebuah pemisahan hanya dipertahankan apabila mampu menurunkan galat relatif minimal sebesar CP. Nilai CP terbaik umumnya dipilih dari CP yang menghasilkan galat validasi silang (xerror) terkecil, atau dengan aturan 1-SE yang memilih pohon paling sederhana dengan xerror masih berada dalam satu standar error dari nilai minimum. Proses memangkas cabang pohon berdasarkan CP tersebut disebut pruning.

2.4 Mean Squared Error (MSE)

Kinerja model regresi dievaluasi menggunakan Mean Squared Error (MSE), yaitu rata-rata kuadrat selisih antara nilai aktual dan nilai prediksi:

\[ MSE = \frac{1}{n} \sum_{i=1}^{n} \left( y_i - \hat{y}_i \right)^2 \]

Semakin kecil nilai MSE, semakin dekat prediksi model dengan nilai aktual. Akar dari MSE disebut RMSE (Root Mean Squared Error) yang memiliki satuan sama dengan variabel respons sehingga lebih mudah diinterpretasi. MSE pada data uji digunakan untuk menilai kemampuan model menggeneralisasi data baru, sedangkan MSE pada data latih hanya menunjukkan kesesuaian model terhadap data yang digunakan untuk membangunnya.

BAB III METODE PENELITIAN

3.1 Sumber Data

Data yang digunakan adalah dataset Hitters dari package ISLR di R. Dataset ini berisi statistik pemain baseball Major League Baseball pada musim 1986 dan 1987 (James et al., 2013). Data dimuat dengan perintah data(Hitters).

3.2 Variabel Penelitian

Variabel respons (Y) adalah Salary, sedangkan variabel prediktor (X) berjumlah 19 variabel sebagai berikut.

Variabel Peran Keterangan
Salary Y Gaji tahunan pemain pada awal musim 1987 (dalam ribuan dolar)
AtBat X Jumlah kesempatan memukul (at bat) pada 1986
Hits X Jumlah pukulan sukses (hits) pada 1986
HmRun X Jumlah home run pada 1986
Runs X Jumlah runs pada 1986
RBI X Jumlah runs batted in pada 1986
Walks X Jumlah walks pada 1986
Years X Lama bermain di liga utama (tahun)
CAtBat X Jumlah at bat sepanjang karier
CHits X Jumlah hits sepanjang karier
CHmRun X Jumlah home run sepanjang karier
CRuns X Jumlah runs sepanjang karier
CRBI X Jumlah RBI sepanjang karier
CWalks X Jumlah walks sepanjang karier
League X Liga pemain pada akhir 1986 (A atau N)
Division X Divisi pemain pada akhir 1986 (E atau W)
PutOuts X Jumlah put outs pada 1986
Assists X Jumlah assists pada 1986
Errors X Jumlah errors pada 1986
NewLeague X Liga pemain pada awal 1987 (A atau N)

3.3 Langkah-langkah Analisis

  1. Memuat data dan menyajikan statistik deskriptif.
  2. Memeriksa missing value dan menanganinya menggunakan na.omit().
  3. Membagi data menjadi data latih (70%) dan data uji (30%) secara acak.
  4. Membangun model regression tree dengan rpart (method = "anova") pada data latih dan memvisualisasikannya dengan rpart.plot.
  5. Menganalisis variable importance.
  6. Memprediksi data uji dan mengevaluasi model awal menggunakan MSE.
  7. Menentukan CP terbaik berdasarkan xerror minimum dari validasi silang 10 lipatan.
  8. Melakukan pruning menggunakan CP terbaik.
  9. Mengevaluasi kembali model hasil pruning menggunakan MSE dan membandingkannya dengan model awal.

BAB IV HASIL DAN PEMBAHASAN

4.1 Library dan Eksplorasi Data

library(ISLR)
library(rpart)
library(rpart.plot)
library(dplyr)
library(ggplot2)
library(knitr)

data(Hitters)
dim(Hitters)
## [1] 322  20
head(Hitters)
##                   AtBat Hits HmRun Runs RBI Walks Years CAtBat CHits CHmRun
## -Andy Allanson      293   66     1   30  29    14     1    293    66      1
## -Alan Ashby         315   81     7   24  38    39    14   3449   835     69
## -Alvin Davis        479  130    18   66  72    76     3   1624   457     63
## -Andre Dawson       496  141    20   65  78    37    11   5628  1575    225
## -Andres Galarraga   321   87    10   39  42    30     2    396   101     12
## -Alfredo Griffin    594  169     4   74  51    35    11   4408  1133     19
##                   CRuns CRBI CWalks League Division PutOuts Assists Errors
## -Andy Allanson       30   29     14      A        E     446      33     20
## -Alan Ashby         321  414    375      N        W     632      43     10
## -Alvin Davis        224  266    263      A        W     880      82     14
## -Andre Dawson       828  838    354      N        E     200      11      3
## -Andres Galarraga    48   46     33      N        E     805      40      4
## -Alfredo Griffin    501  336    194      A        W     282     421     25
##                   Salary NewLeague
## -Andy Allanson        NA         A
## -Alan Ashby        475.0         N
## -Alvin Davis       480.0         A
## -Andre Dawson      500.0         N
## -Andres Galarraga   91.5         N
## -Alfredo Griffin   750.0         A
str(Hitters)
## 'data.frame':    322 obs. of  20 variables:
##  $ AtBat    : int  293 315 479 496 321 594 185 298 323 401 ...
##  $ Hits     : int  66 81 130 141 87 169 37 73 81 92 ...
##  $ HmRun    : int  1 7 18 20 10 4 1 0 6 17 ...
##  $ Runs     : int  30 24 66 65 39 74 23 24 26 49 ...
##  $ RBI      : int  29 38 72 78 42 51 8 24 32 66 ...
##  $ Walks    : int  14 39 76 37 30 35 21 7 8 65 ...
##  $ Years    : int  1 14 3 11 2 11 2 3 2 13 ...
##  $ CAtBat   : int  293 3449 1624 5628 396 4408 214 509 341 5206 ...
##  $ CHits    : int  66 835 457 1575 101 1133 42 108 86 1332 ...
##  $ CHmRun   : int  1 69 63 225 12 19 1 0 6 253 ...
##  $ CRuns    : int  30 321 224 828 48 501 30 41 32 784 ...
##  $ CRBI     : int  29 414 266 838 46 336 9 37 34 890 ...
##  $ CWalks   : int  14 375 263 354 33 194 24 12 8 866 ...
##  $ League   : Factor w/ 2 levels "A","N": 1 2 1 2 2 1 2 1 2 1 ...
##  $ Division : Factor w/ 2 levels "E","W": 1 2 2 1 1 2 1 2 2 1 ...
##  $ PutOuts  : int  446 632 880 200 805 282 76 121 143 0 ...
##  $ Assists  : int  33 43 82 11 40 421 127 283 290 0 ...
##  $ Errors   : int  20 10 14 3 4 25 7 9 19 0 ...
##  $ Salary   : num  NA 475 480 500 91.5 750 70 100 75 1100 ...
##  $ NewLeague: Factor w/ 2 levels "A","N": 1 2 1 2 2 1 1 1 2 1 ...

Dataset Hitters terdiri atas 322 observasi dan 20 variabel: satu variabel respons (Salary) dan 19 variabel prediktor, terdiri atas 16 variabel numerik dan 3 variabel kategorik (League, Division, NewLeague). Statistik deskriptif berikut meringkas nilai minimum, kuartil, rata-rata, dan maksimum setiap variabel serta jumlah missing value (NA's).

summary(Hitters)
##      AtBat            Hits         HmRun            Runs       
##  Min.   : 16.0   Min.   :  1   Min.   : 0.00   Min.   :  0.00  
##  1st Qu.:255.2   1st Qu.: 64   1st Qu.: 4.00   1st Qu.: 30.25  
##  Median :379.5   Median : 96   Median : 8.00   Median : 48.00  
##  Mean   :380.9   Mean   :101   Mean   :10.77   Mean   : 50.91  
##  3rd Qu.:512.0   3rd Qu.:137   3rd Qu.:16.00   3rd Qu.: 69.00  
##  Max.   :687.0   Max.   :238   Max.   :40.00   Max.   :130.00  
##                                                                
##       RBI             Walks            Years            CAtBat       
##  Min.   :  0.00   Min.   :  0.00   Min.   : 1.000   Min.   :   19.0  
##  1st Qu.: 28.00   1st Qu.: 22.00   1st Qu.: 4.000   1st Qu.:  816.8  
##  Median : 44.00   Median : 35.00   Median : 6.000   Median : 1928.0  
##  Mean   : 48.03   Mean   : 38.74   Mean   : 7.444   Mean   : 2648.7  
##  3rd Qu.: 64.75   3rd Qu.: 53.00   3rd Qu.:11.000   3rd Qu.: 3924.2  
##  Max.   :121.00   Max.   :105.00   Max.   :24.000   Max.   :14053.0  
##                                                                      
##      CHits            CHmRun           CRuns             CRBI        
##  Min.   :   4.0   Min.   :  0.00   Min.   :   1.0   Min.   :   0.00  
##  1st Qu.: 209.0   1st Qu.: 14.00   1st Qu.: 100.2   1st Qu.:  88.75  
##  Median : 508.0   Median : 37.50   Median : 247.0   Median : 220.50  
##  Mean   : 717.6   Mean   : 69.49   Mean   : 358.8   Mean   : 330.12  
##  3rd Qu.:1059.2   3rd Qu.: 90.00   3rd Qu.: 526.2   3rd Qu.: 426.25  
##  Max.   :4256.0   Max.   :548.00   Max.   :2165.0   Max.   :1659.00  
##                                                                      
##      CWalks        League  Division    PutOuts          Assists     
##  Min.   :   0.00   A:175   E:157    Min.   :   0.0   Min.   :  0.0  
##  1st Qu.:  67.25   N:147   W:165    1st Qu.: 109.2   1st Qu.:  7.0  
##  Median : 170.50                    Median : 212.0   Median : 39.5  
##  Mean   : 260.24                    Mean   : 288.9   Mean   :106.9  
##  3rd Qu.: 339.25                    3rd Qu.: 325.0   3rd Qu.:166.0  
##  Max.   :1566.00                    Max.   :1378.0   Max.   :492.0  
##                                                                     
##      Errors          Salary       NewLeague
##  Min.   : 0.00   Min.   :  67.5   A:176    
##  1st Qu.: 3.00   1st Qu.: 190.0   N:146    
##  Median : 6.00   Median : 425.0            
##  Mean   : 8.04   Mean   : 535.9            
##  3rd Qu.:11.00   3rd Qu.: 750.0            
##  Max.   :32.00   Max.   :2460.0            
##                  NAs    :59
ggplot(Hitters, aes(x = Salary)) +
  geom_histogram(bins = 30, fill = "#008080", color = "black", na.rm = TRUE) +
  labs(x = "Salary (ribu dolar)", y = "Frekuensi", title = "Distribusi Salary") +
  theme_minimal()
Gambar 1. Distribusi Salary pemain

Gambar 1. Distribusi Salary pemain

Distribusi Salary pada Gambar 1 cenderung menjulur ke kanan, yaitu sebagian besar pemain bergaji relatif rendah hingga menengah dan hanya sedikit pemain bergaji sangat tinggi. Hal ini perlu diperhatikan karena MSE sangat sensitif terhadap nilai ekstrem. Namun, decision tree tidak mengasumsikan distribusi tertentu pada respons sehingga transformasi tidak diperlukan pada praktikum ini.

4.2 Handling Missing Value (na.omit)

# Cek missing value
colSums(is.na(Hitters))
##     AtBat      Hits     HmRun      Runs       RBI     Walks     Years    CAtBat 
##         0         0         0         0         0         0         0         0 
##     CHits    CHmRun     CRuns      CRBI    CWalks    League  Division   PutOuts 
##         0         0         0         0         0         0         0         0 
##   Assists    Errors    Salary NewLeague 
##         0         0        59         0
cat("Total missing value :", sum(is.na(Hitters)), "\n")
## Total missing value : 59
cat("Baris yang memuat NA:", sum(!complete.cases(Hitters)), "\n")
## Baris yang memuat NA: 59
# Penanganan dengan na.omit()
df <- na.omit(Hitters)

cat("\nJumlah baris sebelum na.omit :", nrow(Hitters), "\n")
## 
## Jumlah baris sebelum na.omit : 322
cat("Jumlah baris sesudah na.omit :", nrow(df), "\n")
## Jumlah baris sesudah na.omit : 263
colSums(is.na(df))
##     AtBat      Hits     HmRun      Runs       RBI     Walks     Years    CAtBat 
##         0         0         0         0         0         0         0         0 
##     CHits    CHmRun     CRuns      CRBI    CWalks    League  Division   PutOuts 
##         0         0         0         0         0         0         0         0 
##   Assists    Errors    Salary NewLeague 
##         0         0         0         0

Pemeriksaan menunjukkan missing value hanya terdapat pada variabel respons Salary, sebanyak 59 observasi (18.32% dari seluruh data). Fungsi na.omit() menghapus seluruh baris yang memuat missing value sehingga tersisa 263 observasi lengkap. Penghapusan baris dipilih karena Salary adalah variabel yang diprediksi, sehingga observasi tanpa nilai Salary tidak dapat digunakan untuk melatih maupun mengevaluasi model.

4.3 Splitting Data

set.seed(123)
idx   <- sample(seq_len(nrow(df)), size = round(0.7 * nrow(df)))
train <- df[idx, ]
test  <- df[-idx, ]

cat("Jumlah data latih :", nrow(train), "\n")
## Jumlah data latih : 184
cat("Jumlah data uji   :", nrow(test), "\n\n")
## Jumlah data uji   : 79
summary(train$Salary)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    67.5   188.8   400.0   545.5   750.0  2460.0
summary(test$Salary)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    70.0   195.0   487.5   513.7   762.5  1975.0

Data dibagi menjadi data latih (70%, 184 observasi) dan data uji (30%, 79 observasi) secara acak menggunakan sample(). Penggunaan set.seed(123) menjamin hasil pembagian dapat direproduksi. Ringkasan Salary pada kedua bagian digunakan untuk memastikan sebaran respons pada data latih dan data uji tidak berbeda terlalu jauh.

4.4 Membangun dan Memvisualisasikan Regression Tree

Model awal dibangun dengan rpart menggunakan method = "anova" untuk kasus regresi. Nilai CP yang kecil (cp = 0.001) dan minsplit = 10 digunakan agar pohon tumbuh cukup besar sehingga tahap pemilihan CP terbaik dan pruning memiliki ruang untuk menyederhanakan pohon.

set.seed(123)
tree_full <- rpart(
  Salary ~ .,
  data    = train,
  method  = "anova",
  control = rpart.control(cp = 0.001, minsplit = 10, xval = 10)
)

print(tree_full)
## n= 184 
## 
## node), split, n, deviance, yval
##       * denotes terminal node
## 
##   1) root 184 43317190.00  545.4638  
##     2) CRBI< 321.5 110  7657626.00  300.0258  
##       4) CAtBat< 1260 65  4188730.00  188.5077  
##         8) AtBat>=135 62   369400.80  158.0753  
##          16) CRuns< 98.5 38    48470.19  110.5395 *
##          17) CRuns>=98.5 24    99108.12  233.3403 *
##         9) AtBat< 135 3  2575225.00  817.4443 *
##       5) CAtBat>=1260 45  1492909.00  461.1074  
##        10) CHits< 447.5 20   338416.70  372.2000  
##          20) Walks< 45 12   171510.50  319.5000  
##            40) AtBat>=477 3    11400.00  170.0000 *
##            41) AtBat< 477 9    70709.50  369.3333 *
##          21) Walks>=45 8    83587.50  451.2500 *
##        11) CHits>=447.5 25   869929.70  532.2334  
##          22) Years>=9.5 4    20863.28  312.0835 *
##          23) Years< 9.5 21   618276.10  574.1667  
##            46) Errors>=6.5 9   313588.00  492.4074 *
##            47) Errors< 6.5 12   199406.10  635.4861  
##              94) HmRun>=13.5 6    89180.21  562.9167 *
##              95) HmRun< 13.5 6    47030.09  708.0555 *
##     3) CRBI>=321.5 74 19183150.00  910.3041  
##       6) Walks< 61 47  4149361.00  672.1200  
##        12) AtBat< 362 20  1460003.00  496.6250  
##          24) Walks< 42.5 15   348597.50  401.5000  
##            48) Years>=16.5 4    11650.00  270.0000 *
##            49) Years< 16.5 11   242626.10  449.3182  
##              98) Hits< 72 5    35950.00  340.0000 *
##              99) Hits>=72 6    97130.21  540.4167 *
##          25) Walks>=42.5 5   568480.00  782.0000 *
##        13) AtBat>=362 27  1617113.00  802.1164  
##          26) Errors>=15.5 8   311087.90  632.7679 *
##          27) Errors< 15.5 19   979991.40  873.4210  
##            54) Assists< 10.5 6    41509.15  667.7777 *
##            55) Assists>=10.5 13   567638.70  968.3333  
##             110) Years>=9.5 8   373288.80  890.8334 *
##             111) Years< 9.5 5    69420.09 1092.3330 *
##       7) Walks>=61 27  7725913.00 1324.9210  
##        14) CRuns< 798.5 16  2245915.00 1117.7080  
##          28) Walks< 66.5 4   272829.70  710.6250 *
##          29) Walks>=66.5 12  1089262.00 1253.4030  
##            58) Assists< 199 9   346559.80 1127.8700 *
##            59) Assists>=199 3   175400.00 1630.0000 *
##        15) CRuns>=798.5 11  3793743.00 1626.3210  
##          30) Hits< 143.5 5  1217607.00 1157.1140 *
##          31) Hits>=143.5 6   558048.30 2017.3270 *
rpart.plot(
  tree_full,
  type = 4, extra = 101, fallen.leaves = TRUE,
  box.palette = "GnBu",
  main = "Regression Tree Sebelum Pruning"
)
Gambar 2. Visualisasi regression tree sebelum pruning

Gambar 2. Visualisasi regression tree sebelum pruning

n_leaf <- function(model) sum(model$frame$var == "<leaf>")
cat("Jumlah simpul daun model awal:", n_leaf(tree_full), "\n")
## Jumlah simpul daun model awal: 23

Pada Gambar 2, setiap simpul menampilkan nilai prediksi Salary (rata-rata respons pada simpul), jumlah observasi (n), dan persentasenya terhadap data latih. Pohon dibaca dari simpul akar di bagian atas: observasi yang memenuhi kondisi pada simpul diarahkan ke cabang kiri (“yes”), sedangkan yang tidak memenuhi diarahkan ke cabang kanan (“no”) hingga mencapai simpul daun yang memberikan prediksi akhir. Semakin gelap warna simpul, semakin tinggi nilai prediksi Salary. Model awal memiliki 23 simpul daun dengan 22 pemisahan.

4.5 Variable Importance

vi <- data.frame(
  Variabel   = names(tree_full$variable.importance),
  Importance = as.numeric(tree_full$variable.importance)
) %>%
  mutate(Persen = round(Importance / sum(Importance) * 100, 2)) %>%
  arrange(desc(Importance))

kable(vi, digits = 2, caption = "Tabel 1. Nilai variable importance")
Tabel 1. Nilai variable importance
Variabel Importance Persen
CRBI 19881180.15 13.07
CAtBat 19082839.68 12.54
CRuns 18895761.93 12.42
CWalks 18689360.37 12.29
CHits 18447843.43 12.13
CHmRun 14266199.09 9.38
Walks 10450555.42 6.87
Runs 7529755.05 4.95
Hits 5278355.77 3.47
AtBat 4610669.29 3.03
Years 4337941.20 2.85
RBI 4307817.65 2.83
HmRun 3547767.79 2.33
Assists 1247289.25 0.82
Errors 1104484.96 0.73
PutOuts 400713.43 0.26
Division 42130.56 0.03
ggplot(vi, aes(x = reorder(Variabel, Importance), y = Importance)) +
  geom_col(fill = "#008080", color = "black") +
  coord_flip() +
  labs(x = "Variabel", y = "Importance", title = "Variable Importance") +
  theme_minimal()
Gambar 3. Variable importance model awal

Gambar 3. Variable importance model awal

Variabel dengan kontribusi terbesar dalam memprediksi Salary adalah CRBI (13.07%), diikuti CAtBat (12.54%) dan CRuns (12.42%). Variabel-variabel tersebut paling banyak menurunkan galat dan paling menentukan pembagian pemain ke dalam kelompok gaji yang berbeda. Perlu diperhatikan bahwa banyak variabel statistik karier saling berkorelasi tinggi (misalnya CHits, CRuns, dan CRBI), sehingga nilai importance dapat terbagi di antara variabel yang membawa informasi serupa. Variabel dengan importance rendah memberikan kontribusi kecil terhadap model.

4.6 Prediksi dan Evaluasi Model Sebelum Pruning (MSE)

mse <- function(aktual, prediksi) mean((aktual - prediksi)^2)

pred_train_full <- predict(tree_full, newdata = train)
pred_test_full  <- predict(tree_full, newdata = test)

mse_train_full <- mse(train$Salary, pred_train_full)
mse_test_full  <- mse(test$Salary,  pred_test_full)

cat("MSE data latih (sebelum pruning) :", round(mse_train_full, 2), "\n")
## MSE data latih (sebelum pruning) : 40424.58
cat("MSE data uji   (sebelum pruning) :", round(mse_test_full, 2), "\n")
## MSE data uji   (sebelum pruning) : 107293.4
cat("RMSE data uji  (sebelum pruning) :", round(sqrt(mse_test_full), 2), "\n")
## RMSE data uji  (sebelum pruning) : 327.56

Model awal menghasilkan MSE data latih sebesar 4.042458^{4} dan MSE data uji sebesar 1.0729343^{5} (RMSE data uji 327.56 ribu dolar). MSE data uji lebih besar daripada MSE data latih, yang mengindikasikan model cenderung lebih cocok pada data latih dibandingkan data baru (indikasi overfitting), sehingga pemangkasan pohon perlu dipertimbangkan.

ggplot(data.frame(Aktual = test$Salary, Prediksi = pred_test_full),
       aes(x = Aktual, y = Prediksi)) +
  geom_point(color = "#008080", size = 2, alpha = 0.8) +
  geom_abline(slope = 1, intercept = 0, linetype = "dashed") +
  labs(x = "Salary aktual", y = "Salary prediksi",
       title = "Aktual vs Prediksi (Sebelum Pruning)") +
  theme_minimal()
Gambar 4. Salary aktual vs prediksi pada data uji (sebelum pruning)

Gambar 4. Salary aktual vs prediksi pada data uji (sebelum pruning)

Semakin dekat titik-titik pada Gambar 4 ke garis putus-putus (garis 45 derajat), semakin akurat prediksi model. Karena prediksi regression tree berupa nilai rata-rata pada simpul daun, prediksi hanya dapat bernilai sejumlah nilai diskrit (sebanyak simpul daun) sehingga titik-titik tampak tersusun dalam kolom-kolom vertikal.

4.7 Menentukan CP Terbaik

printcp(tree_full)
## 
## Regression tree:
## rpart(formula = Salary ~ ., data = train, method = "anova", control = rpart.control(cp = 0.001, 
##     minsplit = 10, xval = 10))
## 
## Variables actually used in tree construction:
##  [1] Assists AtBat   CAtBat  CHits   CRBI    CRuns   Errors  Hits    HmRun  
## [10] Walks   Years  
## 
## Root node error: 43317187/184 = 235419
## 
## n= 184 
## 
##           CP nsplit rel error  xerror    xstd
## 1  0.3803665      0   1.00000 1.01491 0.16117
## 2  0.1687062      1   0.61963 0.75458 0.12999
## 3  0.0456167      2   0.45093 0.58021 0.12376
## 4  0.0427583      3   0.40531 0.61175 0.13372
## 5  0.0287208      5   0.31979 0.59721 0.13441
## 6  0.0247533      6   0.29107 0.63075 0.13692
## 7  0.0204035      7   0.26632 0.64359 0.13888
## 8  0.0130965      8   0.24592 0.65686 0.13815
## 9  0.0125337      9   0.23282 0.65355 0.13800
## 10 0.0080439     10   0.22029 0.66934 0.13400
## 11 0.0065693     12   0.20420 0.65920 0.13289
## 12 0.0053279     13   0.19763 0.65516 0.13184
## 13 0.0051209     14   0.19230 0.66020 0.13478
## 14 0.0028841     15   0.18718 0.67428 0.14053
## 15 0.0024305     16   0.18430 0.67507 0.13946
## 16 0.0023532     17   0.18187 0.68108 0.13944
## 17 0.0019937     19   0.17716 0.69235 0.13915
## 18 0.0014589     21   0.17317 0.69203 0.13927
## 19 0.0010000     22   0.17171 0.69297 0.13927
plotcp(tree_full)
Gambar 5. Plot nilai CP terhadap cross-validation error

Gambar 5. Plot nilai CP terhadap cross-validation error

cp_tab  <- as.data.frame(tree_full$cptable)
best_cp <- cp_tab$CP[which.min(cp_tab$xerror)]

# Sebagai pembanding: aturan 1-SE
row_min <- which.min(cp_tab$xerror)
thr     <- cp_tab$xerror[row_min] + cp_tab$xstd[row_min]
cp_1se  <- cp_tab$CP[which(cp_tab$xerror <= thr)[1]]

cat("CP terbaik (xerror minimum) :", best_cp, "\n")
## CP terbaik (xerror minimum) : 0.04561669
cat("CP menurut aturan 1-SE      :", cp_1se, "\n")
## CP menurut aturan 1-SE      : 0.04561669

Tabel CP memuat nilai CP, jumlah pemisahan (nsplit), galat relatif pada data latih (rel error), galat validasi silang (xerror), dan standar errornya (xstd). Seiring bertambahnya pemisahan, rel error terus menurun, tetapi xerror pada akhirnya berhenti menurun atau justru naik karena pohon mulai menyesuaikan noise. Berdasarkan kriteria xerror minimum, nilai CP terbaik adalah 0.04562. Sebagai pembanding, aturan 1-SE menghasilkan CP sebesar 0.04562 yang cenderung memberikan pohon lebih sederhana. Dalam praktikum ini digunakan CP dengan xerror minimum.

4.8 Pruning

tree_pruned <- prune(tree_full, cp = best_cp)
print(tree_pruned)
## n= 184 
## 
## node), split, n, deviance, yval
##       * denotes terminal node
## 
## 1) root 184 43317190  545.4638  
##   2) CRBI< 321.5 110  7657626  300.0258 *
##   3) CRBI>=321.5 74 19183150  910.3041  
##     6) Walks< 61 47  4149361  672.1200 *
##     7) Walks>=61 27  7725913 1324.9210 *
rpart.plot(
  tree_pruned,
  type = 4, extra = 101, fallen.leaves = TRUE,
  box.palette = "GnBu",
  main = "Regression Tree Setelah Pruning"
)
Gambar 6. Visualisasi regression tree setelah pruning

Gambar 6. Visualisasi regression tree setelah pruning

Setelah pruning dengan CP = 0.04562, jumlah simpul daun berubah dari 23 menjadi 3, dan jumlah pemisahan dari 22 menjadi 2. Pohon yang lebih ringkas lebih mudah diinterpretasi dan berpotensi lebih baik dalam menggeneralisasi data baru karena risiko overfitting berkurang.

4.9 Evaluasi Model Setelah Pruning (MSE)

pred_train_pruned <- predict(tree_pruned, newdata = train)
pred_test_pruned  <- predict(tree_pruned, newdata = test)

mse_train_pruned <- mse(train$Salary, pred_train_pruned)
mse_test_pruned  <- mse(test$Salary,  pred_test_pruned)

cat("MSE data latih (setelah pruning) :", round(mse_train_pruned, 2), "\n")
## MSE data latih (setelah pruning) : 106157.1
cat("MSE data uji   (setelah pruning) :", round(mse_test_pruned, 2), "\n")
## MSE data uji   (setelah pruning) : 113822.2
cat("RMSE data uji  (setelah pruning) :", round(sqrt(mse_test_pruned), 2), "\n")
## RMSE data uji  (setelah pruning) : 337.38
ggplot(data.frame(Aktual = test$Salary, Prediksi = pred_test_pruned),
       aes(x = Aktual, y = Prediksi)) +
  geom_point(color = "#E69F00", size = 2, alpha = 0.8) +
  geom_abline(slope = 1, intercept = 0, linetype = "dashed") +
  labs(x = "Salary aktual", y = "Salary prediksi",
       title = "Aktual vs Prediksi (Setelah Pruning)") +
  theme_minimal()
Gambar 7. Salary aktual vs prediksi pada data uji (setelah pruning)

Gambar 7. Salary aktual vs prediksi pada data uji (setelah pruning)

Perbandingan Kinerja Model

r2 <- function(aktual, prediksi) 1 - sum((aktual - prediksi)^2) / sum((aktual - mean(aktual))^2)

perbandingan <- data.frame(
  Model       = c("Sebelum Pruning", "Setelah Pruning"),
  Jumlah_Daun = c(n_leaf(tree_full), n_leaf(tree_pruned)),
  MSE_Latih   = c(mse_train_full, mse_train_pruned),
  MSE_Uji     = c(mse_test_full,  mse_test_pruned),
  RMSE_Uji    = c(sqrt(mse_test_full), sqrt(mse_test_pruned)),
  R2_Uji      = c(r2(test$Salary, pred_test_full), r2(test$Salary, pred_test_pruned))
)

kable(perbandingan, digits = 4, caption = "Tabel 2. Perbandingan kinerja model")
Tabel 2. Perbandingan kinerja model
Model Jumlah_Daun MSE_Latih MSE_Uji RMSE_Uji R2_Uji
Sebelum Pruning 23 40424.58 107293.4 327.5568 0.1478
Setelah Pruning 3 106157.07 113822.2 337.3754 0.0959

MSE data uji naik dari 107293.43 menjadi 113822.19 setelah pruning. Pada data uji ini pohon yang lebih besar memprediksi sedikit lebih baik, tetapi model hasil pruning jauh lebih sederhana sehingga lebih mudah diinterpretasi; selisih ini dapat dipengaruhi pembagian data latih dan uji yang acak.

BAB V KESIMPULAN

5.1 Kesimpulan

  1. Decision Tree dengan metode CART (Classification and Regression Trees) membagi data secara rekursif dan biner berdasarkan variabel prediktor. Pada kasus klasifikasi, pemisahan dipilih untuk menurunkan impuritas (misalnya indeks Gini) dan prediksi simpul daun berupa kelas mayoritas. Pada kasus regresi, pemisahan dipilih untuk meminimalkan RSS dan prediksi simpul daun berupa rata-rata respons. Pohon kemudian dipangkas menggunakan cost-complexity pruning melalui nilai CP untuk mencegah overfitting.
  2. Model pohon keputusan dibangun menggunakan algoritma CART dengan fungsi rpart pada data latih. Pada praktikum ini algoritma CART diterapkan untuk kasus regresi (Regression Tree) guna memprediksi Salary pada dataset Hitters setelah 59 observasi yang memuat missing value dihapus dengan na.omit(). Data dibagi menjadi 184 data latih dan 79 data uji.
  3. Variabel yang paling berpengaruh dalam memprediksi Salary adalah CRBI, CAtBat, dan CRuns.
  4. Model awal dengan 23 simpul daun menghasilkan MSE data uji sebesar 1.0729343^{5}. Nilai CP terbaik berdasarkan xerror minimum adalah 0.04562. Setelah pruning, pohon memiliki 3 simpul daun dengan MSE data uji sebesar 1.1382219^{5}.

DAFTAR PUSTAKA

Breiman, L., Friedman, J. H., Olshen, R. A., & Stone, C. J. (1984). Classification and Regression Trees. Wadsworth.

Hastie, T., Tibshirani, R., & Friedman, J. (2009). The Elements of Statistical Learning: Data Mining, Inference, and Prediction (2nd ed.). Springer.

James, G., Witten, D., Hastie, T., & Tibshirani, R. (2013). An Introduction to Statistical Learning: with Applications in R. Springer.

Therneau, T., & Atkinson, B. (2023). rpart: Recursive Partitioning and Regression Trees (R package). https://CRAN.R-project.org/package=rpart