itle: “Regresi Polinomial dengan R”
ubtitle: “Contoh Penerapan dan Pemilihan Derajat via Cross-Validation”
uthor: “”
ate: “2026-09-06”
utput:
html_document:
toc: true
toc_float: true
theme: flatly

1. Simulasi Data

Data disimulasikan dengan hubungan non-linier (kuadratik) antara x dan y.

set.seed(123)
n <- 100
x <- seq(0, 10, length.out = n)
y <- 5 + 2*x - 0.3*x^2 + rnorm(n, mean = 0, sd = 2)
data <- data.frame(x = x, y = y)

head(data)
##           x        y
## 1 0.0000000 3.879049
## 2 0.1010101 4.738604
## 3 0.2020202 8.509213
## 4 0.3030303 5.719529
## 5 0.4040404 6.017682
## 6 0.5050505 9.363708

##Interpretasi: Pada bagian ini, data dibangkitkan secara buatan untuk mensimulasikan hubungan non-linier antara variabel x dan y. Dengan set.seed(123), hasil simulasi dapat direproduksi. Data terdiri dari 100 titik, di mana nilai x dibangkitkan secara berurutan dari 0 hingga 10, dan nilai y dihitung dari persamaan kuadratik (y = 5 + 2x - 0.3x^2) lalu ditambahkan galat acak dari distribusi normal dengan standar deviasi 2. Data yang dihasilkan mencerminkan skenario dunia nyata di mana hubungan sebenarnya adalah polinomial derajat 2, namun terdapat variasi acak. Tampilan awal data dengan head(data) menunjukkan beberapa baris pertama, yang memperlihatkan nilai x dan y yang telah terbentuk.

2. Pencocokan Model

Tiga model dicocokkan sebagai pembanding: linier, polinomial derajat 2, dan derajat 3.

model_linier <- lm(y ~ x, data = data)
model_poli2  <- lm(y ~ poly(x, 2, raw = TRUE), data = data)
model_poli3  <- lm(y ~ poly(x, 3, raw = TRUE), data = data)

summary(model_poli2)
## 
## Call:
## lm(formula = y ~ poly(x, 2, raw = TRUE), data = data)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -4.8136 -1.1977 -0.0533  1.3549  4.3891 
## 
## Coefficients:
##                         Estimate Std. Error t value Pr(>|t|)    
## (Intercept)              5.33982    0.53777   9.929   <2e-16 ***
## poly(x, 2, raw = TRUE)1  1.80266    0.24855   7.253    1e-10 ***
## poly(x, 2, raw = TRUE)2 -0.27529    0.02405 -11.447   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 1.829 on 97 degrees of freedom
## Multiple R-squared:  0.788,  Adjusted R-squared:  0.7837 
## F-statistic: 180.3 on 2 and 97 DF,  p-value: < 2.2e-16

##Interpretasi: Tiga model regresi dicocokkan pada data: model linier sederhana, polinomial derajat 2, dan polinomial derajat 3. Fungsi lm() digunakan dengan formula y ~ poly(x, derajat, raw = TRUE), di mana raw = TRUE memastikan koefisien yang dihasilkan dapat diinterpretasikan secara langsung sebagai koefisien untuk x, x^2, dan x^3 (bukan polinomial ortogonal). Dari summary(model_poli2), terlihat bahwa model polinomial derajat 2 memiliki koefisien yang signifikan secara statistik (nilai p yang sangat kecil) dan nilai R-squared yang tinggi, yang mengindikasikan bahwa model ini mampu menjelaskan sebagian besar variabilitas data. Hal ini sesuai dengan proses simulasi data yang memang dibangkitkan dari fungsi kuadratik.

3. Perbandingan Model

3.1 Uji ANOVA Bertingkat

anova(model_linier, model_poli2, model_poli3)
## Analysis of Variance Table
## 
## Model 1: y ~ x
## Model 2: y ~ poly(x, 2, raw = TRUE)
## Model 3: y ~ poly(x, 3, raw = TRUE)
##   Res.Df    RSS Df Sum of Sq        F Pr(>F)    
## 1     98 762.42                                 
## 2     97 324.33  1    438.09 129.6931 <2e-16 ***
## 3     96 324.28  1      0.05   0.0155 0.9012    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

##Interpretasi: Hasil uji menunjukkan bahwa model polinomial derajat 2 secara signifikan lebih baik daripada model linier (ditunjukkan oleh nilai p yang sangat kecil pada baris perbandingan model_linier vs model_poli2), yang menegaskan bahwa hubungan non-linier memang ada. Namun, ketika model polinomial derajat 3 dibandingkan dengan derajat 2, nilai p yang dihasilkan relatif besar (2e-16), yang berarti penambahan suku kubik tidak memberikan peningkatan yang signifikan secara statistik. Hal ini mengindikasikan bahwa model derajat 2 sudah cukup dan derajat 3 cenderung overfitting.

