Tugas ini bertujuan untuk mengimplementasikan konsep Pemrograman Berorientasi Objek (OOP) menggunakan sistem S4 di R. Sistem S4 dipilih karena mendukung definisi kelas yang lebih formal dibandingkan S3, termasuk definisi slot yang eksplisit, kontrol pewarisan yang ketat, serta validasi tipe data otomatis.
Program yang dibangun mencakup dua kelas utama:
ModelRegresi sebagai kelas induk,
digunakan untuk regresi linier bergandaModelPoli sebagai kelas turunan dari
ModelRegresi, digunakan untuk regresi polinomial
(nonlinier)Estimasi koefisien pada kedua kelas dilakukan menggunakan
optimasi numerik melalui fungsi optim(),
selain juga tersedia metode analitik OLS sebagai pembanding.
ModelRegresiKelas ModelRegresi berfungsi sebagai kerangka utama yang
menyimpan seluruh hasil fitting regresi linier. Kelas ini memiliki 8
slot yang mencakup informasi koefisien, nilai fitted, residual, matriks
desain, dan status optimasi.
setClass("ModelRegresi",
representation(
beta = "numeric", # koefisien hasil estimasi (beta-hat)
yhat = "numeric", # nilai fitted y-hat
ehat = "numeric", # residual = y - y-hat
matX = "matrix", # matriks desain X
vekY = "numeric", # vektor respons y
rumus = "character", # formula model yang digunakan
conv = "logical", # cek optimasi konvergen
iter = "numeric" # jumlah iterasi yang dibutuhkan
)
)
Konstruktor ModelRegresi() bertugas membentuk objek
kelas S4 dari data yang diberikan. Proses estimasi koefisien dapat
dilakukan dengan dua cara:
optim() dengan pilihan metode
BFGS, Nelder-Mead, CG, atau L-BFGS-BModelRegresi <- function(rumus, data, metode = "OLS") {
# parsing formula ke matriks desain dan vektor respons
mf <- model.frame(rumus, data = data)
X <- model.matrix(rumus, data = data)
y <- model.response(mf)
p <- ncol(X)
# fungsi objektif: SSE yang akan diminimalkan
SSE_fn <- function(b) {
resid <- y - X %*% b
sum(resid^2)
}
if (metode == "OLS") {
# solusi analitik
b_hat <- as.numeric(solve(t(X) %*% X) %*% t(X) %*% y)
ok <- TRUE
niter <- 1L
} else {
# optimasi numerik via optim()
hasil <- optim(
par = rep(0, p),
fn = SSE_fn,
method = metode,
control = list(maxit = 5000, reltol = 1e-10)
)
b_hat <- hasil$par
ok <- hasil$convergence == 0
niter <- hasil$counts[1]
}
names(b_hat) <- colnames(X)
# buat dan kembalikan objek S4
new("ModelRegresi",
beta = b_hat,
yhat = as.numeric(X %*% b_hat),
ehat = as.numeric(y - X %*% b_hat),
matX = X,
vekY = y,
rumus = deparse(rumus),
conv = ok,
iter = as.numeric(niter))
}
Fungsi aksesor dibuat agar pengguna dapat mengambil informasi dari dalam objek tanpa perlu mengakses slot secara langsung (dengan operator @). Dengan adanya aksesor, informasi dari objek dapat diakses dengan lebih mudah tanpa perlu memanggil slot secara langsung.
# definisi generik
setGeneric("getKoef", function(obj) standardGeneric("getKoef"))
[1] "getKoef"
setGeneric("getFit", function(obj) standardGeneric("getFit"))
[1] "getFit"
setGeneric("getResid", function(obj) standardGeneric("getResid"))
[1] "getResid"
setGeneric("getConv", function(obj) standardGeneric("getConv"))
[1] "getConv"
# implementasi untuk kelas ModelRegresi
setMethod("getKoef", "ModelRegresi", function(obj) obj@beta)
setMethod("getFit", "ModelRegresi", function(obj) obj@yhat)
setMethod("getResid", "ModelRegresi", function(obj) obj@ehat)
setMethod("getConv", "ModelRegresi", function(obj)
list(konvergen = obj@conv, iterasi = obj@iter)
)
Pada langkah ini didefinisikan tiga metode generik sesuai yang
diminta: plot, summary, dan
residuals.
plot_model()Menghasilkan empat panel diagnostik yang umum digunakan untuk mengevaluasi asumsi model regresi: plot aktual vs fitted, residual vs fitted, histogram residual, dan QQ-plot.
setGeneric("plot_model", function(obj, ...) standardGeneric("plot_model"))
[1] "plot_model"
setMethod("plot_model", "ModelRegresi", function(obj, ...) {
par(mfrow = c(2, 2), mar = c(4, 4, 3, 1))
# panel 1: nilai aktual vs fitted
plot(obj@vekY, obj@yhat,
main = "Aktual vs Fitted",
xlab = "y aktual", ylab = "y fitted",
pch = 16, col = "steelblue", cex = 0.8)
abline(0, 1, col = "red", lty = 2)
# panel 2: residual vs fitted (cek homoskedastisitas)
plot(obj@yhat, obj@ehat,
main = "Residual vs Fitted",
xlab = "y fitted", ylab = "residual",
pch = 16, col = "coral", cex = 0.8)
abline(h = 0, col = "red", lty = 2)
# panel 3: histogram residual
hist(obj@ehat, breaks = 15, freq = FALSE,
main = "Distribusi Residual",
xlab = "residual",
col = "lightblue", border = "white")
curve(dnorm(x, mean(obj@ehat), sd(obj@ehat)),
add = TRUE, col = "darkblue", lwd = 2)
# panel 4: QQ-plot (cek normalitas)
qqnorm(obj@ehat, pch = 16, col = "purple",
main = "Normal Q-Q Plot")
qqline(obj@ehat, col = "red")
par(mfrow = c(1, 1))
invisible(obj)
})
summary()Menampilkan tabel koefisien (estimasi, standard error, t-hitung, p-value) serta statistik kelayakan model seperti \(R^2\), \(R^2\) adjusted, dan RMSE.
setMethod("summary", "ModelRegresi", function(object, ...) {
n <- length(object@vekY)
p <- length(object@beta)
# hitung statistik model
SST <- sum((object@vekY - mean(object@vekY))^2)
SSE <- sum(object@ehat^2)
R2 <- 1 - SSE / SST
R2adj <- 1 - (SSE / (n - p)) / (SST / (n - 1))
s2 <- SSE / (n - p)
# standard error, t-hitung, p-value koefisien
vb <- s2 * solve(t(object@matX) %*% object@matX)
se <- sqrt(diag(vb))
tval <- object@beta / se
pval <- 2 * pt(-abs(tval), df = n - p)
cat("=============================================\n")
cat("Formula :", object@rumus, "\n")
cat("Metode : Optimasi Numerik (optim)\n")
cat("Konvergen:", object@conv, "| Iterasi:", object@iter, "\n")
cat("=============================================\n\n")
cat("Tabel Koefisien:\n")
print(data.frame(
Estimasi = round(object@beta, 5),
Std.Error = round(se, 5),
t.hitung = round(tval, 3),
p.value = round(pval, 4),
row.names = names(object@beta)
))
cat("\n---------------------------------------------\n")
cat(sprintf("R-squared : %.5f\n", R2))
cat(sprintf("R-squared adj. : %.5f\n", R2adj))
cat(sprintf("RMSE : %.5f\n", sqrt(s2)))
cat(sprintf("n observasi : %d\n", n))
cat("=============================================\n")
invisible(list(R2 = R2, R2adj = R2adj, RMSE = sqrt(s2)))
})
residuals()setMethod("residuals", "ModelRegresi", function(object, ...) object@ehat)
# tampilan default saat objek dipanggil
setMethod("show", "ModelRegresi", function(object) {
cat("Objek S4 : ModelRegresi\n")
cat("Formula :", object@rumus, "\n")
cat("Koefisien:\n")
print(round(object@beta, 4))
cat("Konvergen:", object@conv, "| Iterasi:", object@iter, "\n")
})
ModelPoliKelas ModelPoli mewarisi seluruh slot dan metode dari
ModelRegresi. Perbedaannya terletak pada proses konstruksi:
prediktor \(x\) diperluas secara
otomatis menjadi \(x, x^2, x^3, \ldots,
x^d\) sebelum dimasukkan ke dalam matriks desain. Metode
summary() dan plot_model() dimodifikasi agar
dapat menampilkan informasi yang lebih sesuai untuk model polinomial,
sementara aksesor dari kelas induk (getKoef,
getFit, getResid) tetap dapat digunakan
langsung tanpa perlu didefinisikan ulang.
setClass("ModelPoli",
contains = "ModelRegresi", # pewarisan dari ModelRegresi
representation(
deg = "numeric", # derajat polinomial
xvar = "character" # nama variabel prediktor asli
)
)
ModelPoli <- function(rumus, data, deg = 2, metode = "OLS") {
yvar <- all.vars(rumus)[1]
xvar <- all.vars(rumus)[-1]
if (length(xvar) != 1)
stop("ModelPoli hanya mendukung satu variabel prediktor.")
# perluas data: tambahkan kolom x^2, x^3, ..., x^deg
d2 <- data
for (k in 2:deg)
d2[[paste0(xvar, k)]] <- data[[xvar]]^k
# susun formula baru dengan semua suku polinomial
suku_baru <- c(xvar, paste0(xvar, 2:deg))
f_baru <- as.formula(paste(yvar, "~", paste(suku_baru, collapse = "+")))
mf <- model.frame(f_baru, data = d2)
X <- model.matrix(f_baru, data = d2)
y <- model.response(mf)
p <- ncol(X)
SSE_fn <- function(b) sum((y - X %*% b)^2)
if (metode == "OLS") {
b_hat <- as.numeric(solve(t(X) %*% X) %*% t(X) %*% y)
ok <- TRUE
niter <- 1L
} else {
hasil <- optim(rep(0, p), SSE_fn, method = metode,
control = list(maxit = 5000, reltol = 1e-10))
b_hat <- hasil$par
ok <- hasil$convergence == 0
niter <- hasil$counts[1]
}
names(b_hat) <- colnames(X)
new("ModelPoli",
beta = b_hat,
yhat = as.numeric(X %*% b_hat),
ehat = as.numeric(y - X %*% b_hat),
matX = X, vekY = y,
rumus = deparse(rumus),
conv = ok, iter = as.numeric(niter),
deg = deg, xvar = xvar)
}
# aksesor derajat polinomial
setGeneric("getDeg", function(obj) standardGeneric("getDeg"))
[1] "getDeg"
setMethod("getDeg", "ModelPoli", function(obj) obj@deg)
# fungsi prediksi untuk data baru
setGeneric("predik", function(obj, baru, ...) standardGeneric("predik"))
[1] "predik"
setMethod("predik", "ModelPoli", function(obj, baru, ...) {
xb <- baru[[obj@xvar]]
dfb <- setNames(data.frame(xb), obj@xvar)
for (k in 2:obj@deg)
dfb[[paste0(obj@xvar, k)]] <- xb^k
Xb <- cbind(1, as.matrix(dfb))
colnames(Xb)[1] <- "(Intercept)"
as.numeric(Xb %*% obj@beta)
})
# override summary: tampilkan info derajat, lalu panggil summary induk
setMethod("summary", "ModelPoli", function(object, ...) {
cat("=============================================\n")
cat("Kelas : ModelPoli (turunan ModelRegresi)\n")
cat("Derajat :", object@deg, "| Prediktor:", object@xvar, "\n")
cat("=============================================\n\n")
callNextMethod() # memanggil summary() dari ModelRegresi
})
# override plot: scatter + kurva polinomial, dan residual vs fitted
setMethod("plot_model", "ModelPoli", function(obj, ...) {
par(mfrow = c(1, 2), mar = c(4, 4, 3, 1))
xv <- obj@matX[, obj@xvar]
urut <- order(xv)
# panel kiri: scatter plot + kurva hasil fitting
plot(xv, obj@vekY,
main = paste("Regresi Polinomial Derajat", obj@deg),
xlab = obj@xvar, ylab = "y",
pch = 16, col = "gray55", cex = 0.8)
lines(xv[urut], obj@yhat[urut], col = "red", lwd = 2)
legend("topleft", legend = paste("derajat =", obj@deg),
col = "red", lty = 1, bty = "n")
# panel kanan: residual vs fitted
plot(obj@yhat, obj@ehat,
main = "Residual vs Fitted",
xlab = "fitted", ylab = "residual",
pch = 16, col = "steelblue", cex = 0.8)
abline(h = 0, col = "red", lty = 2)
par(mfrow = c(1, 1))
invisible(obj)
})
setMethod("show", "ModelPoli", function(object) {
cat("Objek S4 : ModelPoli (turunan ModelRegresi)\n")
cat("Formula :", object@rumus, "| Derajat:", object@deg, "\n")
print(round(object@beta, 4))
})
KomstatK4P2Setelah seluruh kelas dan metode selesai didefinisikan, program
dikemas menjadi sebuah package R bernama
KomstatK4P2. Proses pembangunan package dilakukan langsung
dari chunk berikut menggunakan R CMD build.
Package ini terdiri dari:
| File | Keterangan |
|---|---|
DESCRIPTION |
Metadata package (nama, versi, author, dependensi) |
NAMESPACE |
Daftar fungsi dan kelas yang diekspor |
R/ModelRegresi.R |
Source code kelas induk |
R/ModelPoli.R |
Source code kelas turunan |
pkg <- "KomstatK4P2"
# buat struktur folder
dir.create(file.path(pkg, "R"), recursive = TRUE, showWarnings = FALSE)
# --- DESCRIPTION ---
writeLines(c(
"Package: KomstatK4P2",
"Type: Package",
"Title: Model Regresi Linier dan Polinomial berbasis OOP S4",
"Version: 1.0.0",
"Date: 2026-06-05",
"Author: Kelompok 4 Paralel 2 Komputasi Statistika",
"Maintainer: Kelompok 4 Paralel 2 <komstat.k4p2@email.com>",
"Description: Implementasi Pemrograman Berorientasi Objek sistem S4 di R",
" untuk pemodelan regresi linier berganda (ModelRegresi) dan regresi",
" polinomial (ModelPoli). Estimasi koefisien menggunakan optimasi numerik",
" via optim() maupun solusi analitik OLS.",
"License: GPL-3",
"Encoding: UTF-8",
"Imports: methods, stats, graphics",
"Collate: 'ModelRegresi.R' 'ModelPoli.R'"
), file.path(pkg, "DESCRIPTION"))
# --- NAMESPACE ---
writeLines(c(
"import(methods)",
"importFrom(stats, model.frame, model.matrix, model.response,",
" optim, pt, dnorm, qqline, qqnorm, sd)",
"importFrom(graphics, abline, curve, hist, legend, lines, par, plot)",
"exportClasses(ModelRegresi, ModelPoli)",
"exportMethods(show, summary, residuals,",
" plot_model, getKoef, getFit, getResid, getConv,",
" getDeg, predik)",
"export(ModelRegresi, ModelPoli)"
), file.path(pkg, "NAMESPACE"))
# --- R/ModelRegresi.R ---
writeLines(c(
'# ModelRegresi.R — Kelas Induk OOP S4',
'# Kelompok 4 Paralel 2, Komputasi Statistika',
'',
'setClass("ModelRegresi",',
' representation(',
' beta = "numeric", yhat = "numeric", ehat = "numeric",',
' matX = "matrix", vekY = "numeric", rumus = "character",',
' conv = "logical", iter = "numeric"',
' )',
')',
'',
'ModelRegresi <- function(rumus, data, metode = "OLS") {',
' mf <- model.frame(rumus, data = data)',
' X <- model.matrix(rumus, data = data)',
' y <- model.response(mf)',
' p <- ncol(X)',
' SSE_fn <- function(b) { resid <- y - X %*% b; sum(resid^2) }',
' if (metode == "OLS") {',
' b_hat <- as.numeric(solve(t(X) %*% X) %*% t(X) %*% y)',
' ok <- TRUE; niter <- 1L',
' } else {',
' hasil <- optim(rep(0,p), SSE_fn, method=metode,',
' control=list(maxit=5000, reltol=1e-10))',
' b_hat <- hasil$par; ok <- hasil$convergence==0; niter <- hasil$counts[1]',
' }',
' names(b_hat) <- colnames(X)',
' new("ModelRegresi", beta=b_hat, yhat=as.numeric(X%*%b_hat),',
' ehat=as.numeric(y-X%*%b_hat), matX=X, vekY=y,',
' rumus=deparse(rumus), conv=ok, iter=as.numeric(niter))',
'}',
'',
'setGeneric("getKoef", function(obj) standardGeneric("getKoef"))',
'setGeneric("getFit", function(obj) standardGeneric("getFit"))',
'setGeneric("getResid", function(obj) standardGeneric("getResid"))',
'setGeneric("getConv", function(obj) standardGeneric("getConv"))',
'setMethod("getKoef", "ModelRegresi", function(obj) obj@beta)',
'setMethod("getFit", "ModelRegresi", function(obj) obj@yhat)',
'setMethod("getResid", "ModelRegresi", function(obj) obj@ehat)',
'setMethod("getConv", "ModelRegresi", function(obj)',
' list(konvergen=obj@conv, iterasi=obj@iter))',
'',
'setGeneric("plot_model", function(obj,...) standardGeneric("plot_model"))',
'setMethod("plot_model", "ModelRegresi", function(obj,...) {',
' par(mfrow=c(2,2), mar=c(4,4,3,1))',
' plot(obj@vekY, obj@yhat, main="Aktual vs Fitted",',
' xlab="y aktual", ylab="y fitted", pch=16, col="steelblue", cex=0.8)',
' abline(0,1,col="red",lty=2)',
' plot(obj@yhat, obj@ehat, main="Residual vs Fitted",',
' xlab="y fitted", ylab="residual", pch=16, col="coral", cex=0.8)',
' abline(h=0,col="red",lty=2)',
' hist(obj@ehat, breaks=15, freq=FALSE, main="Distribusi Residual",',
' xlab="residual", col="lightblue", border="white")',
' curve(dnorm(x,mean(obj@ehat),sd(obj@ehat)), add=TRUE, col="darkblue", lwd=2)',
' qqnorm(obj@ehat, pch=16, col="purple", main="Normal Q-Q Plot")',
' qqline(obj@ehat, col="red")',
' par(mfrow=c(1,1)); invisible(obj)',
'})',
'',
'setMethod("summary", "ModelRegresi", function(object,...) {',
' n <- length(object@vekY); p <- length(object@beta)',
' SST <- sum((object@vekY-mean(object@vekY))^2); SSE <- sum(object@ehat^2)',
' R2 <- 1-SSE/SST; R2adj <- 1-(SSE/(n-p))/(SST/(n-1)); s2 <- SSE/(n-p)',
' se <- sqrt(diag(s2*solve(t(object@matX)%*%object@matX)))',
' tval <- object@beta/se; pval <- 2*pt(-abs(tval), df=n-p)',
' cat("=============================================\n")',
' cat("Formula :", object@rumus, "\n")',
' cat("Konvergen:", object@conv, "| Iterasi:", object@iter, "\n")',
' cat("=============================================\n\n")',
' print(data.frame(Estimasi=round(object@beta,5), Std.Error=round(se,5),',
' t.hitung=round(tval,3), p.value=round(pval,4),',
' row.names=names(object@beta)))',
' cat(sprintf("\nR2=%.5f | R2adj=%.5f | RMSE=%.5f | n=%d\n",',
' R2, R2adj, sqrt(s2), n))',
' invisible(list(R2=R2, R2adj=R2adj, RMSE=sqrt(s2)))',
'})',
'',
'setMethod("residuals","ModelRegresi",function(object,...) object@ehat)',
'setMethod("show","ModelRegresi",function(object) {',
' cat("Objek S4 : ModelRegresi\nFormula :", object@rumus, "\nKoefisien:\n")',
' print(round(object@beta,4))',
' cat("Konvergen:", object@conv, "| Iterasi:", object@iter, "\n")',
'})'
), file.path(pkg, "R", "ModelRegresi.R"))
# --- R/ModelPoli.R ---
writeLines(c(
'# ModelPoli.R — Kelas Turunan OOP S4',
'# Kelompok 4 Paralel 2, Komputasi Statistika',
'',
'setClass("ModelPoli",',
' contains = "ModelRegresi",',
' representation(deg="numeric", xvar="character")',
')',
'',
'ModelPoli <- function(rumus, data, deg=2, metode="OLS") {',
' yvar <- all.vars(rumus)[1]; xvar <- all.vars(rumus)[-1]',
' if (length(xvar)!=1) stop("ModelPoli hanya mendukung satu variabel prediktor.")',
' d2 <- data',
' for (k in 2:deg) d2[[paste0(xvar,k)]] <- data[[xvar]]^k',
' suku_baru <- c(xvar, paste0(xvar, 2:deg))',
' f_baru <- as.formula(paste(yvar,"~",paste(suku_baru,collapse="+")))',
' mf <- model.frame(f_baru,data=d2); X <- model.matrix(f_baru,data=d2)',
' y <- model.response(mf); p <- ncol(X)',
' SSE_fn <- function(b) sum((y-X%*%b)^2)',
' if (metode=="OLS") {',
' b_hat <- as.numeric(solve(t(X)%*%X)%*%t(X)%*%y); ok<-TRUE; niter<-1L',
' } else {',
' hasil <- optim(rep(0,p),SSE_fn,method=metode,',
' control=list(maxit=5000,reltol=1e-10))',
' b_hat<-hasil$par; ok<-hasil$convergence==0; niter<-hasil$counts[1]',
' }',
' names(b_hat) <- colnames(X)',
' new("ModelPoli", beta=b_hat, yhat=as.numeric(X%*%b_hat),',
' ehat=as.numeric(y-X%*%b_hat), matX=X, vekY=y, rumus=deparse(rumus),',
' conv=ok, iter=as.numeric(niter), deg=deg, xvar=xvar)',
'}',
'',
'setGeneric("getDeg", function(obj) standardGeneric("getDeg"))',
'setMethod("getDeg", "ModelPoli", function(obj) obj@deg)',
'',
'setGeneric("predik", function(obj,baru,...) standardGeneric("predik"))',
'setMethod("predik", "ModelPoli", function(obj,baru,...) {',
' xb <- baru[[obj@xvar]]; dfb <- setNames(data.frame(xb), obj@xvar)',
' for (k in 2:obj@deg) dfb[[paste0(obj@xvar,k)]] <- xb^k',
' Xb <- cbind(1, as.matrix(dfb)); colnames(Xb)[1] <- "(Intercept)"',
' as.numeric(Xb %*% obj@beta)',
'})',
'',
'setMethod("summary","ModelPoli",function(object,...) {',
' cat("=============================================\n")',
' cat("Kelas : ModelPoli (turunan ModelRegresi)\n")',
' cat("Derajat :", object@deg, "| Prediktor:", object@xvar, "\n")',
' cat("=============================================\n\n")',
' callNextMethod()',
'})',
'',
'setMethod("plot_model","ModelPoli",function(obj,...) {',
' par(mfrow=c(1,2), mar=c(4,4,3,1))',
' xv <- obj@matX[,obj@xvar]; urut <- order(xv)',
' plot(xv, obj@vekY, main=paste("Regresi Polinomial Derajat",obj@deg),',
' xlab=obj@xvar, ylab="y", pch=16, col="gray55", cex=0.8)',
' lines(xv[urut], obj@yhat[urut], col="red", lwd=2)',
' legend("topleft", legend=paste("derajat =",obj@deg), col="red", lty=1, bty="n")',
' plot(obj@yhat, obj@ehat, main="Residual vs Fitted",',
' xlab="fitted", ylab="residual", pch=16, col="steelblue", cex=0.8)',
' abline(h=0, col="red", lty=2)',
' par(mfrow=c(1,1)); invisible(obj)',
'})',
'',
'setMethod("show","ModelPoli",function(object) {',
' cat("Objek S4 : ModelPoli (turunan ModelRegresi)\n")',
' cat("Formula :", object@rumus, "| Derajat:", object@deg, "\n")',
' print(round(object@beta,4))',
'})'
), file.path(pkg, "R", "ModelPoli.R"))
# build package → hasilkan file .tar.gz
system("R CMD build KomstatK4P2", intern = TRUE)
[1] "* checking for file 'KomstatK4P2/DESCRIPTION' ... OK"
[2] "* preparing 'KomstatK4P2':"
[3] "* checking DESCRIPTION meta-information ... OK"
[4] "* checking for LF line-endings in source and make files and shell scripts"
[5] "* checking for empty or unneeded directories"
[6] "* building 'KomstatK4P2_1.0.0.tar.gz'"
# konfirmasi file package berhasil dibuat
pkg_file <- list.files(pattern = "KomstatK4P2.*\\.tar\\.gz")
if (length(pkg_file) > 0) {
cat("Package berhasil dibuat:", pkg_file, "\n")
cat("Ukuran file:", file.size(pkg_file), "bytes\n")
cat("\nCara install:\n")
cat(' install.packages("', pkg_file, '", repos=NULL, type="source")\n', sep="")
} else {
cat("Package belum ditemukan di direktori ini.\n")
}
Package berhasil dibuat: KomstatK4P2_1.0.0.tar.gz
Ukuran file: 2857 bytes
Cara install:
install.packages("KomstatK4P2_1.0.0.tar.gz", repos=NULL, type="source")
Dibuat dua dataset simulasi untuk menguji kedua kelas di atas.
Dataset 1 — regresi linier berganda dengan model populasi: \[y = 3 + 2{,}5x_1 - 1{,}2x_2 + \varepsilon, \quad \varepsilon \sim N(0, 1{,}5^2)\]
Dataset 2 — regresi polinomial dengan model populasi: \[y = 1 - 0{,}5x + 2x^2 + \varepsilon, \quad \varepsilon \sim N(0, 0{,}5^2)\]
# dataset 1: regresi linier berganda
set.seed(42)
n <- 100
x1 <- rnorm(n, mean = 5, sd = 2)
x2 <- rnorm(n, mean = 10, sd = 3)
y <- 3 + 2.5*x1 - 1.2*x2 + rnorm(n, sd = 1.5)
dat <- data.frame(y, x1, x2)
head(dat)
y x1 x2
1 3.0299230 7.741917 13.602896
2 -2.5839290 3.870604 13.134253
3 10.6841809 5.726257 6.990374
4 3.0990870 6.265725 15.545446
5 5.8564335 5.808537 7.999680
6 0.8632443 4.787751 10.316541
# dataset 2: regresi polinomial
set.seed(7)
x <- seq(-3, 3, length.out = 80)
y2 <- 1 - 0.5*x + 2*x^2 + rnorm(80, sd = 0.5)
dat2 <- data.frame(y2, x)
head(dat2)
y2 x
1 21.64362 -3.000000
2 18.96378 -2.924051
3 18.30027 -2.848101
4 17.54958 -2.772152
5 16.40178 -2.696203
6 15.56794 -2.620253
ModelRegresim_ols <- ModelRegresi(y ~ x1 + x2, data = dat, metode = "OLS")
m_ols
Objek S4 : ModelRegresi
Formula : y ~ x1 + x2
Koefisien:
(Intercept) x1 x2
3.1151 2.3922 -1.1574
Konvergen: TRUE | Iterasi: 1
m_bfgs <- ModelRegresi(y ~ x1 + x2, data = dat, metode = "BFGS")
m_bfgs
Objek S4 : ModelRegresi
Formula : y ~ x1 + x2
Koefisien:
(Intercept) x1 x2
3.1151 2.3922 -1.1574
Konvergen: TRUE | Iterasi: 27
getKoef(m_ols)
(Intercept) x1 x2
3.115093 2.392218 -1.157353
head(getFit(m_ols))
[1] 5.8920884 -2.8265516 8.7232149 0.1124996 7.7519228 2.6285531
head(getResid(m_ols))
[1] -2.8621654 0.2426227 1.9609659 2.9865874 -1.8954893 -1.7653088
getConv(m_bfgs)
$konvergen
[1] TRUE
$iterasi
[1] 27
summary()summary(m_ols)
=============================================
Formula : y ~ x1 + x2
Metode : Optimasi Numerik (optim)
Konvergen: TRUE | Iterasi: 1
=============================================
Tabel Koefisien:
Estimasi Std.Error t.hitung p.value
(Intercept) 3.11509 0.67068 4.645 0
x1 2.39222 0.07341 32.588 0
x2 -1.15735 0.05636 -20.534 0
---------------------------------------------
R-squared : 0.93702
R-squared adj. : 0.93572
RMSE : 1.52045
n observasi : 100
=============================================
plot_model()plot_model(m_ols)
Diagnostik plot ModelRegresi (OLS)
residuals()e <- residuals(m_ols)
cat("Rata-rata residual :", round(mean(e), 8), "(harusnya mendekati 0)\n")
Rata-rata residual : 0 (harusnya mendekati 0)
cat("Std. dev. residual :", round(sd(e), 4), "\n")
Std. dev. residual : 1.505
ModelPoli (Pewarisan)mp2 <- ModelPoli(y2 ~ x, data = dat2, deg = 2)
mp3 <- ModelPoli(y2 ~ x, data = dat2, deg = 3)
mp2
Objek S4 : ModelPoli (turunan ModelRegresi)
Formula : y2 ~ x | Derajat: 2
(Intercept) x x2
1.0989 -0.5337 1.9998
getDeg(mp2)
[1] 2
getKoef(mp2)
(Intercept) x x2
1.0989361 -0.5336739 1.9998032
summary() (Override + callNextMethod())summary(mp2)
=============================================
Kelas : ModelPoli (turunan ModelRegresi)
Derajat : 2 | Prediktor: x
=============================================
=============================================
Formula : y2 ~ x
Metode : Optimasi Numerik (optim)
Konvergen: TRUE | Iterasi: 1
=============================================
Tabel Koefisien:
Estimasi Std.Error t.hitung p.value
(Intercept) 1.09894 0.08308 13.228 0
x -0.53367 0.03158 -16.901 0
x2 1.99980 0.02013 99.327 0
---------------------------------------------
R-squared : 0.99247
R-squared adj. : 0.99228
RMSE : 0.49532
n observasi : 80
=============================================
$R2
[1] 0.992472
$R2adj
[1] 0.9922764
$RMSE
[1] 0.495324
plot_model() (Override)plot_model(mp2)
Plot ModelPoli derajat 2
plot_model(mp3)
Plot ModelPoli derajat 3
x_baru <- data.frame(x = c(-2.5, -1, 0, 1, 2.5))
y_pred <- predik(mp2, x_baru)
y_asli <- 1 - 0.5*x_baru$x + 2*x_baru$x^2
data.frame(
x = x_baru$x,
y_populasi = round(y_asli, 4),
y_prediksi = round(y_pred, 4),
selisih = round(abs(y_pred - y_asli), 4)
)
x y_populasi y_prediksi selisih
1 -2.5 14.75 14.9319 0.1819
2 -1.0 3.50 3.6324 0.1324
3 0.0 1.00 1.0989 0.0989
4 1.0 2.50 2.5651 0.0651
5 2.5 12.25 12.2635 0.0135
cat("is(m_ols, 'ModelRegresi') :", is(m_ols, "ModelRegresi"), "\n")
is(m_ols, 'ModelRegresi') : TRUE
cat("is(mp2, 'ModelRegresi') :", is(mp2, "ModelRegresi"), "\n")
is(mp2, 'ModelRegresi') : TRUE
cat("is(mp2, 'ModelPoli') :", is(mp2, "ModelPoli"), "\n")
is(mp2, 'ModelPoli') : TRUE
cat("is(m_ols, 'ModelPoli') :", is(m_ols, "ModelPoli"), "\n")
is(m_ols, 'ModelPoli') : FALSE
Hasilnya menunjukkan bahwa mp2 dikenali sebagai
ModelRegresi (karena mewarisi), sementara
m_ols tidak dikenali sebagai ModelPoli.
Pewarisan berjalan sesuai yang diharapkan.
cat(sprintf("%-14s %10s %8s %8s\n", "Metode", "Intercept", "x1", "x2"))
Metode Intercept x1 x2
cat(strrep("-", 46), "\n")
----------------------------------------------
for (met in c("OLS", "BFGS", "Nelder-Mead", "CG", "L-BFGS-B")) {
m <- ModelRegresi(y ~ x1 + x2, data = dat, metode = met)
b <- getKoef(m)
cat(sprintf("%-14s %10.5f %8.5f %8.5f\n", met, b[1], b[2], b[3]))
}
OLS 3.11509 2.39222 -1.15735
BFGS 3.11510 2.39222 -1.15735
Nelder-Mead 3.11509 2.39221 -1.15735
CG 3.11487 2.39223 -1.15734
L-BFGS-B 3.11509 2.39222 -1.15735
Hasil estimasi dari berbagai metode optimasi menunjukkan nilai yang sangat mirip dengan solusi OLS. Temuan ini menunjukkan bahwa proses estimasi telah berjalan dengan baik.
Berdasarkan hasil implementasi, konsep OOP menggunakan sistem S4 berhasil diterapkan pada pemodelan regresi linier dan regresi polinomial.
| Komponen | Implementasi |
|---|---|
| Kelas induk | ModelRegresi dengan 8 slot |
| Konstruktor | ModelRegresi() — OLS analitik dan optim()
numerik |
| Aksesor | getKoef(), getFit(),
getResid(), getConv() |
| Metode generik | plot_model(), summary(),
residuals() |
| Kelas turunan | ModelPoli dengan
contains = "ModelRegresi" |
| Pewarisan | Slot dan aksesor induk digunakan langsung oleh
ModelPoli |
| Override | summary() dan plot_model() di
ModelPoli menggunakan callNextMethod() |
| Metode baru | predik() dan getDeg() khusus
ModelPoli |
| Package R | KomstatK4P2_1.0.0.tar.gz dibangun otomatis dari chunk
di atas |