1. Simulasi \(E[X^2]\) untuk \(X \sim \mathcal{U}(0, 1)\)

set.seed(123)
x <- runif(10000, 0, 1)
ex2_est <- mean(x^2)
ex2_est
## [1] 0.3297405

Telah dilakukan simulasi untuk menghitung nilai ekspektasi dari kuadrat variabel acak X yang berdistribusi Uniform antara 0 dan 1, yaitu E[X²]. Dengan menggunakan 10.000 bilangan acak, diperoleh nilai estimasi sebesar 0,3297. Nilai ini mendekati hasil analitik teoritis E[X²] untuk distribusi Uniform(0,1), yaitu 1/3 atau sekitar 0,3333. Hasil ini menunjukkan bahwa pendekatan menggunakan simulasi memberikan hasil yang cukup akurat dan sesuai dengan teori.

2. Simulasi dan Histogram untuk X ~ Normal(100, 15²)

set.seed(123)

# Generate data
n1 <- rnorm(100, mean = 100, sd = 15)
n2 <- rnorm(1000, mean = 100, sd = 15)
n3 <- rnorm(10000, mean = 100, sd = 15)

# Buat data frame ringkasan statistik
summary_table <- data.frame(
  Sample_Size = c(100, 1000, 10000),
  Mean = c(mean(n1), mean(n2), mean(n3)),
  SD = c(sd(n1), sd(n2), sd(n3))
)

# Tampilkan tabel ringkasan
knitr::kable(summary_table, caption = "Ringkasan Statistik untuk Tiga Ukuran Sampel")
Ringkasan Statistik untuk Tiga Ukuran Sampel
Sample_Size Mean SD
100 101.35609 13.69224
1000 100.28622 15.06891
10000 99.96336 14.98314

Pada soal ini dilakukan simulasi data acak dari distribusi normal dengan rata-rata 100 dan standar deviasi 15. Tiga ukuran sampel yang digunakan yaitu n = 100, n = 1000, dan n = 10000. Hasil simulasi menunjukkan bahwa semakin besar ukuran sampel, maka nilai rata-rata dan simpangan baku yang diperoleh semakin mendekati nilai teoritisnya.

Untuk n = 100, diperoleh rata-rata sekitar 101,36 dan simpangan baku sekitar 13,69. Sedangkan untuk n = 1000 dan n = 10000, nilai rata-rata mendekati 100 dan simpangan bakunya mendekati 15, sesuai dengan karakteristik distribusi normal yang digunakan.

# Histogram
par(mfrow = c(1, 3))  # layout 1 baris 3 kolom
hist(n1, main = "Histogram n = 100", col = "skyblue", xlab = "Nilai")
hist(n2, main = "Histogram n = 1000", col = "salmon", xlab = "Nilai")
hist(n3, main = "Histogram n = 10000", col = "lightgreen", xlab = "Nilai")

Berdasarkan histogram yang ditampilkan, distribusi data dengan ukuran sampel kecil masih terlihat kurang halus. Namun, ketika ukuran sampel bertambah besar, bentuk histogram menjadi semakin simetris dan menyerupai bentuk distribusi normal. Hal ini menunjukkan bahwa dengan sampel yang lebih besar, distribusi data akan semakin stabil dan menyerupai distribusi populasi. Ini sesuai dengan prinsip hukum bilangan besar, yaitu semakin banyak data yang diambil, maka hasilnya akan semakin mendekati nilai sebenarnya dari populasi.

3. Simulasi Distribusi Binomial dan Estimasi \(P(X \geq 15)\)

set.seed(123)

# Simulasi 5000 data dari Binomial(n=30, p=0.25)
x_binom <- rbinom(5000, size = 30, prob = 0.25)

# Estimasi P(X ≥ 15)
p_ge_15 <- mean(x_binom >= 15)
p_ge_15
## [1] 0.0024

Simulasi dilakukan sebanyak 5000 kali untuk distribusi binomial dengan jumlah percobaan sebanyak 30 dan peluang sukses sebesar 25 persen pada setiap percobaan. Dari hasil simulasi, diperoleh bahwa peluang terjadinya 15 keberhasilan atau lebih adalah sekitar 0,0024. Ini berarti bahwa kemungkinan mendapatkan 15 atau lebih keberhasilan dalam kondisi tersebut sangat kecil, yaitu sekitar 0,24 persen. Dengan demikian, kejadian ini tergolong langka atau jarang terjadi dalam distribusi binomial tersebut.