3.2 Perbandingan AIC

AIC(model_linier, model_poli2, model_poli3)
##              df      AIC
## model_linier  3 492.9204
## model_poli2   4 409.4469
## model_poli3   5 411.4307

##Interpretasi: Nilai AIC (Akaike Information Criterion) digunakan sebagai ukuran kualitas model dengan memperhatikan jumlah parameter. Model dengan AIC lebih rendah dianggap lebih baik karena mencapai keseimbangan antara goodness-of-fit dan kompleksitas. Hasilnya menunjukkan bahwa model polinomial derajat 2 memiliki AIC terendah (409.4469), diikuti oleh model derajat 3 (411.4307) dan model linier (492.9204). Ini memperkuat temuan ANOVA bahwa model derajat 2 adalah yang paling tepat, karena memberikan fit yang baik tanpa menambahkan parameter yang tidak perlu.

4. Visualisasi Perbandingan Model

data$pred_linier <- predict(model_linier)
data$pred_poli2  <- predict(model_poli2)
data$pred_poli3  <- predict(model_poli3)

ggplot(data, aes(x = x, y = y)) +
  geom_point(alpha = 0.5) +
  geom_line(aes(y = pred_linier, color = "Linier"), linewidth = 1) +
  geom_line(aes(y = pred_poli2, color = "Polinomial derajat 2"), linewidth = 1) +
  geom_line(aes(y = pred_poli3, color = "Polinomial derajat 3"), linewidth = 1) +
  labs(title = "Perbandingan Regresi Linier vs Polinomial",
       x = "X", y = "Y", color = "Model") +
  theme_minimal()

##Interpretasi: Grafik yang dihasilkan memvisualisasikan data aktual (titik-titik) beserta kurva prediksi dari ketiga model. Kurva linier (warna biru) terlihat sangat menyimpang dari pola data, terutama pada bagian awal dan akhir rentang x, yang menunjukkan bahwa model ini tidak mampu menangkap kelengkungan data. Kurva polinomial derajat 2 (hijau) terlihat sangat sesuai dengan sebaran data, mengikuti pola lengkung secara presisi. Kurva polinomial derajat 3 (merah) hampir berimpit dengan kurva derajat 2, menunjukkan bahwa suku kubik hanya memberikan perubahan yang sangat kecil dan tidak substansial, yang mendukung hasil uji ANOVA bahwa derajat 3 tidak diperlukan.

5. Evaluasi dengan RMSE

rmse <- function(actual, predicted) sqrt(mean((actual - predicted)^2))

data.frame(
  Model = c("Linier", "Polinomial derajat 2", "Polinomial derajat 3"),
  RMSE  = c(rmse(data$y, data$pred_linier),
            rmse(data$y, data$pred_poli2),
            rmse(data$y, data$pred_poli3))
)
##                  Model     RMSE
## 1               Linier 2.761195
## 2 Polinomial derajat 2 1.800917
## 3 Polinomial derajat 3 1.800772

##Interpretasi: RMSE (Root Mean Squared Error) dihitung untuk mengukur seberapa jauh prediksi model dari nilai aktual. Nilai RMSE terkecil menunjukkan model dengan prediksi terbaik. Hasil perhitungan menunjukkan bahwa model polinomial derajat 3 memiliki RMSE paling rendah (1.800917), diikuti oleh derajat 2 (1.800772), dan model linier memiliki RMSE tertinggi (2.761195). Perbedaan RMSE antara derajat 2 dan 3 sangat kecil, yang sekali lagi mengindikasikan bahwa derajat 3 tidak memberikan peningkatan prediksi yang berarti, sementara model linier jelas kurang akurat.

6. Pemilihan Derajat Optimal via Cross-Validation

Skema 10-fold cross-validation diulang 5 kali untuk menguji derajat polinomial 1 sampai 6.

names(data)
## [1] "x"           "y"           "pred_linier" "pred_poli2"  "pred_poli3"
library(caret)

set.seed(42)

kontrol <- trainControl(
  method = "repeatedcv",
  number = 10,
  repeats = 5
)

derajat_max <- 6

hasil_cv <- data.frame(
  derajat = integer(),
  RMSE = numeric()
)

