Randomness in Action: Simulasi Distribusi dengan R
Author
Muhammad Yusran
Published
September 22, 2025
library(tidyverse)
Warning: package 'ggplot2' was built under R version 4.4.3
Warning: package 'dplyr' was built under R version 4.4.3
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.1.4 ✔ readr 2.1.5
✔ forcats 1.0.0 ✔ stringr 1.5.1
✔ ggplot2 3.5.2 ✔ tibble 3.2.1
✔ lubridate 1.9.3 ✔ tidyr 1.3.1
✔ purrr 1.0.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
Pendahuluan: Dari Kebetulan ke Simulasi
Dalam dunia statistik modern, randomness bukan sekadar kebetulan, melainkan sebuah alat sains. Pembangkitan bilangan acak menjadi fondasi penting dalam komputasi statistik, terutama ketika kita ingin melakukan simulasi, eksperimen virtual, atau pengujian model tanpa harus selalu mengandalkan data nyata.
Bilangan acak yang dibangkitkan komputer pada dasarnya bukan “benar-benar acak”, melainkan pseudorandom: angka-angka yang dihasilkan oleh algoritma, tetapi cukup menyerupai sifat acak alami. Hebatnya, pseudorandom ini bisa dikendalikan sehingga eksperimen bisa direplikasi dengan hasil identik.
Lebih jauh, bilangan acak yang kita bangkitkan tidak berdiri sendiri, melainkan mengikuti distribusi probabilitas tertentu:
Fungsi massa peluang (pmf) untuk sebaran diskrit,
Fungsi kepekatan peluang (pdf) untuk sebaran kontinu,
serta Fungsi sebaran kumulatif (cdf) untuk melihat peluang kumulatif dari suatu sebaran.
Dengan memahami dan mempraktikkan pembangkitan bilangan acak, kita akan mampu:
Mensimulasikan data dari berbagai distribusi (normal, uniform, binomial, dsb.).
Menerapkan metode matematis seperti inverse transform, acceptance–rejection, dan direct transformation.
Menggunakan bilangan acak untuk membangun dan mengevaluasi model regresi sederhana maupun berganda ataupun model-model lainnya.
Praktikum ini akan mengajak kita untuk melihat aksi randomness secara nyata: bagaimana teori peluang berubah menjadi deretan angka, grafik distribusi, hingga model statistik yang bisa dianalisis.
Fungsi-fungsi Peluang dalam R
Sebagai salah satu bahasa pemrograman yang lahir dari kebutuhan akan komputasi statistik, R menyediakan sekumpulan fungsi bawaan untuk bekerja dengan berbagai sebaran peluang. Fungsi ini punya pola nama yang konsisten dengan prefix berikut:
Prefix
Deskripsi
r-
Pembangkitan bilangan acak dari suatu sebaran
d-
Probability density function (pdf) atau probability mass function (pmf)
p-
Cumulative distribution function (cdf)
q-
Fungsi quantile / invers CDF
Sebagai contoh, dnorm() menghitung kepadatan peluang dari distribusi normal, sedangkan rbinom() digunakan untuk membangkitkan angka acak dari distribusi binomial.
Tabel Fungsi Distribusi di R
Tabel berikut menyajikan daftar distribusi peluang yang paling umum digunakan dalam analisis dan simulasi statistik di R. Masing-masing distribusi disajikan dalam bentuk:
Notasi matematis formal yang menunjukkan bentuk distribusinya.
Nama fungsi dasar di R (misalnya norm, binom, pois) yang digunakan dengan awalan d-, p-, q-, atau r- sesuai kebutuhan.
Parameter-parameter yang harus ditentukan agar fungsi bekerja sesuai distribusi yang dimaksud.
Rumus probabilitas atau kepadatan peluang (PMF/PDF) sebagai representasi matematis distribusi tersebut.
Pemahaman terhadap struktur distribusi dan cara R mengimplementasikannya akan menjadi bekal penting sebelum kita mulai melakukan simulasi data acak dari distribusi-distribusi ini.
Distribusi
Notasi
R Name
Parameter
PDF / PMF
Beta
\(X \sim \text{Beta}(\alpha, \beta)\)
beta
shape1 = \(\alpha\), shape2 = \(\beta\)
\(f(x) = \dfrac{\Gamma(\alpha+\beta)}{\Gamma(\alpha)\Gamma(\beta)} x^{\alpha-1}(1-x)^{\beta-1}, \; 0 < x < 1\)
Pada literatur statistika, distribusi eksponensial dengan dua parameter yang berbeda:
Parameter rate (\(\lambda\)): \[
f(x) = \lambda e^{-\lambda x}, \quad x \geq 0
\]
dengan \(E[X] = 1/\lambda\).
Parameter scale (\(\theta\)): \[
f(x) = \frac{1}{\theta} e^{-x/\theta}, \quad x \geq 0
\]
dengan \(E[X] = \theta\).
Keduanya konsisten karena \(\lambda = 1/\theta\).
Pada R (rexp(), dexp(), pexp(), qexp()), parameter yang digunakan adalah rate (\(\lambda\)), bukan scale.
Jika notasi yang dipakai adalah \(X \sim \text{Exp}(\theta)\), maka implementasinya di R harus ditulis dengan rate = 1/theta.
Contoh Penggunaan Fungsi Distribusi di R
Mari kita lihat bagaimana R bekerja dengan distribusi peluang melalui contoh distribusi Normal dan Binomial.
Distribusi Normal (Kontinu)
Distribusi Normal merupakan salah satu distribusi paling penting dalam statistika. Pada contoh ini, kita akan:
Membangkitkan 1000 data acak dari distribusi \(X \sim N(\mu = 10, \sigma = 2)\) menggunakan rnorm(),
Menampilkan sebagian data dengan head(),
Memvisualisasikan distribusi data bangkitan melalui histogram,
Menambahkan kurva PDF teoritis menggunakan dnorm().
set.seed(123)data_norm <-rnorm(1000, mean =10, sd =2)data_norm <-data.frame(x=data_norm)head(data_norm)
ggplot(data_norm, aes(x = x)) +geom_histogram(aes(y =after_stat(density)), fill ="#56B4E9", color ="white", alpha =0.7) +stat_function(fun = dnorm, args =list(mean =10, sd =2), color ="#D55E00", linewidth =0.8) +labs(title ="Distribusi Normal: Histogram vs Kurva PDF",x ="Nilai",y ="Kepadatan (Density)" ) +theme_minimal() +theme(plot.title =element_text(size =14, face ="bold", hjust =0.5) )
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Pada grafik di atas, histogram mewakili distribusi data hasil simulasi, sedangkan kurva Vermilion menunjukkan bentuk teoretis dari PDF distribusi Normal. Kemiripan bentuk antara keduanya menunjukkan bahwa rnorm() berhasil membangkitkan data acak yang mengikuti karakteristik distribusi Normal yang diharapkan.
Distribusi Binomial (Diskrit)
Distribusi Binomial digunakan untuk memodelkan banyaknya keberhasilan dari sejumlah percobaan Bernoulli. Kita akan:
Membangkitkan 1000 data acak dari distribusi \(X \sim \text{Bin}(n = 10, p = 0.3)\) menggunakan rbinom(),
Menampilkan sebagian data dengan head(),
Menyajikan frekuensi hasil simulasi menggunakan barplot,
Menambahkan garis nilai probabilitas teoretis dari dbinom().
Karena distribusi Binomial bersifat diskrit, grafiknya disajikan sebagai barplot berdasarkan frekuensi hasil simulasi. Titik-titik Vermilion menunjukkan nilai probabilitas dari fungsi massa peluang (PMF) yang diperoleh dari dbinom() dan dikalikan dengan 1000 agar berada pada skala yang sama dengan frekuensi observasi. Distribusi simulasi dan probabilitas teoretis terlihat sejalan, memperlihatkan bahwa rbinom() membangkitkan data dengan distribusi yang sesuai secara empiris.
Teknik Pembangkitan Bilangan Acak
Komputer pada dasarnya adalah mesin deterministik—semua operasinya bisa diprediksi. Maka untuk menghasilkan bilangan acak, kita membutuhkan algoritma khusus yang menghasilkan pseudorandom number: bilangan yang tampak acak, namun sebenarnya dibangkitkan dari proses deterministik yang bisa direplikasi.
Ada beberapa teknik utama untuk membangkitkan bilangan acak, terutama dari distribusi tertentu:
Inverse-Transform Method
Konsep dasar: Jika kita memiliki fungsi distribusi kumulatif (CDF) \(F(x)\) dari suatu distribusi, dan sebuah bilangan acak \(U \sim \text{Unif}(0,1)\), maka bilangan acak \(X = F^{-1}(U)\) akan mengikuti distribusi \(F\) tersebut.
Prinsip Inverse-Transform Method
Untuk membangkitkan contoh acak \(X\) dengan sebaran tertentu:
Tentukan fungsi sebaran kumulatif \(F(x)\) dari sebaran yang diinginkan.
Hitung invers dari \(F\) atau \(F^{-1}(x)\).
Bangkitkan contoh acak \(u_1, u_2, u_3, \ldots, u_n\) yang menyebar \(\text{Seragam}(0,1)\).
\(x_1, x_2, x_3, \ldots, x_n\) merupakan contoh acak yang saling bebas dari peubah acak \(X\).
Dari PDF ke CDF: Langkah Mendapatkan Fungsi Sebaran Kumulatif
Sebelum menggunakan metode inverse transform, kita perlu mengetahui fungsi distribusi kumulatif (CDF) dari distribusi yang dimaksud. CDF diperoleh dengan mengintegralkan fungsi kepadatan peluang (PDF).
Jika suatu peubah acak kontinu \(X\) memiliki fungsi kepadatan peluang \(f(x)\), maka fungsi distribusi kumulatif \(F(x)\) didefinisikan sebagai:
CDF menggambarkan probabilitas kumulatif bahwa \(X\) bernilai kurang dari atau sama dengan \(x\).
Setelah fungsi \(F(x)\) diperoleh, kita bisa mencari fungsi inversnya \(F^{-1}(u)\), yang diperlukan untuk teknik inverse transform. Bila \(U \sim \text{Unif}(0,1)\), maka:
\[
X = F^{-1}(U)
\]
akan mengikuti distribusi peluang \(F\).
Contoh: Membangkitan dari Distribusi Eksponensial
Misalkan kita ingin membangkitkan bilangan acak dari distribusi eksponensial dengan parameter \(\theta = 2\), yaitu:
# Visualisasiggplot(data_exp, aes(x = x)) +geom_histogram(aes(y =after_stat(density)),fill ="#56B4E9", color ="white", alpha =0.8) +stat_function(fun = dexp, args =list(rate =1/theta),color ="#D55E00", linewidth =0.8) +labs(title =expression("Pembangkitan Acak dari Distribusi Eksponensial"~(theta ==2)),x ="Nilai X",y ="Kepadatan" ) +theme_minimal() +theme(plot.title =element_text(size =14, face ="bold", hjust =0.5))
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Pada grafik di atas, histogram biru merepresentasikan hasil simulasi pembangkitan bilangan acak dari distribusi eksponensial menggunakan metode inverse transform. Sementara itu, kurva Vermilion adalah fungsi kepadatan peluang (PDF) teoritis dari distribusi eksponensial dengan parameter \(\theta = 2\). Keselarasan bentuk histogram dengan kurva PDF menunjukkan bahwa metode inverse transform berhasil menghasilkan data acak yang mengikuti distribusi eksponensial sesuai teori.
Selain menggunakan rumus manual \(X = -\theta \ln(U)\), R juga menyediakan fungsi qexp() yang merupakan invers dari fungsi distribusi kumulatif eksponensial. Jika \(U \sim \text{Unif}(0,1)\), maka qexp(U, rate = 1/theta) akan menghasilkan nilai acak dari distribusi eksponensial dengan parameter \(\theta\). Dengan kata lain, qexp() mengimplementasikan metode inverse transform secara langsung.
set.seed(123)n <-1000theta <-2# Membangkitan langsung dengan qexp()x_exp_qexp <-qexp(runif(n), rate =1/theta)head(x_exp_qexp)
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Contoh: Distribusi dengan PDF Khusus
Sekarang, misalkan kita ingin membangkitkan contoh acak dari sebuah distribusi yang tidak tersedia secara langsung dalam fungsi bawaan R, yaitu dengan fungsi kepadatan peluang:
\[
f(x)=3x^2, \quad 0<x<1
\]
Distribusi ini tidak memiliki fungsi r- bawaan di R, sehingga kita perlu menggunakan metode inverse transform.
Langkah 1: Tentukan Fungsi Distribusi Kumulatif (CDF)
\[
F(x) = \int_{0}^{x} 3t^2 dt= x^3
\]
Langkah 2: Cari Invers dari CDF
Jika \(U \sim \text{Unif}(0,1)\), maka:
\[
F(x) = u \;\Rightarrow\; x^3 = u \;\Rightarrow\; x = u^{\tfrac{1}{3}}
\]
Langkah 3: Rumus Pembangkitan
Dengan demikian, untuk membangkitkan bilangan acak yang mengikuti distribusi \(f(x) = 3x^2\), kita dapat menggunakan:
\[
X = U^{\tfrac{1}{3}}, \quad U \sim \text{Unif}(0,1)
\]
ggplot(data_custom, aes(x = x)) +geom_histogram(aes(y =after_stat(density)),fill ="#56B4E9", color ="white", alpha =0.7) +stat_function(fun =function(x) 3*x^2, color ="#D55E00", linewidth =0.8) +labs(title =expression("Pembangkitan Acak dari"~f(x) ==3*x^2~","~~"0 < x < 1"),x ="Nilai X",y ="Kepadatan" ) +theme_minimal() +theme(plot.title =element_text(size =14, face ="bold", hjust =0.5))
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Pada grafik di atas, histogram biru adalah hasil simulasi pembangkitan acak dengan metode inverse transform, sedangkan kurva Vermilion menunjukkan bentuk teoritis dari \(f(x) = 3x^2\). Keselarasan keduanya menunjukkan bahwa metode inverse transform dapat digunakan untuk membangkitkan distribusi non-standar yang tidak tersedia dalam fungsi bawaan R.
Acceptance-Rejection Method
Konsep Dasar: Metode Acceptance–Rejection digunakan ketika distribusi target sulit atau tidak praktis untuk dibangkitkan langsung dengan inverse transform. Idenya adalah:
Kita pilih distribusi pembangkit yang lebih sederhana (disebut proposal distribution, misalnya uniform atau eksponensial).
Kita bangkitkan data dari distribusi proposal.
Kita terima atau tolak contoh tersebut berdasarkan probabilitas tertentu sehingga contoh yang diterima mengikuti distribusi target.
Prinsip Acceptance–Rejection Method
Misalkan:
\(f(x)\) = PDF target (yang ingin kita bangkitkan).
\(g(x)\) = PDF proposal (mudah dibangkitkan).
\(C>0\) adalah konstanta sehingga
\[
f(x)≤Cg(x), \quad ∀x
\] Algoritma:
Bangkitkan \(Y∼g(x)\).
Bangkitkan \(U∼Unif(0,1)\).
Jika \(U≤\frac{f(Y)}{C\times g(Y)}\) maka terima \(Y\) sebagai sampel dari distribusi target. Jika tidak, tolak \(Y\) dan ulangi.
Gambar di atas memperlihatkan ilustrasi proses Acceptance–Rejection Method untuk membangkitkan sampel dari distribusi Beta(5,12). Kurva hitam merepresentasikan PDF target \(f(x)\), sedangkan garis hijau putus-putus menggambarkan \(Cg(x)\), yaitu distribusi proposal Uniform(0,1) yang telah diskalakan dengan konstanta \(C\) sehingga selalu berada di atas kurva target.
Titik-titik biru (lingkaran) menunjukkan sampel proposal yang diterima karena jatuh di bawah kurva target, sementara titik-titik merah (silang) adalah sampel yang ditolak. Hanya titik-titik yang diterima yang membentuk distribusi sesuai dengan distribusi target Beta(5,12).
Dari visualisasi ini dapat dipahami bahwa meskipun sebagian besar titik proposal ditolak, distribusi akhir dari titik-titik yang diterima akan mengikuti pola distribusi target. Efisiensi metode ini bergantung pada nilai konstanta \(C\); semakin kecil \(C\), semakin banyak titik yang diterima sehingga proses lebih efisien. Namun, jika \(C\) dipilih terlalu kecil, maka ada kemungkinan kurva target \(f(x)\) tidak sepenuhnya berada di bawah \(Cg(x)\). Akibatnya, sebagian sampel valid bisa salah ditolak, dan distribusi yang dihasilkan tidak lagi sesuai dengan target. Sebaliknya, jika \(C\) dipilih terlalu besar, semua sampel memang valid (selalu \(f(x)≤Cg(x)\)), tetapi efisiensi metode menjadi rendah karena proporsi titik yang diterima sangat kecil.
Oleh karena itu, nilai \(C\) biasanya dipilih sebagai nilai maksimum dari rasio \(f(x)/g(x)\).
Contoh: Membangkitkan Data Berdistribusi Beta
Pada contoh ini, kita akan membangkitkan sampel acak dari distribusi Beta(2,2) menggunakan metode Acceptance–Rejection. Distribusi target Beta(2,2) memiliki fungsi kepadatan peluang (PDF) sebagai berikut:
Fungsi ini bersifat simetris dan berbentuk seperti parabola terbalik, dengan puncaknya di tengah interval. Untuk membangkitkan data dengan metode Acceptance–Rejection, diperlukan distribusi proposal \(g(x)\) yang mudah dibangkitkan dan mendominasi \(f(x)\) di seluruh domainnya. Dalam hal ini, digunakan distribusi Uniform(0,1) sebagai proposal, dengan PDF:
\[
g(x)=1, \quad 0<x<1
\]
Selanjutnya, perlu dicari nilai konstanta \(C\) sedemikian hingga \(f(x)≤Cg(x\)) untuk semua \(x∈(0,1)\). Dengan kata lain, kita mencari nilai maksimum dari fungsi rasio berikut:
Dengan menyelesaikan \(\frac{dh}{dx}=0\), diperoleh nilai \(x=\frac{1}{2}\) sebagai titik stasioner. Substitusi kembali ke fungsi \(h(x)\) menghasilkan:
Dengan demikian, konstanta \(C=1.5\). Nilai ini menunjukkan batas atas dari rasio antara fungsi target dan proposal di seluruh domain.
Untuk memverifikasi nilai maksimum tersebut secara numerik, dapat digunakan fungsi optimize() dalam R sebagai berikut:
h <-function(x) 6* x * (1- x)optimize(h, interval =c(0, 1), maximum =TRUE)$objective
[1] 1.5
Hal ini mengonfirmasi bahwa nilai maksimum dari rasio \(\frac{f(x)}{g(x)}\) adalah \(1.5\), yang digunakan sebagai konstanta skala dalam algoritma Acceptance–Rejection.
Note
Penentuan Konstanta Skala ( C )
Dalam praktik komputasi, pendekatan untuk mendapatkan nilai konstanta ( C ) dapat dilakukan dengan mengevaluasi rasio pada grid titik yang rapat (misalnya 1000 titik pada interval ([0,1])). Dengan pemilihan seperti ini, ( C ) cukup besar untuk menjamin kondisi ( f(x) Cg(x) ) selalu terpenuhi, tetapi tidak terlalu besar sehingga tetap menjaga efisiensi proses acceptance–rejection.
set.seed(123)n_iter <-3000# jumlah titik yang dicekalpha <-2beta <-2# Fungsi target: Beta(2,2) → 6x(1-x)f <-function(x) 6* x * (1- x)# Fungsi proposal: Uniform(0,1) → g(x) = 1g <-function(x) 1# Cari konstanta C secara numerikx_seq <-seq(0, 1, length.out =1000)C <-1.5# Simulasi Acceptance–Rejectionaccepted_x <-c()rejected_x <-c()accepted_y <-c()rejected_y <-c()for (i in1:n_iter) { y <-runif(1) # dari proposal u <-runif(1) # uniform(0,1)if (u <=f(y) / (C *g(y))) { accepted_x <-c(accepted_x, y) accepted_y <-c(accepted_y, u * C *g(y)) } else { rejected_x <-c(rejected_x, y) rejected_y <-c(rejected_y, u * C *g(y)) }}# Data untuk titik dan kurvadf_points <-data.frame(x =c(accepted_x, rejected_x),y =c(accepted_y, rejected_y),status =factor(c(rep("Accepted", length(accepted_x)), rep("Rejected", length(rejected_x))),levels =c("Accepted", "Rejected")))df_curve <-data.frame(x = x_seq,target =f(x_seq),proposal = C *g(x_seq))# Plotlibrary(ggplot2)ggplot() +geom_point(data = df_points, aes(x = x, y = y, color = status, shape = status), alpha =0.6) +scale_color_manual(values =c("blue", "red")) +scale_shape_manual(values =c(1, 4)) +geom_line(data = df_curve, aes(x = x, y = target), color ="black", linewidth =0.8) +geom_line(data = df_curve, aes(x = x, y = proposal), color ="darkgreen", linetype ="dashed", linewidth =0.8) +labs(title ="Acceptance-Rejection Method (Target: Beta(2,2))",subtitle =paste0("Total dicek = ", n_iter," | Diterima = ", length(accepted_x)," | Ditolak = ", length(rejected_x)," | Rasio diterima ≈ ", round(length(accepted_x)/n_iter, 3)),x ="x", y ="Kepadatan",color ="Status", shape ="Status" ) +theme_minimal() +theme(plot.title =element_text(face ="bold", size =14, hjust =0.5),plot.subtitle =element_text(size =11, hjust =0.5) )
Jika diperhatikan, banyaknya amatan pada hasil akhir tidak berjumlah sebanyak yang kita inginkan. Hal ini disebabkan karena tidak semua amatan yang dibangkitkan dari distribusi proposal memenuhi kriteria penerimaan (acceptance rule) dalam metode Acceptance–Rejection. Oleh karena itu, jika kita ingin memperoleh tepat 1000 sampel dari distribusi target, maka:
Kita perlu membangkitkan lebih dari 3000 amatan awal, atau
Kita bisa menentukan terlebih dahulu jumlah amatan target (misalnya 3000), lalu melakukan proses pembangkitan dan pengecekan berulang hingga jumlah tersebut tercapai.
Untuk mengevaluasi hasil dari metode Acceptance–Rejection secara visual, kita dapat membandingkan histogram dari sampel yang diterima dengan kurva fungsi kepadatan peluang (PDF) dari distribusi Beta(2,2). Grafik ini memperlihatkan seberapa baik sampel yang dihasilkan mengikuti bentuk distribusi target yang diinginkan.
# Histogram dari sampel yang diterima vs kurva PDF Beta(2,2)data_beta <-data.frame(x = accepted_x)ggplot(data_beta, aes(x = x)) +geom_histogram(aes(y =after_stat(density)),bins =40, fill ="#56B4E9", color ="white", alpha =0.7) +stat_function(fun = dbeta, args =list(shape1 = alpha, shape2 = beta),color ="#D55E00", linewidth =0.8) +labs(title =expression("Histogram Sampel Diterima vs PDF Beta(2,2)"),x ="x",y ="Kepadatan" ) +theme_minimal() +theme(plot.title =element_text(size =14, face ="bold", hjust =0.5))
Contoh: Membangkitkan Data Berdistribusi Gamma
Misalkan kita ingin membangkitkan data sebanyak 100 dari distribusi \(X \sim \text{Gamma}(\alpha=3, \beta=2)\) dengan PDF:
# Plotggplot() +geom_point(data = df_points, aes(x = x, y = y, color = accepted, shape = accepted),alpha =0.5, size =1.2) +scale_color_manual(values =c("red", "blue"), labels =c("Rejected", "Accepted")) +scale_shape_manual(values =c(4, 1), labels =c("Rejected", "Accepted")) +geom_line(data = df_curves, aes(x = x, y = target), color ="black", linewidth =0.8) +geom_line(data = df_curves, aes(x = x, y = proposal), color ="darkgreen", linetype ="dashed", linewidth =0.8) +labs(title ="Acceptance-Rejection Method (Target: Gamma(3,2))",subtitle =paste0("Total iterasi = ", total_iter," | Total diterima = ", total_accept," | Total ditolak = ", total_reject),x ="x", y ="Density",color ="Status", shape ="Status" ) +coord_cartesian(xlim =c(0, 20)) +theme_minimal() +theme(plot.title =element_text(size =14, face ="bold", hjust =0.5),plot.subtitle =element_text(size =11, hjust =0.5))
Pada visualisasi diatas, terlihat bahwa sebaran titik hasil proposal didominasi oleh titik-titik yang ditolak. Karena jumlah sampel ditolak sangat besar, sumbu-y secara otomatis menyesuaikan ke nilai maksimum dari proposal \(Cg(x)\). Akibatnya, kurva target Gamma(3,2) dan titik-titik accepted (biru) tampak kecil dan kurang jelas.
Untuk mengatasi hal ini, kita perlu membatasi rentang sumbu-y agar fokus pada area di sekitar kurva target. Dengan cara ini, bentuk distribusi target serta titik-titik accepted akan lebih mudah terlihat tanpa “tertutup” oleh skala yang terlalu besar akibat titik rejected.
# Ploty_max <-max(df_curves$target) *1.2ggplot() +geom_point(data = df_points, aes(x = x, y = y, color = accepted, shape = accepted),alpha =0.5, size =1.2) +scale_color_manual(values =c("red", "blue"), labels =c("Rejected", "Accepted")) +scale_shape_manual(values =c(4, 1), labels =c("Rejected", "Accepted")) +geom_line(data = df_curves, aes(x = x, y = target), color ="black", linewidth =0.8) +geom_line(data = df_curves, aes(x = x, y = proposal), color ="darkgreen", linetype ="dashed", linewidth =0.8) +labs(title ="Acceptance-Rejection Method (Target: Gamma(3,2))",subtitle =paste0("Total iterasi = ", total_iter," | Total diterima = ", total_accept," | Total ditolak = ", total_reject),x ="x", y ="Density",color ="Status", shape ="Status" ) +coord_cartesian(xlim =c(0, 20), ylim =c(0, y_max)) +theme_minimal() +theme(plot.title =element_text(size =14, face ="bold", hjust =0.5),plot.subtitle =element_text(size =11, hjust =0.5))
# Data hanya dari sampel accepteddata_gamma <-data.frame(x = accepted_x)# Histogram vs PDF targetggplot(data_gamma, aes(x = x)) +geom_histogram(aes(y =after_stat(density)),fill ="#56B4E9", color ="white", alpha =0.7) +stat_function(fun = dgamma, args =list(shape = alpha, scale = beta),color ="#D55E00", linewidth =0.8) +labs(title ="Histogram Sampel Accepted vs PDF Gamma(3,2)",x ="x",y ="Density" ) +theme_minimal() +theme(plot.title =element_text(size =14, face ="bold", hjust =0.5))
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Histogram di atas memperlihatkan distribusi dari sampel yang diterima hasil metode Acceptance–Rejection untuk target distribusi Gamma(3,2). Histogram biru menunjukkan sebaran data simulasi, sedangkan kurva oranye merepresentasikan fungsi kepadatan peluang (PDF) teoretis Gamma(3,2).
Meskipun jumlah sampel yang diterima relatif sedikit (hanya 100), pola histogram sudah mulai mengikuti bentuk kurva target: naik di awal, mencapai puncak di sekitar nilai 4–5, kemudian menurun secara eksponensial. Jika jumlah sampel diterima diperbesar (misalnya 2000 atau lebih), bentuk histogram akan semakin halus dan mendekati kurva PDF teoretis.
Hal ini menunjukkan bahwa metode Acceptance–Rejection berhasil menghasilkan data acak yang distribusinya konsisten dengan distribusi target, meskipun efisiensinya sangat dipengaruhi oleh pemilihan konstanta \(C\) dan distribusi proposal \(g(x)\).
Contoh: Membangkitkan Data Berdistribusi Normal(0,1)
Distribusi target yang ingin dibangkitkan adalah distribusi Normal standar (\(X \sim N(\mu=0, \sigma^2=1)\)) , dengan fungsi kepadatan peluang \[
f(x) = \dfrac{1}{\sqrt{2\pi}} e^{- \frac{x^2}{2}}, \quad -\infty< x < \infty
\]
Kita pilih distribusi proposal yang lebih sederhana. Dalam hal ini digunakan distribusi seragam pada interval \([−5,5]\), dengan fungsi kepadatan peluang
Kita memerlukan suatu konstanta C>0 yang menjamin bahwa kurva target selalu berada di bawah kurva proposal yang telah diskalakan, atau dengan kata lain
# Data hanya dari sampel accepteddata_norm_ar <-data.frame(x = accepted_x)# Histogram vs PDF target Normal(0,1)ggplot(data_norm_ar, aes(x = x)) +geom_histogram(aes(y =after_stat(density)),fill ="#56B4E9", color ="white", alpha =0.7) +stat_function(fun = dnorm, args =list(mean = mu, sd = sigma),color ="#D55E00", linewidth =0.8) +labs(title ="Histogram Sampel Accepted vs PDF Normal(0,1)",x ="x",y ="Density" ) +theme_minimal() +theme(plot.title =element_text(size =14, face ="bold", hjust =0.5))
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Histogram biru menunjukkan distribusi sampel yang diterima dari proses Acceptance–Rejection, sedangkan kurva vermilion adalah fungsi kepadatan peluang Normal(0,1). Dengan jumlah sampel yang cukup (misalnya 1000 atau lebih), histogram terlihat semakin mendekati bentuk kurva Normal standar. Hal ini membuktikan bahwa metode Acceptance–Rejection mampu menghasilkan data acak yang distribusinya sesuai dengan distribusi target meskipun menggunakan proposal sederhana seperti Uniform(-5,5).
Setelah melihat bagaimana metode Acceptance–Rejection dapat digunakan untuk membangkitkan sampel dari distribusi Normal(0,1), langkah selanjutnya adalah memahami pengaruh ukuran sampel terhadap hasil simulasi. Jumlah sampel yang diterima sangat menentukan seberapa halus histogram hasil simulasi dibandingkan dengan bentuk teoretis distribusi target. Dengan jumlah sampel yang kecil, histogram cenderung kasar dan tidak sepenuhnya mencerminkan pola distribusi target. Sebaliknya, semakin banyak sampel yang diterima, semakin baik pula histogram mendekati kurva kepadatan peluang (PDF) teoretis. Untuk mengilustrasikan hal ini, mari kita bandingkan hasil Acceptance–Rejection dengan jumlah sampel diterima sebanyak \(n=100\) dan \(n=2000\).
set.seed(123)mu <-0sigma <-1# Target dan proposalf <-function(x) dnorm(x, mean = mu, sd = sigma)g <-function(x) dunif(x, min =-5, max =5)# Fungsi AR untuk menghasilkan n_target sampelAR_sampler <-function(n_target, f, g){# Cari konstanta C x_seq <-seq(-5, 5, length.out =2000) C <-max(f(x_seq) /g(x_seq)) accepted_x <-c()while(length(accepted_x) < n_target){ y <-runif(1, min =-5, max =5) # proposal u <-runif(1)if(u <=f(y)/(C*g(y))){ accepted_x <-c(accepted_x, y) } }return(accepted_x)}# Bangkitkan dataaccepted_100 <-AR_sampler(100, f, g)accepted_2000 <-AR_sampler(2000, f, g)# Buat data frame gabungandf_hist <-data.frame(x =c(accepted_100, accepted_2000),Sampel =c(rep("n = 100", length(accepted_100)),rep("n = 2000", length(accepted_2000))))# Plot histogram berdampinganggplot(df_hist, aes(x = x)) +geom_histogram(aes(y =after_stat(density)),fill ="#56B4E9", color ="white", alpha =0.7) +stat_function(fun = dnorm, args =list(mean = mu, sd = sigma),color ="#D55E00", linewidth =0.8) +facet_wrap(~ Sampel, ncol =2) +labs(title ="Perbandingan jumlah sampel n=100 dan n=2000",x ="x",y ="Density" ) +theme_minimal() +theme(plot.title =element_text(size =14, face ="bold", hjust =0.5),plot.subtitle =element_text(size =11, hjust =0.5) )
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Pada gambar di atas ditampilkan hasil simulasi distribusi Normal(0,1) dengan metode Acceptance–Rejection untuk dua ukuran sampel yang berbeda. Panel kiri menunjukkan histogram dari \(n=100\) sampel yang diterima, sedangkan panel kanan memperlihatkan histogram dari \(n=2000\) sampel.
Dapat dilihat bahwa ketika jumlah sampel relatif kecil (\(n=100\)), histogram masih terlihat kasar, bergelombang, dan belum sepenuhnya mengikuti bentuk kurva teoretis (garis merah). Namun, ketika jumlah sampel diperbesar (\(n=2000\)), histogram semakin halus dan bentuknya jauh lebih menyerupai kurva kepadatan peluang Normal standar.
Hal ini menegaskan prinsip dasar simulasi Monte Carlo: semakin banyak sampel yang dibangkitkan, semakin baik distribusi hasil simulasi mendekati distribusi target yang sebenarnya. Materi Monte Carlo akan dibahas pada pertemuan lainnya.
Acceptance–Rejection untuk Distribusi dengan PDF Khusus
Pada praktiknya, tidak semua distribusi target memiliki fungsi r- bawaan di R atau atau merupakan distribusi standar yang sudah dikenal namanya. Ada kalanya kita hanya mengetahui bentuk fungsi kepadatan peluang (PDF), tetapi distribusi tersebut tidak memiliki nama khusus atau tidak tersedia fungsi pembangkitnya di perangkat lunak statistik. Dalam situasi seperti ini, metode Acceptance–Rejection sangat berguna karena tetap memungkinkan kita membangkitkan sampel acak hanya berdasarkan bentuk PDF target yang diketahui.
Sebagai ilustrasi, Misalkan target distribusi acak kita memiliki fungsi kepadatan peluang:
Distribusi ini tidak memiliki nama khusus dalam literatur statistik, tetapi merupakan PDF valid karena memenuhi dua syarat: 1. \(f(x)≥0\) untuk semua \(x∈[0,1]\), 2. \(\int_{0}^{1} f(x)\,dx=1\)
Proposal yang sesuai adalah distribusi Uniform(0,1):
\[
g(x)=1, \quad 0≤x≤1
\] Dengan proposal sederhana ini, konstanta \(C\) diperoleh dari:
Karena \(g(x)=1\), maka \(C\) cukup dicari dengan menghitung maksimum fungsi \(f(x)\) pada interval [0,1]. Setelah itu, algoritma Acceptance–Rejection dapat digunakan untuk menghasilkan sampel dari distribusi target polinomial ini.
# Histogram sampel accepted vs PDF targetdf_accept <-data.frame(x = accepted_x)ggplot(df_accept, aes(x)) +geom_histogram(aes(y=after_stat(density)),bins =30, fill="#56B4E9", color="white", alpha=0.7) +stat_function(fun = f, color="#D55E00", linewidth=0.8) +labs(title =expression("Histogram Sampel Accepted vs"~~f(x) ==frac(3, 2)*x^3+frac(11, 8)*x^2+frac(1, 6)*x +frac(1, 12)),x ="x", y ="Density" ) +theme_minimal() +theme(plot.title=element_text(size=14, face="bold", hjust=0.5))
Hasil visualisasi pada histogram menunjukkan bahwa sampel yang dihasilkan melalui metode Acceptance–Rejection mengikuti bentuk distribusi target yang telah ditentukan. Histogram biru yang merepresentasikan sebaran sampel acak memperlihatkan kesesuaian dengan kurva fungsi kepadatan peluang (PDF) target yang digambarkan oleh garis oranye. Hal ini menegaskan bahwa metode Acceptance–Rejection mampu menghasilkan sampel yang mendekati distribusi target, meskipun distribusi tersebut tidak memiliki nama standar atau fungsi pembangkit bawaan dalam perangkat lunak statistik. Seiring dengan bertambahnya jumlah sampel, bentuk histogram cenderung semakin halus dan semakin mendekati kurva teoritis, sehingga akurasi pendekatan distribusi semakin baik. Perbandingan antara histogram dengan jumlah sampel \(n=2000\) dan \(n=100000\) ditampilkan pada gambar di bawah untuk memperlihatkan pengaruh ukuran sampel terhadap kualitas pendekatan distribusi.
# Target PDF: polinomialf <-function(x) { (3/2)*x^3+ (11/8)*x^2+ (1/6)*x + (1/12)}# Proposal: Uniform(0,1)g <-function(x) dunif(x, min=0, max=1)# Fungsi AR untuk menghasilkan n_target sampelAR_sampler <-function(n_target, f, g){ x_seq <-seq(0, 1, length.out =2000) C <-max(f(x_seq) /g(x_seq)) accepted_x <-c()while(length(accepted_x) < n_target){ y <-runif(1, min=0, max=1) # proposal u <-runif(1)if(u <=f(y)/(C*g(y))){ accepted_x <-c(accepted_x, y) } }return(accepted_x)}# Bangkitkan dataset.seed(123)accepted_2000 <-AR_sampler(2000, f, g)accepted_100000 <-AR_sampler(100000, f, g)# Buat data frame gabungandf_hist <-data.frame(x =c(accepted_2000, accepted_100000),Sampel =c(rep("n = 2000", length(accepted_2000)),rep("n = 100000", length(accepted_100000))))# Plot histogram berdampinganggplot(df_hist, aes(x = x)) +geom_histogram(aes(y =after_stat(density)),bins =30, fill ="#56B4E9", color ="white", alpha =0.7) +stat_function(fun = f, color ="#D55E00", linewidth =0.8) +facet_wrap(~ Sampel, ncol =2) +labs(title ="Perbandingan jumlah sampel n=2000 dan n=100000",x ="x",y ="Density" ) +theme_minimal() +theme(plot.title =element_text(size =14, face ="bold", hjust =0.5),plot.subtitle =element_text(size =11, hjust =0.5) )
Direct Transform Method
Metode Direct Transform digunakan untuk membangkitkan sampel acak dari distribusi target dengan cara mentransformasi peubah acak lain yang lebih sederhana. Teknik ini memanfaatkan sifat-sifat hubungan antar distribusi dalam teori probabilitas. Dengan demikian, pembangkitan tidak lagi melalui inversi fungsi distribusi kumulatif atau prosedur acceptance–rejection, melainkan melalui transformasi langsung dari distribusi yang sudah diketahui algoritma pembangkitannya. Diagram berikut memperlihatkan hubungan matematis antara berbagai distribusi peluang.
Contoh: Normal dari Dua Uniform (Metode Box-Muller)
Jika \(U_1, U_2 \sim \text{Unif}(0,1)\), maka kita bisa membangkitkan dua variabel normal independen \(Z_1, Z_2 \sim \mathcal{N}(0,1)\) menggunakan Transformasi Box-Muller:
ggplot(data_f, aes(x = x)) +geom_histogram(aes(y =after_stat(density)),bins =60, fill ="#56B4E9", color ="white", alpha =0.7) +stat_function(fun = df, args =list(df1 = df1, df2 = df2),color ="#D55E00", linewidth =0.8) +labs(title =bquote("Distribusi"~F(.(df1),~.(df2))~"dari Dua"~chi^2),x ="F", y ="Kepadatan" ) +theme_minimal() +theme(plot.title =element_text(hjust =0.5, face ="bold"))
Multivariate Normal Distribution
Distribusi Normal Multivariat (Multivariate Normal Distribution, MND) adalah generalisasi dari distribusi Normal univariat ke dimensi lebih tinggi. Sebuah vektor acak berdimensi \(p\) dikatakan berdistribusi normal multivariat jika setiap kombinasi linear dari komponennya mengikuti distribusi Normal univariat.
Misalkan \(\mathbf{X}\) adalah vektor acak berdimensi \(p\):
Pembangkitan bilangan acak dari distribusi \(\mathcal{N}_d(\boldsymbol{\mu}, \boldsymbol{\Sigma})\) dilakukan dalam dua tahap utama
Pertama, kita membangkitkan vektor acak standar. Bangkitkan vektor \(\mathbf{Z} = (Z_1, Z_2, \dots, Z_d)\) dari distribusi Normal standar multivariat \(\mathcal{N}_d(\mathbf{0}, \mathbf{I})\).
Kedua, kita melakukan transformasi linear Transformasi vektor \(\mathbf{Z}\) menggunakan rata-rata \(\boldsymbol{\mu}_d\) dan matriks kovarians \(\boldsymbol{\Sigma}\) yang diinginkan:
dengan \(C\) merupakan matriks faktor kovarians sedemikian hingga:
\[
\boldsymbol{\Sigma} = C C^\top
\]
Pemfaktoran \(\boldsymbol{\Sigma}\) dapat dilakukan melalui beberapa metode dekomposisi matriks:
Dekomposisi Eigen: eigen() di R
Dekomposisi Cholesky: chol() di R (paling umum jika \(\Sigma\) positif-definit)
Dekomposisi Singular Value (SVD): svd() di R (jika matriks singular atau numerik tidak stabil)
Dekomposisi Eigen
Dekomposisi eigen digunakan untuk membentuk transformasi linear terhadap vektor acak \(\mathbf{Z} \sim \mathcal{N}_d(\mathbf{0}, \mathbf{I})\) sehingga menghasilkan vektor \(\mathbf{X} \sim \mathcal{N}_d(\boldsymbol{\mu}, \boldsymbol{\Sigma})\).
Jika \(\boldsymbol{\Sigma}\) adalah matriks kovarians simetris dan semi-definit positif, maka ia dapat didekomposisi sebagai:
\[
\boldsymbol{\Sigma} = V \Lambda V^\top
\]
dengan:
\(V\): matriks eigenvektor (\(d \times d\)), bersifat ortonormal
\(\Lambda\): matriks diagonal yang berisi nilai eigen positif (akar variansi)
Dari sini, kita dapat membentuk matriks akar kovarians \(\mathbf{C}\) sebagai:
\[
C = V \Lambda^{1/2}
\]
Transformasi ke vektor target dilakukan dengan:
\[
\mathbf{X} = C \mathbf{Z} + \boldsymbol{\mu} = V \Lambda^{1/2} \mathbf{Z} + \boldsymbol{\mu}
\]
# Fungsi untuk membangkitkan multivariate normal dengan dekomposisi eigenrmvn.eigen <-function(n, mu, Sigma) { d <-length(mu) # Dimensi ev <-eigen(Sigma, symmetric =TRUE) # Dekomposisi eigen lambda <- ev$values # Nilai eigen (varians) V <- ev$vectors # Matriks eigenvektor R <- V %*%diag(sqrt(lambda)) %*%t(V) # Matriks akar kovarians Z <-matrix(rnorm(n * d), nrow = n, ncol = d) # Sampel acak standar X <- Z %*% R +matrix(mu, n, d, byrow =TRUE) # Transformasi ke distribusi targetreturn(X)}
Nilai mean dari data hasil simulasi sangat dekat dengan nilai teoritis (0, 0). Penyimpangan kecil ini wajar terjadi karena sifat acak simulasi (sample error).
Nilai korelasi empiris antara dua variabel X1 dan X2 adalah 0.915, mendekati nilai target 0.9.
Dekomposisi Cholesky
Dekomposisi Cholesky adalah metode untuk memfaktorkan matriks kovarians yang simetris dan positif-definit \(\boldsymbol{\Sigma}\) menjadi hasil perkalian dua matriks segitiga:
\[
\boldsymbol{\Sigma} = LL^\top
\]
di mana:
\(L\) adalah matriks segitiga bawah berdimensi \(d\times d\),
\(L^\top\) adalah transpose dari \(L\)
Seluruh elemen diagonal dari \(L\) bernilai positif.
Agar dekomposisi ini valid, matriks \(\boldsymbol{\Sigma}\) harus memenuhi dua syarat:
Dengan dekomposisi Cholesky, akar kovarians tersebut diperoleh dari \(\boldsymbol{C} = L\) sehingga \(\boldsymbol{\Sigma} = CC^\top=LL^\top\)
# Fungsi untuk membangkitkan multivariate normal dengan dekomposisi Choleskyrmvn.chol <-function(n, mu, Sigma) { d <-length(mu) L <-chol(Sigma) # Transpos dari hasil chol() agar berbentuk segitiga bawah Z <-matrix(rnorm(n * d), nrow = n, ncol = d) X <- Z %*% L +matrix(mu, n, d, byrow =TRUE)return(X)}
Dekomposisi Singular Value (SVD) adalah metode numerik yang sangat stabil dan umum digunakan dalam berbagai aplikasi aljabar linier, termasuk pembangkitan bilangan acak dari distribusi normal multivariat.
Jika \(\boldsymbol{\Sigma}\) adalah matriks kovarians simetris dan semi-definit positif berdimensi \(d \times d\), maka dapat dilakukan dekomposisi SVD sebagai berikut:
\[
\boldsymbol{\Sigma} = UDU^\top
\]
dengan:
\(U\): matriks ortogonal berisi vektor singular kiri (untuk matriks simetris positif-definit, \(U\) sama dengan matriks eigenvektor),
\(D\): matriks diagonal berisi nilai singular positif (sama dengan nilai eigen jika \(\boldsymbol{\Sigma}\) simetris positif-definit).
Dari dekomposisi tersebut, kita bentuk akar kovarians sebagai:
\[
\mathbf{C} = \mathbf{U} \mathbf{D}^{1/2} \mathbf{U}^\top
\] Sehingga transformasi dari vektor acak standar \(Z \sim \mathcal{N}_d(\boldsymbol{\mu}, \boldsymbol{I})\) menjadi:
\[
\mathbf{X} = C \mathbf{Z} + \boldsymbol{\mu} = UD^{1/2}U \mathbf{Z} + \boldsymbol{\mu}
\] dengan hasil akhir \(X \sim \mathcal{N}_d(\boldsymbol{\mu}, \boldsymbol{\Sigma})\).
# Fungsi untuk membangkitkan multivariate normal dengan dekomposisi SVDrmvn.svd <-function(n, mu, Sigma) { d <-length(mu) sv <-svd(Sigma) # Dekomposisi SVD U <- sv$u D <- sv$d C <- U %*%diag(sqrt(D)) %*%t(U) # Matriks akar kovarians simetris Z <-matrix(rnorm(n * d), nrow = n, ncol = d) # Sampel acak standar X <- Z %*% C +matrix(mu, n, d, byrow =TRUE) # Transformasireturn(X)}
Pada R, telah tersedia library MASS yang menyediakan berbagai fungsi statistik klasik, salah satunya adalah mvrnorm() yang digunakan untuk membangkitkan data dari distribusi Normal multivariat. Untuk menggunakan fungsi ini, kita perlu terlebih dahulu memuat library MASS berikut:
library(MASS)
Attaching package: 'MASS'
The following object is masked from 'package:dplyr':
select
Fungsi mvrnorm(n, mu, Sigma) digunakan untuk menghasilkan n observasi dari distribusi \(\mathcal{N}_p(\boldsymbol{\mu}, \boldsymbol{\Sigma})\), dengan:
Parameter tambahan empirical = TRUE memaksa hasil simulasi memiliki rata-rata dan kovarians sampel yang persis sama dengan nilai mu dan Sigma. Hal ini bermanfaat jika ingin memastikan struktur statistik eksak dari data simulasi.
set.seed(123)# Parameter distribusimu <-c(0, 0)Sigma <-matrix(c(1, 0.8,0.8, 1), nrow =2, byrow =TRUE)# Simulasi 100 observasi dari distribusi Normal multivariatsim_data2 <-mvrnorm(n =100000, mu = mu, Sigma = Sigma, empirical =TRUE)
colMeans(sim_data2) # Harus mendekati mu
[1] -2.304122e-17 -2.770374e-17
cov(sim_data2) # Harus mendekati Sigma
[,1] [,2]
[1,] 1.0 0.8
[2,] 0.8 1.0
cor(sim_data2) # Harus mendekati 0.9
[,1] [,2]
[1,] 1.0 0.8
[2,] 0.8 1.0
Pembangkitan Bilangan Acak untuk Regresi Linier
Dalam analisis regresi, sering kali kita memerlukan data simulasi untuk menguji performa metode estimasi, validasi model, atau tujuan pembelajaran. Data ini dapat dibangkitkan secara acak berdasarkan model regresi linear yang kita tentukan.
Model Regresi Linier Sederhana
Model regresi linear sederhana:
\[
Y=\beta_0+\beta_1X_1+\mu
\] dengan:
\(Y\): peubah respon,
\(X\): peubah penjelas,
\(\beta_0, \beta_1\): parameter regresi,
\(\varepsilon \sim \mathcal{N}(0, \sigma^2)\): error acak berdistribusi Normal.
Semisal, kita ingin membangkitkan data simulasi yang mengikuti model regresi linear dengan:
Intersep \(\beta_0 = 5\),
Koefisien slope \(\beta_1 = 2\),
Error acak mengikuti distribusi Normal dengan rata-rata 0 dan simpangan baku \(\sigma = 1\).
Untuk membangkitkan data simulasi sebanyak \(n = 1000\) observasi, kita dapat memilih nilai prediktor \(X\) dari distribusi tertentu (misalnya seragam/Uniform), lalu menghitung nilai \(Y\) berdasarkan rumus model dengan menambahkan error acak.
set.seed(123)# Tentukan parametern <-1000# Jumlah observasibeta0 <-5# Intersepbeta1 <-2# Koefisien slopesigma <-1# Simpangan baku error# Bangkitkan X ~ Uniform(0, 10)x <-runif(n, min =0, max =10)# Bangkitkan error ~ N(0, sigma^2)epsilon <-rnorm(n, mean =0, sd = sigma)# Hitung Yy <- beta0 + beta1 * x + epsilon# Gabungkan ke dalam data framedata_regresi <-data.frame(x = x, y = y)
Kita dapat memvisualisasikan data hasil simulasi dalam bentuk scatter plot:
Setelah memperoleh data simulasi, kita bisa mengestimasi parameter \(\beta_0\) dan \(\beta_1\) (diestimasi dengan \(\hat{\beta}_0\) dan \(\hat{\beta}_1\)) menggunakan fungsi lm():
model_lm <-lm(y ~ x, data = data_regresi)summary(model_lm)
Call:
lm(formula = y ~ x, data = data_regresi)
Residuals:
Min 1Q Median 3Q Max
-2.8431 -0.7007 0.0136 0.6558 3.4072
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 5.04094 0.06333 79.6 <2e-16 ***
x 1.99417 0.01103 180.9 <2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 1.002 on 998 degrees of freedom
Multiple R-squared: 0.9704, Adjusted R-squared: 0.9704
F-statistic: 3.271e+04 on 1 and 998 DF, p-value: < 2.2e-16
Perhatikan bahwa hasil estimasi Intercept dan x dalam output summary() seharusnya mendekati nilai parameter sebenarnya, yaitu \(\beta_0 = 5\) dan \(\beta_1 = 2\), dengan sedikit variasi akibat pengaruh error acak.
# Visualisasi 2: Scatter plot + garis regresi dari hasil lm()ggplot(data_regresi, aes(x = x, y = y)) +geom_point(aes(color ="Data Simulasi"), alpha =0.7) +geom_abline(aes(intercept =coef(model_lm)[1],slope =coef(model_lm)[2],color ="Garis Regresi (Hasil Estimasi)"),linewidth =0.8) +scale_color_manual(name ="Keterangan",values =c("Data Simulasi"="#56B4E9", "Garis Regresi (Hasil Estimasi)"="#D55E00") ) +labs(title ="Garis Regresi dari Hasil Estimasi Model Linier",x ="X",y ="Y" ) +theme_minimal() +theme(plot.title =element_text(hjust =0.5, face ="bold"),legend.position ="right" )
Terkadang, kita ingin mengetahui bagaimana hasil estimasi parameter regresi berubah-ubah ketika data dibangkitkan ulang berkali-kali dalam kondisi yang sama. Pendekatan ini membantu mengevaluasi rata-rata (bias) dan keragaman (variabilitas) dari estimator parameter.
Misalnya, kita ingin mengevaluasi kestabilan hasil estimasi dari model regresi sederhana melalui simulasi sebanyak 100 kali, dengan skenario sebagai berikut:
Ukuran sampel kecil (\(n = 10\)),
Intersep sebenarnya \(\beta_0 = 5\), slope \(\beta_1 = 2\),
Error acak mengikuti distribusi Normal: \(\varepsilon \sim \mathcal{N}(0, 1)\),
Prediktor \(X\) diambil dari distribusi Uniform(5, 10).
set.seed(123)# Parameter simulasin_simulasi <-100n_obs <-10beta0 <-5beta1 <-2sigma <-1# Vektor untuk menyimpan hasil estimasib0_hat <-numeric(n_simulasi)b1_hat <-numeric(n_simulasi)# Simulasi berulang 100 kalifor (i in1:n_simulasi) { x <-runif(n_obs, min =5, max =10) eps <-rnorm(n_obs, mean =0, sd = sigma) y <- beta0 + beta1 * x + eps model <-lm(y ~ x) b0_hat[i] <-coef(model)[1] b1_hat[i] <-coef(model)[2]}# Ringkasan hasilhasil_simulasi <-data.frame(Estimator =c("Intercept (b0)", "Slope (b1)"),Mean =c(mean(b0_hat), mean(b1_hat)),SD =c(sd(b0_hat), sd(b1_hat)))hasil_simulasi
Setelah melakukan simulasi berulang sebanyak 100 kali, kita memperoleh 100 nilai estimasi untuk masing-masing parameter regresi, yaitu intersep (\(\beta_0\)) dan slope (\(\beta_1\)). Nilai-nilai estimasi ini dapat bervariasi karena adanya komponen error acak (\(\varepsilon\)) dalam setiap replikasi data.
Untuk memahami sebaran, bias, dan stabilitas estimasi parameter yang dihasilkan dari proses simulasi tersebut, kita dapat menggunakan boxplot. Visualisasi ini memberikan gambaran ringkas mengenai:
Letak pusat estimasi (median dan mean secara kasar),
Sebaran estimasi (varians),
Potensi outlier,
Apakah hasil estimasi cenderung bias terhadap parameter sebenarnya.
Dengan boxplot, kita bisa dengan cepat melihat apakah estimasi parameter regresi konsisten dan mendekati nilai sebenarnya (\(\beta_0 = 5\), \(\beta_1 = 2\)) dalam konteks simulasi.
# Buat data boxplotdf_boxplot <-data.frame(Estimator =factor(rep(c("Intercept (b0)", "Slope (b1)"), each = n_simulasi)),Nilai =c(b0_hat, b1_hat))ggplot(df_boxplot, aes(x = Estimator, y = Nilai, fill = Estimator)) +geom_boxplot(alpha =0.8, width =0.5, outlier.shape =16, outlier.size =1.5) +# Garis horizontal untuk nilai sebenarnyageom_hline(aes(yintercept =5, color ="beta0"),linetype ="dashed", linewidth =0.8) +geom_hline(aes(yintercept =2, color ="beta1"),linetype ="dashed", linewidth =0.8) +scale_color_manual(name =NULL,values =c("beta0"="#FF6666", "beta1"="#66CC66"),labels =c("beta0"=expression("True value of "* beta[0]),"beta1"=expression("True value of "* beta[1]) ) ) +# Warna boxplot tanpa legendscale_fill_manual(values =c("Intercept (b0)"="#56B4E9", "Slope (b1)"="#D55E00"),guide ="none"# Hapus legend fill ) +labs(title ="Variabilitas Estimator Parameter Regresi dari 100 Simulasi",x =NULL,y ="Nilai Estimasi" ) +theme_minimal() +theme(plot.title =element_text(hjust =0.5, face ="bold"),legend.position ="right" )
Model Regresi Linier Berganda
Model regresi linier berganda merupakan perluasan dari regresi linier sederhana dengan melibatkan lebih dari satu peubah penjelas:
Error acak \(\varepsilon \sim \mathcal{N}(0, 1)\).
set.seed(123)# Parametern <-1000beta0 <-3beta1 <-1.5beta2 <--2sigma <-1# Bangkitkan peubah penjelasx1 <-runif(n, min =0, max =10) # X1 ~ Uniformx2 <-rnorm(n, mean =5, sd =2) # X2 ~ Normal# Errorepsilon <-rnorm(n, mean =0, sd = sigma)# Respon Yy <- beta0 + beta1 * x1 + beta2 * x2 + epsilon# Gabungkan ke dalam data framedata_regresi_ganda <-data.frame(x1 = x1, x2 = x2, y = y)# Estimasi modelmodel_ganda <-lm(y ~ x1 + x2, data = data_regresi_ganda)# Output modelsummary(model_ganda)
Call:
lm(formula = y ~ x1 + x2, data = data_regresi_ganda)
Residuals:
Min 1Q Median 3Q Max
-2.9879 -0.6392 -0.0180 0.6932 3.2486
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 2.92260 0.10044 29.1 <2e-16 ***
x1 1.48509 0.01082 137.3 <2e-16 ***
x2 -1.97037 0.01553 -126.9 <2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.983 on 997 degrees of freedom
Multiple R-squared: 0.9727, Adjusted R-squared: 0.9727
F-statistic: 1.776e+04 on 2 and 997 DF, p-value: < 2.2e-16
Seperti sebelumnya, kita ingin mengetahui bagaimana estimasi \(\hat{\beta}_0\), \(\hat{\beta}_1\), dan \(\hat{\beta}_2\) berubah saat model dibangkitkan ulang sebanyak 100 kali dengan kondisi yang sama. Pendekatan ini membantu mengevaluasi rata-rata, sebaran, dan potensi bias dari setiap estimator dalam regresi linier berganda.
df_box_ganda <-data.frame(Estimator =factor(rep(c("Intercept (b0)", "Slope X1 (b1)", "Slope X2 (b2)"), each = n_simulasi)),Nilai =c(b0_hat, b1_hat, b2_hat))ggplot(df_box_ganda, aes(x = Estimator, y = Nilai, fill = Estimator)) +geom_boxplot(alpha =0.8, outlier.shape =16, outlier.size =1.5) +geom_hline(aes(yintercept =3, color ="b0"), linetype ="dashed", linewidth =0.8) +geom_hline(aes(yintercept =1.5, color ="b1"), linetype ="dashed", linewidth =0.8) +geom_hline(aes(yintercept =-2, color ="b2"), linetype ="dashed", linewidth =0.8) +scale_color_manual(name =NULL,values =c("b0"="#009E73","b1"="#D55E00","b2"="#0072B2" ),labels =c("b0"=expression("True value of "* beta[0]),"b1"=expression("True value of "* beta[1]),"b2"=expression("True value of "* beta[2]) ) ) +# Warna boxplot (tanpa legend)scale_fill_manual(values =c("#E69F00", "#56B4E9", "#009E73"),guide ="none" ) +labs(title ="Variabilitas Estimator Parameter pada Regresi Linier Berganda",x =NULL,y ="Nilai Estimasi" ) +theme_minimal() +theme(plot.title =element_text(hjust =0.5, face ="bold"),legend.position ="right" )
Pada contoh sebelumnya, peubah penjelas \(X_1\) dan \(X_2\) dibangkitkan secara independen. Dalam kenyataannya, peubah penjelas sering kali saling berkorelasi, misalnya pendapatan dan pengeluaran rumah tangga. Untuk merepresentasikan kondisi tersebut, kita dapat membangkitkan \(X_1\) dan \(X_2\) dari distribusi Normal multivariat dengan kovarians tidak nol.
Model yang digunakan:
\[
Y=\beta_0+\beta_1X_1+\beta_2X_2+\mu
\]
dengan:
\(\beta_0 = 3, \beta_1 = 1.5, \beta_2 = -2\),
\((X_1, X_2) \sim \mathcal{N}(\mu, \Sigma)\) dengan