4. Fungsi Manual untuk Menghitung Simpangan Baku \(s\)

# Fungsi menghitung s berdasarkan rumus manual
s_manual <- function(x) {
  n <- length(x)
  sqrt((sum(x^2) - (sum(x)^2)/n) / (n - 1))
}

# Simulasi data normal: n = 1000, mean = 89, sd = 10
set.seed(123)
data_norm <- rnorm(1000, mean = 89, sd = 10)

# Hitung nilai s menggunakan fungsi manual
s_manual(data_norm)
## [1] 9.91695

Fungsi s_manual digunakan untuk menghitung simpangan baku (standar deviasi) berdasarkan rumus manual dari statistika. Dengan mensimulasikan 1000 data acak yang mengikuti distribusi normal dengan rata-rata 89 dan simpangan baku 10, diperoleh hasil perhitungan simpangan baku sebesar 9.92. Nilai ini mendekati nilai teoritis (yaitu 10), sehingga dapat disimpulkan bahwa fungsi manual telah bekerja dengan baik dalam mengestimasi simpangan baku dari data yang diberikan.

5. Simulasi Antrian di Bank

Bank yang disimulasikan memiliki 2 teller dan melayani nasabah selama 6 jam setiap harinya. Rata-rata kedatangan nasabah adalah 5 orang per jam dan waktu pelayanan untuk setiap nasabah mengikuti distribusi eksponensial dengan rata-rata 8 menit. Simulasi dilakukan selama 20 hari kerja untuk mengevaluasi performa sistem antrian, termasuk waktu tunggu nasabah, tingkat kesibukan teller, serta dampak efisiensi jika teller ditambah menjadi 3. Analisis juga mencakup grafik panjang antrian tiap jam untuk membandingkan kedua skenario pelayanan.

library(ggplot2)
set.seed(123)
(a) Simulasi Antrian Selama 20 Hari
lambda <- 5/60   
mu <- 1/8         
jam_kerja <- 360
n_hari <- 20

# Fungsi simulasi
sim_bank <- function(n_teller) {
  total_tunggu <- 0
  total_nasabah <- 0
  total_sibuk <- 0
  antrian_harian <- matrix(0, n_hari, 6)
  
  for(hari in 1:n_hari) {
    # Generate nasabah
    n <- rpois(1, lambda * jam_kerja)
    kedatangan <- sort(runif(n, 0, jam_kerja))
    pelayanan <- rexp(n, mu)
    
    # Simulasi
    teller_selesai <- rep(0, n_teller)
    tunggu <- numeric(n)
    
    for(i in 1:n) {
      teller_idx <- which.min(teller_selesai)
      mulai <- max(kedatangan[i], teller_selesai[teller_idx])
      tunggu[i] <- mulai - kedatangan[i]
      teller_selesai[teller_idx] <- mulai + pelayanan[i]
    }
    
    # Akumulasi hasil
    total_tunggu <- total_tunggu + sum(tunggu)
    total_nasabah <- total_nasabah + n
    total_sibuk <- total_sibuk + sum(pmin(teller_selesai, jam_kerja))
    
    # Panjang antrian per jam
    for(jam in 1:6) {
      start_t <- (jam-1) * 60
      end_t <- jam * 60
      dalam_jam <- kedatangan >= start_t & kedatangan < end_t
      if(sum(dalam_jam) > 0) {
        antrian_harian[hari, jam] <- mean(tunggu[dalam_jam] > 0)
      }
    }
  }
  
  list(
    rata_tunggu = total_tunggu / total_nasabah,
    utilisasi = total_sibuk / (n_teller * jam_kerja * n_hari),
    antrian_jam = colMeans(antrian_harian)
  )
}
hasil_2 <- sim_bank(2)
cat("Simulasi 20 hari dengan 2 teller selesai\n")
## Simulasi 20 hari dengan 2 teller selesai
cat("Total nasabah dilayani rata-rata:", round(rpois(1, lambda * jam_kerja)), "orang/hari\n")
## Total nasabah dilayani rata-rata: 32 orang/hari