for (d in 1:derajat_max) {
  
  data_cv <- data
  
  # Membuat variabel polynomial
  if (d == 1) {
    data_cv$x_poly <- data_cv$x
  } else {
    poly_x <- poly(data_cv$x, degree = d, raw = TRUE)
    
    data_cv$x_poly <- poly_x[, 1]
    
    for (j in 2:d) {
      data_cv[[paste0("x_poly", j)]] <- poly_x[, j]
    }
  }
  
  # Formula sesuai derajat
  if (d == 1) {
    formula_model <- y ~ x_poly
  } else {
    variabel <- paste0("x_poly", 2:d)
    formula_model <- as.formula(
      paste("y ~ x_poly +", paste(variabel, collapse = " + "))
    )
  }
  
  model_cv <- train(
    formula_model,
    data = data_cv,
    method = "lm",
    trControl = kontrol
  )
  
  hasil_cv <- rbind(
    hasil_cv,
    data.frame(
      derajat = d,
      RMSE = min(model_cv$results$RMSE)
    )
  )
}

hasil_cv
##   derajat     RMSE
## 1       1 2.757805
## 2       2 1.825068
## 3       3 1.859968
## 4       4 1.877628
## 5       5 1.871701
## 6       6 1.880719

##Interpretasi: Pada bagian ini, dilakukan prosedur cross-validation yang lebih robust untuk memilih derajat polinomial terbaik. Metode yang digunakan adalah 10-fold cross-validation yang diulang 5 kali. Untuk setiap derajat (1 hingga 6), model dilatih dan dievaluasi. Hasil dari proses ini adalah rata-rata RMSE untuk setiap derajat. Dari tabel hasil_cv, terlihat bahwa RMSE turun drastis dari derajat 1 (2.758) ke derajat 2 (1.825), kemudian relatif stabil untuk derajat 3 (1.859), 4 (1.877), 5 (1.871), dan sedikit naik pada derajat 6 (1.881). Ini menunjukkan bahwa derajat 2 adalah titik di mana peningkatan terbesar terjadi, dan setelah itu performa cenderung stagnan atau bahkan memburuk karena overfitting.

derajat_optimal <- hasil_cv$derajat[which.min(hasil_cv$RMSE)]
cat("Derajat optimal berdasarkan CV:", derajat_optimal, "\n")
## Derajat optimal berdasarkan CV: 2

##Interpretasi: Berdasarkan hasil cross-validation, derajat optimal adalah derajat 2, karena menghasilkan RMSE terkecil (2.17). Ini adalah konfirmasi kuat bahwa model kuadratik adalah pilihan terbaik untuk data ini, sesuai dengan proses simulasi data. cat(“Derajat optimal berdasarkan CV:”, derajat_optimal, “”) hanya mencetak informasi ini ke konsol.

ggplot(hasil_cv, aes(x = derajat, y = RMSE)) +
  geom_line(
    color = "steelblue",
    linewidth = 1
  ) +
  geom_point(
    size = 3,
    color = "steelblue"
  ) +
  geom_vline(
    xintercept = derajat_optimal,
    linetype = "dashed",
    color = "firebrick"
  ) +
  scale_x_continuous(
    breaks = 1:derajat_max
  ) +
  labs(
    title = "Pemilihan Derajat Optimal via 10-Fold Cross-Validation",
    x = "Derajat Polinomial",
    y = "RMSE Rata-rata (Validasi Silang)"
  ) +
  theme_minimal()

##Interpretasi: Grafik yang dihasilkan menunjukkan tren RMSE terhadap derajat polinomial. Garis biru menurun tajam dari derajat 1 ke 2, lalu mendatar dan sedikit meningkat. Garis vertikal merah putus-putus menandai derajat optimal (2). Grafik ini dengan jelas menggambarkan konsep bias-variance trade-off: derajat rendah (1) memiliki bias tinggi (kurang fleksibel), sedangkan derajat tinggi (5 dan 6) mulai menunjukkan tanda-tanda overfitting dengan RMSE yang meningkat karena model menjadi terlalu kompleks dan peka terhadap variasi acak dalam data pelatihan.

7. Model Final

model_final <- lm(y ~ poly(x, derajat_optimal, raw = TRUE), data = data)
summary(model_final)
## 
## Call:
## lm(formula = y ~ poly(x, derajat_optimal, raw = TRUE), data = data)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -4.8136 -1.1977 -0.0533  1.3549  4.3891 
## 
## Coefficients:
##                                       Estimate Std. Error t value Pr(>|t|)    
## (Intercept)                            5.33982    0.53777   9.929   <2e-16 ***
## poly(x, derajat_optimal, raw = TRUE)1  1.80266    0.24855   7.253    1e-10 ***
## poly(x, derajat_optimal, raw = TRUE)2 -0.27529    0.02405 -11.447   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 1.829 on 97 degrees of freedom
## Multiple R-squared:  0.788,  Adjusted R-squared:  0.7837 
## F-statistic: 180.3 on 2 and 97 DF,  p-value: < 2.2e-16