Simulasi antrian bank selama 20 hari dilakukan dengan 2 teller, waktu kerja 6 jam per hari, dan rata-rata kedatangan 5 nasabah per jam. Berdasarkan hasil simulasi, rata-rata jumlah nasabah yang datang dan dilayani per hari adalah sekitar 32 orang. Simulasi ini menjadi dasar untuk mengevaluasi efisiensi pelayanan dan waktu tunggu nasabah pada tahap berikutnya.

(b) Rata-Rata Waktu Tunggu Nasabah
cat("Rata-rata waktu tunggu:", round(hasil_2$rata_tunggu, 2), "menit\n")
## Rata-rata waktu tunggu: 1.14 menit

Hasil simulasi menunjukkan bahwa rata-rata waktu tunggu nasabah selama 20 hari kerja adalah sekitar 1,14 menit. Artinya, dengan dua teller yang tersedia dan rata-rata kedatangan 5 nasabah per jam, sebagian besar nasabah tidak perlu menunggu lama untuk dilayani. Waktu tunggu yang relatif singkat ini menunjukkan bahwa sistem antrian bank dalam kondisi tersebut cukup efisien dalam menangani jumlah nasabah yang datang.

(c) Persentase Waktu Teller Sibuk
cat("Utilisasi teller:", round(hasil_2$utilisasi * 100, 1), "%\n")
## Utilisasi teller: 95.7 %

Hasil simulasi menunjukkan bahwa tingkat utilisasi teller mencapai 95,7 persen selama 20 hari kerja. Ini berarti bahwa teller sibuk melayani nasabah hampir sepanjang waktu operasional bank. Utilisasi yang tinggi ini menunjukkan bahwa kapasitas pelayanan teller digunakan secara maksimal, namun juga mengindikasikan potensi risiko kelebihan beban kerja dan antrean jika terjadi lonjakan jumlah nasabah.

(d) Evaluasi Efisiensi Penambahan Teller
hasil_3 <- sim_bank(3)

perbandingan <- data.frame(
  Metrik = c("Waktu tunggu (menit)", "Utilisasi (%)", "Efisiensi"),
  Teller_2 = c(round(hasil_2$rata_tunggu, 2), 
               round(hasil_2$utilisasi * 100, 1),
               round(hasil_2$rata_tunggu / hasil_2$utilisasi, 2)),
  Teller_3 = c(round(hasil_3$rata_tunggu, 2),
               round(hasil_3$utilisasi * 100, 1), 
               round(hasil_3$rata_tunggu / hasil_3$utilisasi, 2))
)

print(perbandingan)
##                 Metrik Teller_2 Teller_3
## 1 Waktu tunggu (menit)     1.14     0.07
## 2        Utilisasi (%)    95.70    95.80
## 3            Efisiensi     1.19     0.07
penurunan <- (hasil_2$rata_tunggu - hasil_3$rata_tunggu) / hasil_2$rata_tunggu * 100
cat("\nPenurunan waktu tunggu:", round(penurunan, 1), "%\n")
## 
## Penurunan waktu tunggu: 93.7 %
cat("Kesimpulan:", ifelse(penurunan > 25, "EFISIEN - tambah teller", "KURANG EFISIEN"))
## Kesimpulan: EFISIEN - tambah teller

Dengan menambahkan satu teller, waktu tunggu rata-rata nasabah menurun secara signifikan dari 1,14 menit menjadi hanya 0,07 menit, atau terjadi penurunan sebesar 93,7 persen. Sementara itu, tingkat utilisasi tetap tinggi di kisaran 95 persen untuk kedua skenario. Hal ini menunjukkan bahwa penambahan teller tidak hanya mengurangi beban antrean secara drastis, tetapi juga tetap mempertahankan efisiensi kerja teller. Oleh karena itu, dapat disimpulkan bahwa penambahan teller terbukti efisien dalam meningkatkan kualitas layanan.

(e) Grafik Panjang Antrian Sepanjang Hari
jam_data <- data.frame(
  Jam = 1:6,
  Teller_2 = hasil_2$antrian_jam,
  Teller_3 = hasil_3$antrian_jam
)