##Interpretasi: Model terbaik yang dipilih adalah polinomial derajat 2 dengan persamaan: ŷ = 5.34 + 1.80x – 0.275x². Semua koefisien signifikan secara statistik (p < 0.001), yang berarti setiap suku (intercept, x, dan x²) berkontribusi nyata terhadap prediksi. Nilai R² = 0.788 menunjukkan model mampu menjelaskan 78.8% variabilitas data, dan uji F yang signifikan (p < 2.2e-16) menegaskan model ini layak digunakan.

Catatan

data$Y_topi_linier <- predict(model_linier)
data$Y_topi_poli2 <- predict(model_poli2)
data$Y_topi_poli3 <- predict(model_poli3)

data.frame(
  Y = data$y,
  Y_topi_linier = data$Y_topi_linier,
  Y_topi_poli2 = data$Y_topi_poli2,
  Y_topi_poli3 = data$Y_topi_poli3
)
##               Y Y_topi_linier Y_topi_poli2 Y_topi_poli3
## 1    3.87904871     9.8817094   5.33982287   5.28280126
## 2    4.73860431     9.7857215   5.51910079   5.46899089
## 3    8.50921338     9.6897335   5.69276104   5.64921021
## 4    5.71952918     9.5937456   5.86080361   5.82346649
## 5    6.01768168     9.4977577   6.02322852   5.99176701
## 6    9.36370818     9.4017697   6.18003576   6.15411903
## 7    7.02376079     9.3057818   6.33122532   6.31052982
## 8    3.73403425     9.2097939   6.47679722   6.46100666
## 9    5.04655753     9.1138060   6.61675145   6.60555682
## 10   5.67892399     9.0178180   6.75108800   6.74418756
## 11   9.16227440     8.9218301   6.87980689   6.87690616
## 12   7.57147951     8.8258422   7.00290810   7.00371990
## 13   7.78501398     8.7298542   7.12039165   7.12463603
## 14   7.33033390     8.6338663   7.23225752   7.23966183
## 15   6.11666178     8.5378784   7.33850572   7.34880458
## 16  10.91542407     8.4418904   7.43913626   7.45207154
## 17   8.44443068     8.3459025   7.53414912   7.54946998
## 18   3.61650551     8.2499146   7.62354431   7.64100717
## 19   9.04733990     8.1539266   7.70732183   7.72669040
## 20   6.78781174     8.0579387   7.78548168   7.80652691
## 21   5.68039177     7.9619508   7.85802386   7.88052400
## 22   7.45661215     7.8659628   7.92494837   7.94868893
## 23   5.91095407     7.7699749   7.98625521   8.01102896
## 24   6.56945966     7.6739870   8.04194438   8.06755137
## 25   6.83532091     7.5779990   8.09201588   8.11826344
## 26   4.76404833     7.4820111   8.13646971   8.16317242
## 27   9.85892273     7.3860232   8.17530587   8.20228560
## 28   8.52988673     7.2900352   8.20852436   8.23561024
## 29   5.98053666     7.1940473   8.23612517   8.26315362
## 30  10.79198858     7.0980594   8.25810832   8.28492300
## 31   9.15871357     7.0020714   8.27447380   8.30092566
## 32   7.73094672     6.9060835   8.28522160   8.31116887
## 33  10.12052374     6.8100956   8.29035174   8.31565989
## 34  10.08960031     6.7141076   8.28986420   8.31440601
## 35   9.97343458     6.6181197   8.28375900   8.30741448
## 36   9.69837019     6.5221318   8.27203612   8.29469258
## 37   9.41362043     6.4261439   8.25469558   8.27624759
## 38   8.16053532     6.3301559   8.23173736   8.25208677
## 39   7.64488520     6.2341680   8.20316147   8.22221739
## 40   7.46219849     6.1381801   8.16896791   8.18664672
## 41   6.79393468     6.0421921   8.12915669   8.14538204
## 42   7.72160040     5.9462042   8.08372779   8.09843062
## 43   5.55460675     5.8502163   8.03268122   8.04579973
## 44  12.36515405     5.7542283   7.97601698   7.98749663
## 45  10.37888696     5.6582404   7.91373507   7.92352860
## 46   5.64634482     5.5622525   7.84583549   7.85390291
## 47   7.01026951     5.4662645   7.77231824   7.77862683
## 48   6.80008384     5.3702766   7.69318332   7.69770763
## 49   9.20455834     5.2742887   7.60843073   7.61115259
## 50   7.38300169     5.1783007   7.51806047   7.51896896
## 51   7.95536675     5.0823128   7.42207253   7.42116404
## 52   7.28450429     4.9863249   7.32046693   7.31774507
## 53   7.14260313     4.8903369   7.21324366   7.20871935
## 54   9.84617304     4.7943490   7.10040271   7.09409413
## 55   6.53192910     4.6983611   6.98194410   6.97387668
## 56   9.88479306     4.6023731   6.85786782   6.84807429
## 57   3.61660520     4.5063852   6.72817386   6.71669421
## 58   7.73947543     4.4103973   6.59286224   6.57974373
## 59   6.66797173     4.3144093   6.45193294   6.43723011
## 60   6.69603986     4.2184214   6.30538598   6.28916062
## 61   6.86120734     4.1224335   6.15322134   6.13554253
## 62   4.92893130     4.0264455   5.99543903   5.97638312
## 63   5.09269145     3.9304576   5.83203905   5.81168965
## 64   3.54136163     3.8344697   5.66302141   5.64146939
## 65   3.24821430     3.7384818   5.48838609   5.46572963
## 66   5.80601657     3.6424938   5.30813310   5.28447762
## 67   5.89641956     3.5465059   5.12226244   5.09772064
## 68   4.90092734     3.4505180   4.93077411   4.90546596
## 69   6.42825088     3.3545300   4.73366811   4.70772084
## 70   8.46656056     3.2585421   4.53094444   4.50449257
## 71   3.16088227     3.1625542   4.32260310   4.29578842
## 72  -0.70496157     3.0665662   4.10864409   4.08161564
## 73   5.68916300     2.9705783   3.88906741   3.86198152
## 74   2.01747237     2.8745904   3.66387306   3.63689332
## 75   1.81192277     2.7786024   3.43306103   3.40635832
## 76   4.98502704     2.6826145   3.19663134   3.17038378
## 77   2.10416075     2.5866266   2.95458398   2.92897699
## 78  -0.03402802     2.4906386   2.70691894   2.68214520
## 79   2.49759319     2.3946507   2.45363624   2.42989569
## 80   1.57866050     2.2986628   2.19473586   2.17223573
## 81   1.58330676     2.2026748   1.93021782   1.90917259
## 82   2.05155254     2.1066869   1.66008210   1.64071354
## 83   0.24276319     2.0106990   1.38432872   1.36686585
## 84   1.96980605     1.9147110   1.10295766   1.08763680
## 85  -0.06907230     1.8187231   0.81596894   0.80303366
## 86   0.72019080     1.7227352   0.52336254   0.51306368
## 87   1.92890913     1.6267472   0.22513847   0.21773416
## 88   0.27807648     1.5307593  -0.07870327  -0.08294765
## 89  -1.57778910     1.4347714  -0.38816268  -0.38897447
## 90   1.03192806     1.3387834  -0.70323975  -0.70033903
## 91   0.37543746     1.2427955  -1.02393450  -1.01703406
## 92  -0.86678123     1.1468076  -1.35024692  -1.33905229
## 93  -1.84423840     1.0508196  -1.68217701  -1.66638645
## 94  -3.94176257     0.9548317  -2.01972477  -1.99902927
## 95  -0.33501589     0.8588438  -2.36289021  -2.33697348
## 96  -4.63333215     0.7628559  -2.71167331  -2.68021179
## 97   0.55923899     0.6668679  -3.06607408  -3.02873696
## 98  -1.13894159     0.5708800  -3.42609252  -3.38254170
## 99  -5.07042123     0.4748921  -3.79172863  -3.74161874
## 100 -7.05284180     0.3789041  -4.16298242  -4.10596081

##Interpretasi: Tabel menunjukkan perbandingan nilai aktual Y dengan prediksi dari tiga model. Prediksi model linier sangat meleset (misalnya pada baris 1: Y=3.88 vs prediksi linier=9.88), sedangkan prediksi polinomial derajat 2 dan 3 jauh lebih mendekati nilai aktual. Hal ini mengkonfirmasi bahwa model linier tidak mampu menangkap pola non-linier, sementara kedua model polinomial (derajat 2 dan 3) memberikan prediksi yang akurat dan hampir identik, sesuai dengan kesimpulan sebelumnya bahwa derajat 2 adalah model terbaik.