library(reshape2)
## Warning: package 'reshape2' was built under R version 4.4.3
jam_long <- melt(jam_data, id.vars = "Jam", variable.name = "Skenario", value.name = "Panjang")

ggplot(jam_long, aes(x = Jam, y = Panjang, fill = Skenario)) +
  geom_bar(stat = "identity", position = "dodge", alpha = 0.7) +
  labs(title = "Rata-rata Panjang Antrian per Jam",
       x = "Jam ke-", y = "Proporsi Waktu Ada Antrian") +
  theme_minimal() +
  scale_x_continuous(breaks = 1:6)

Grafik menunjukkan rata-rata panjang antrian per jam selama jam operasional bank dalam dua skenario: dengan 2 teller dan dengan 3 teller. Pada skenario 2 teller, antrian terjadi hampir di setiap jam, terutama pada jam ke-3, 5, dan 6, di mana proporsi waktu terjadinya antrian mencapai lebih dari 10 persen. Sebaliknya, pada skenario dengan 3 teller, antrian jauh lebih jarang terjadi dan proporsinya jauh lebih rendah di semua jam. Hal ini memperkuat kesimpulan bahwa penambahan satu teller secara signifikan mengurangi kepadatan dan frekuensi antrian, serta membuat layanan menjadi lebih lancar sepanjang hari kerja.

6. Simulasi Toko Kelontong Bu Sari

Bu Sari memiliki toko kelontong dengan stok awal beras sebanyak 100 karung. Setiap harinya, penjualan beras berkisar antara 8 hingga 15 karung secara acak. Untuk menjaga ketersediaan barang, Bu Sari melakukan pemesanan ulang sebanyak 50 karung setiap 5 hari. Jika stok habis sebelum pemesanan berikutnya, ia akan kehilangan keuntungan sebesar Rp50.000 per karung. Simulasi dilakukan selama 60 hari untuk mengevaluasi efektivitas strategi tersebut.

(a) Simulasikan stok beras selama 60 hari
set.seed(123)

simulasi_stok <- function(hari = 60,
                          stok_awal = 100,
                          min_jual = 8,
                          max_jual = 15,
                          frekuensi_pesan = 5,
                          jumlah_pesan = 50,
                          rugi_per_karung = 50000) {
  stok <- numeric(hari)
  penjualan <- numeric(hari)
  rugi <- 0
  kehabisan_hari <- 0
  
  stok[1] <- stok_awal
  
  for (i in 1:hari) {
    # Penjualan hari ini
    jual <- sample(min_jual:max_jual, 1)
    penjualan[i] <- jual
    
    if (stok[i] >= jual) {
      stok[i] <- stok[i] - jual
    } else {
      rugi <- rugi + (jual - stok[i]) * rugi_per_karung
      kehabisan_hari <- kehabisan_hari + 1
      stok[i] <- 0
    }
    
    # Tambah stok keesokan harinya
    if (i < hari) stok[i + 1] <- stok[i]
    
    # Pemesanan
    if (i %% frekuensi_pesan == 0 && i < hari) {
      stok[i + 1] <- stok[i + 1] + jumlah_pesan
    }
  }
  
  return(list(stok = stok,
              penjualan = penjualan,
              rugi = rugi,
              kehabisan_hari = kehabisan_hari))
}

# Simulasi awal
hasil_awal <- simulasi_stok()
(b) Hitung berapa kali toko kehabisan stok
cat("Jumlah hari kehabisan stok:", hasil_awal$kehabisan_hari, "\n")
## Jumlah hari kehabisan stok: 3

Berdasarkan hasil simulasi selama 60 hari, diketahui bahwa toko Bu Sari mengalami kehabisan stok sebanyak 3 hari. Artinya, selama 3 hari tersebut, permintaan beras dari pelanggan tidak dapat dipenuhi karena stok yang tersedia sudah habis sebelum dilakukan pemesanan ulang. Hal ini menunjukkan bahwa meskipun strategi pemesanan 50 karung setiap 5 hari cukup membantu menjaga kestabilan stok, tetap terdapat risiko kehabisan akibat fluktuasi penjualan harian yang bersifat acak. Oleh karena itu, Bu Sari perlu mempertimbangkan untuk meningkatkan jumlah pesanan atau memperpendek interval pemesanan agar kejadian kehabisan stok dapat diminimalkan di masa mendatang.

(c) Coba strategi pesan 40, 50, atau 60 karung
strategi <- c(40, 50, 60)
evaluasi_pesan <- sapply(strategi, function(pesan) {
  sim <- simulasi_stok(jumlah_pesan = pesan)
  c(Rugi = sim$rugi, Kehabisan = sim$kehabisan_hari)
})

rownames(evaluasi_pesan) <- c("Rugi (Rp)", "Hari Kehabisan")
print(evaluasi_pesan)
##                   [,1]    [,2] [,3]
## Rugi (Rp)      8350000 3950000    0
## Hari Kehabisan      17       9    0

Simulasi menunjukkan bahwa semakin banyak jumlah beras yang dipesan, semakin kecil kemungkinan kehabisan stok dan kerugian yang ditimbulkan. Dengan memesan 40 karung, toko kehabisan stok selama 17 hari dan mengalami kerugian Rp8.350.000. Strategi 50 karung mengurangi kehabisan menjadi 9 hari dengan kerugian Rp3.950.000. Sementara itu, strategi 60 karung terbukti paling efektif karena tidak menyebabkan kehabisan stok dan kerugian sama sekali. Oleh karena itu, strategi terbaik adalah memesan 60 karung setiap 5 hari.

(d) Ubah frekuensi pesan: setiap 3, 5, atau 7 hari
frekuensi <- c(3, 5, 7)
evaluasi_frekuensi <- sapply(frekuensi, function(freq) {
  sim <- simulasi_stok(frekuensi_pesan = freq)
  c(Rugi = sim$rugi, Kehabisan = sim$kehabisan_hari)
})

rownames(evaluasi_frekuensi) <- c("Rugi (Rp)", "Hari Kehabisan")
print(evaluasi_frekuensi)
##                [,1]  [,2]    [,3]
## Rugi (Rp)         0 7e+05 8700000
## Hari Kehabisan    0 2e+00      17

Simulasi menunjukkan bahwa semakin sering Bu Sari memesan beras, semakin kecil kemungkinan kehabisan stok. Dengan frekuensi pemesanan setiap 3 hari, toko tidak pernah kehabisan stok dan tidak mengalami kerugian. Saat pemesanan dilakukan setiap 5 hari, terjadi kehabisan stok selama 2 hari dengan kerugian sebesar Rp700.000. Sementara itu, pemesanan setiap 7 hari menyebabkan kehabisan selama 17 hari dengan kerugian Rp8.700.000. Oleh karena itu, strategi paling optimal adalah memesan setiap 3 hari, karena mampu menghilangkan risiko kehilangan keuntungan akibat kekosongan stok.

(e) Grafik pergerakan stok & rekomendasi
library(ggplot2)

stok_data <- data.frame(
  Hari = 1:60,
  Stok = hasil_awal$stok,
  Penjualan = hasil_awal$penjualan
)

ggplot(stok_data, aes(x = Hari)) +
  geom_line(aes(y = Stok), color = "darkgreen", size = 1.2) +
  geom_bar(aes(y = Penjualan), stat = "identity", fill = "orange", alpha = 0.5) +
  labs(title = "Pergerakan Stok & Penjualan Beras Selama 60 Hari",
       y = "Jumlah Karung", x = "Hari") +
  theme_minimal()
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

Grafik menunjukkan bahwa stok beras Bu Sari cenderung menurun setiap hari akibat penjualan, lalu meningkat tajam setelah pemesanan dilakukan setiap 5 hari. Pola ini membentuk kurva seperti gigi gergaji. Namun, seiring waktu, puncak stok makin rendah, dan pada beberapa hari stok hampir habis. Hal ini menunjukkan bahwa strategi pemesanan 50 karung setiap 5 hari belum cukup untuk mengimbangi permintaan. Oleh karena itu, Bu Sari sebaiknya meningkatkan jumlah pesanan atau memperpendek frekuensi pemesanan agar stok tetap aman dan tidak kehilangan potensi keuntungan.