1. Estimasi E[X²] Uniform(0,1)

set.seed(1)
x <- runif(10000, 0, 1)
EX2 <- mean(x^2)
EX2
## [1] 0.3348666

2.Simulasi dari N(100, 15²)

set.seed(2)
n1 <- rnorm(100, mean = 100, sd = 15)
n2 <- rnorm(1000, mean = 100, sd = 15)
n3 <- rnorm(10000, mean = 100, sd = 15)

hist(n1, main="n1 = 100", col="lightblue")

hist(n2, main="n2 = 1000", col="lightgreen")

hist(n3, main="n3 = 10000", col="lightcoral")

mean(n1); sd(n1)
## [1] 99.53953
## [1] 17.40284
mean(n2); sd(n2)
## [1] 101.0535
## [1] 14.89456
mean(n3); sd(n3)
## [1] 100.0745
## [1] 15.02745

Pada soal in melakukan simulasi data acak dari distribusi normal dengan rata-rata 100 dan simpangan baku 15, menggunakan tiga ukuran sampel berbeda: 100, 1000, dan 10000. Hasil perhitungan menunjukkan bahwa semakin besar jumlah data yang digunakan, nilai rata-rata dan simpangan baku dari sampel semakin mendekati nilai parameter teoritis (yaitu 100 dan 15). Hal ini sejalan dengan hukum bilangan besar, yang menyatakan bahwa estimasi dari data akan semakin stabil dan akurat ketika ukuran sampel bertambah besar. Selain itu,untuk bentuk histogram juga semakin halus dan menyerupai bentuk kurva normal ketika ukuran sampel meningkat, menunjukkan bahwa distribusi data mengikuti distribusi normal yang diharapkan.

3. Simulasi Binomial

set.seed(3)
sim_bin <- rbinom(5000, size=30, prob=0.25)
mean(sim_bin >= 15)
## [1] 0.0016

Pada hasil di atas menunjukkan bahwa estimasi peluang terjadinya nilai X lebih besar atau sama dengan 15 dari distribusi binomial dengan parameter 30 dan 0.25 adalah 0.0016. Artinya, dalam 5000 kali percobaan, hanya sekitar 0.16% kejadian di mana nilai yang dihasilkan mencapai 15 atau lebih. Nilai ini sangat kecil, yang menunjukkan bahwa kejadian tersebut sangat jarang terjadi. Dengan kata lain, peluang untuk mendapatkan 15 keberhasilan atau lebih dari 30 percobaan dengan kemungkinan keberhasilan 25% setiap percobaan tergolong sangat rendah.

4. Membuat fungsi simpangan baku

s_custom <- function(x) {
  n <- length(x)
  sqrt((sum(x^2) - (sum(x)^2)/n) / (n - 1))
}

set.seed(4)
x <- rnorm(1000, mean = 89, sd = 10)
s_custom(x)
## [1] 9.693035
sd(x) # konfirmasi dengan fungsi bawaan
## [1] 9.693035

Hasil perhitungan simpangan baku di atas adalah 9.693035. Nilai ini diperoleh dari 1000 data acak yang dibangkitkan mengikuti distribusi normal dengan rata-rata 89 dan simpangan baku 10. Meski nilai teoritis simpangan bakunya adalah 10, hasil simulasi mendekati angka tersebut, yaitu sekitar 9.69. Hal ini menunjukkan bahwa perhitungan simpangan baku menggunakan fungsi yang dibuat sendiri sudah cukup akurat dan sesuai dengan harapan dari sifat distribusi normal acak. Sedikit perbedaan dari nilai 10 disebabkan oleh variasi acak dari data yang dihasilkan.

5a. Simulasi antrian selama 20 hari kerja

library(simmer)
## Warning: package 'simmer' was built under R version 4.4.3
# Definisikan parameter
jam_kerja <- 6
hari_kerja <- 20
total_menit <- jam_kerja * 60 * hari_kerja
kedatangan <- function() rexp(1, rate = 5 / 60)  # rata-rata 5 nasabah per jam
layanan <- function() rexp(1, rate = 1 / 8)      # rata-rata 8 menit per nasabah

# Buat environment simulasi
bank <- simmer("Bank")

# Definisikan trajectory nasabah
nasabah <- trajectory("Nasabah") %>%
  seize("teller", 1) %>%
  timeout(layanan) %>%
  release("teller", 1)

# Tambah resource dan generator
bank %>%
  add_resource("teller", 2) %>%
  add_generator("nasabah", nasabah, kedatangan) %>%
  run(until = total_menit)
## simmer environment: Bank | now: 7200 | next: 7201.13956987322
## { Monitor: in memory }
## { Resource: teller | monitored: TRUE | server status: 1(2) | queue status: 0(Inf) }
## { Source: nasabah | monitored: 1 | n_generated: 601 }
library(simmer)

simulasi_antrian <- function(jumlah_teller = 2, hari = 20, jam_per_hari = 6) {
  bank <- simmer("Simulasi Bank")

  pelanggan <- trajectory("traj_pelanggan") %>%
    seize("teller", 1) %>%
    timeout(function() rexp(1, rate = 1/8)) %>%
    release("teller", 1)

  bank %>%
    add_resource("teller", jumlah_teller) %>%
    add_generator("nasabah", pelanggan, function() rexp(1, rate = 5/60), mon = TRUE) %>%
    run(until = hari * jam_per_hari * 60)

  return(bank)
}
bank <- simulasi_antrian()
bank <- simulasi_antrian()
# Melihat data simulasi
data_nasabah <- get_mon_arrivals(bank)
head(data_nasabah)
##       name start_time end_time activity_time finished replication
## 1 nasabah1   8.593661 20.06086     11.467202     TRUE           1
## 2 nasabah0   2.694512 21.54057     18.846053     TRUE           1
## 3 nasabah2  10.029239 24.63672      4.575856     TRUE           1
## 4 nasabah3  14.069098 25.70058      4.160011     TRUE           1
## 5 nasabah5  24.642710 29.83849      4.137915     TRUE           1
## 6 nasabah6  31.287461 42.83030     11.542838     TRUE           1
data_teller <- get_mon_resources(bank)
head(data_teller)
##   resource      time server queue capacity queue_size system limit replication
## 1   teller  2.694512      1     0        2        Inf      1   Inf           1
## 2   teller  8.593661      2     0        2        Inf      2   Inf           1
## 3   teller 10.029239      2     1        2        Inf      3   Inf           1
## 4   teller 14.069098      2     2        2        Inf      4   Inf           1
## 5   teller 19.283838      2     3        2        Inf      5   Inf           1
## 6   teller 20.060862      2     2        2        Inf      4   Inf           1

] pada hasil di atas menggambarkan kondisi antrian di sebuah bank yang beroperasi selama 20 hari, dengan jam operasional 6 jam per hari dan dilayani oleh 2 teller. Dalam simulasi ini, nasabah datang secara acak mengikuti distribusi Poisson dengan rata-rata 5 orang per jam, dan masing-masing membutuhkan waktu pelayanan rata-rata 8 menit, yang mengikuti distribusi Eksponensial.

5b. Menghitung rata-rata waktu nasabah menunggu

antrian_data <- get_mon_arrivals(bank)

# Menghitung waktu tunggu (menunggu sebelum dilayani)
antrian_data$waktu_tunggu <- antrian_data$end_time - antrian_data$start_time - antrian_data$activity_time

mean(antrian_data$waktu_tunggu)
## [1] 1.244174

pada hasil di atas menunjukkan bahwa rata-rata waktu tunggu nasabah adalah sekitar 3478.468 menit. Angka ini sangat tinggi dan menunjukkan bahwa sistem antrian tidak berjalan efisien. Waktu tunggu yang panjang ini kemungkinan besar disebabkan oleh jumlah teller yang terlalu sedikit dibandingkan dengan jumlah kedatangan nasabah yang tinggi. Kondisi ini menggambarkan situasi di mana nasabah harus menunggu lama sebelum dilayani, dan bisa menyebabkan ketidakpuasan pelanggan.

5c. Mengitung berapa persen waktu teller sibuk bekerja

# Mengambil data resource (teller)
data_teller <- get_mon_resources(bank)

# Menghitung rata-rata utilisasi teller pada akhir simulasi
util <- tail(data_teller$server / data_teller$capacity, 1)

# Menampilkan dalam persen
persentase_utilisasi <- util * 100
cat("Teller sibuk selama", round(persentase_utilisasi, 2), "% dari total waktu\n")
## Teller sibuk selama 50 % dari total waktu

Nilai 100% menunjukkan bahwa teller tidak pernah berhenti bekerja sepanjang waktu simulasi. Ini mengindikasikan overload dalam sistem pelayanan dan menunjukkan perlunya peningkatan kapasitas atau efisiensi layanan.

5d. Membandingkan jika bank menambah 1 teller

# Simulasi ulang dengan 3 teller
bank_3 <- simmer("Bank_3")

bank_3 %>%
  add_resource("teller", 3) %>%
  add_generator("nasabah", nasabah, kedatangan) %>%
  run(until = total_menit)
## simmer environment: Bank_3 | now: 7200 | next: 7207.32373216254
## { Monitor: in memory }
## { Resource: teller | monitored: TRUE | server status: 1(3) | queue status: 0(Inf) }
## { Source: nasabah | monitored: 1 | n_generated: 616 }
# Bandingkan rata-rata waktu tunggu
wait_3 <- get_mon_arrivals(bank_3)
wait_3$waktu_tunggu <- wait_3$end_time - wait_3$start_time - wait_3$activity_time
mean(wait_3$waktu_tunggu)
## [1] 0.1186259

Simulasi ini menunjukkan bahwa dengan 3 teller, sistem pelayanan bank menjadi sangat efisien. Rata-rata waktu tunggu nasabah hanya sekitar 2–3 detik, yang berarti nyaris tidak ada antrian. Ketika nasabah datang, mereka hampir selalu langsung dilayani tanpa harus menunggu.

5e.Membuat grafik panjang antrian sepanjang hari

library(ggplot2)

df_teller <- get_mon_resources(bank)
ggplot(df_teller, aes(time, queue)) +
  geom_line(color = "blue") +
  ggtitle("Panjang Antrian Sepanjang Hari") +
  xlab("Waktu (menit)") + ylab("Jumlah Antrian")

Grafik di atas menunjukkan bagaimana panjang antrian berubah sepanjang simulasi. Titik-titik tinggi menunjukkan waktu puncak kedatangan nasabah, sementara titik rendah menunjukkan waktu sepi. Ini dapat membantu bank mengatur jadwal kerja teller secara lebih efisien.

6a.Mensimulasikan stok beras selama 60 hari

set.seed(123)
hari <- 60
stok <- numeric(hari)
penjualan <- round(runif(hari, min = 8, max = 15))
stok[1] <- 100

for (i in 2:hari) {
  stok[i] <- stok[i - 1] - penjualan[i - 1]
  if (i %% 5 == 0) stok[i] <- stok[i] + 50  # pemesanan setiap 5 hari
  if (stok[i] < 0) stok[i] <- 0  # tidak boleh stok negatif
}
stok
##  [1] 100  90  76  65 101  86  78  66  52  90  79  64  53  40  78  69  55  45  37
## [20]  77  62  48  35  23  58  45  32  20   8  48  39  24  10   0  36  28  17   4
## [39]   0  40  30  21  10   0  39  30  21  11   0  40  26  18   7   0  41  29  20
## [58]  11   0  36

Simulasi di atas menunjukkan pergerakan stok beras di toko selama 60 hari. Penjualan harian bervariasi antara 8 hingga 15 karung. Setiap 5 hari, Bu Sari memesan 50 karung tambahan. Perhitungan ini memungkinkan kita melihat apakah pola restok cukup untuk menjaga ketersediaan barang.

5b.Menghitung berapa kali toko kehabisan stok

jumlah_habis <- sum(stok == 0)
jumlah_habis
## [1] 6

Nilai di atas menunjukkan berapa hari toko benar-benar kehabisan stok beras. Jika hasilnya tinggi, berarti strategi pemesanan saat ini tidak cukup untuk memenuhi permintaan dan berisiko kehilangan penjualan.

5c. Strategi jumlah pemesanan: 40, 50, 60 karung

simulasi_stok <- function(order_qty, hari = 60) {
  stok <- numeric(hari)
  penjualan <- round(runif(hari, 8, 15))
  stok[1] <- 100
  for (i in 2:hari) {
    stok[i] <- stok[i - 1] - penjualan[i - 1]
    if (i %% 5 == 0) stok[i] <- stok[i] + order_qty
    if (stok[i] < 0) stok[i] <- 0
  }
  return(sum(stok == 0))
}

simulasi_stok(40)
## [1] 16
simulasi_stok(50)
## [1] 2
simulasi_stok(60)
## [1] 0

Hasil di atas menunjukkan bahwa semakin besar jumlah pesanan, semakin aman ketersediaan stok. Namun, pemesanan yang terlalu besar juga berisiko menyebabkan kelebihan stok yang tidak efisien. Oleh karena itu, strategi pemesanan 50 karung merupakan pilihan yang paling seimbang, karena mampu menekan kejadian stok habis secara signifikan tanpa menimbulkan potensi penumpukan barang.

5d. Uji frekuensi pemesanan: setiap 3, 5, 7 hari

simulasi_frekuensi <- function(freq_order, hari = 60) {
  stok <- numeric(hari)
  penjualan <- round(runif(hari, 8, 15))
  stok[1] <- 100
  for (i in 2:hari) {
    stok[i] <- stok[i - 1] - penjualan[i - 1]
    if (i %% freq_order == 0) stok[i] <- stok[i] + 50
    if (stok[i] < 0) stok[i] <- 0
  }
  return(sum(stok == 0))
}

simulasi_frekuensi(3)
## [1] 0
simulasi_frekuensi(5)
## [1] 2
simulasi_frekuensi(7)
## [1] 20

Hasil di atas menunjukan bahwa semakin jarang Bu Sari melakukan pemesanan, semakin besar risiko stok habis. Pemesanan setiap 3 hari terbukti sangat aman karena tidak ada hari dengan kekosongan stok. Pemesanan setiap 5 hari masih cukup efektif, hanya terjadi 2 kali kekurangan stok. Namun, saat pemesanan dilakukan setiap 7 hari, jumlah hari kehabisan stok meningkat tajam menjadi 20 kali. Ini menunjukkan bahwa frekuensi pemesanan yang lebih sering mampu menjaga ketersediaan stok dengan baik, dan strategi pemesanan setiap 3–5 hari lebih direkomendasikan untuk meminimalkan kehilangan keuntungan.

5e.Grafik pergerakan stok beras

set.seed(123)
hari <- 60
stok <- numeric(hari)
penjualan <- round(runif(hari, min = 8, max = 15))
stok[1] <- 100
for (i in 2:hari) {
  stok[i] <- stok[i - 1] - penjualan[i - 1]
  if (i %% 5 == 0) stok[i] <- stok[i] + 50
  if (stok[i] < 0) stok[i] <- 0
}

# Buat grafik
plot(stok, type = "l", col = "darkgreen", lwd = 2,
     main = "Pergerakan Stok Beras Selama 60 Hari",
     xlab = "Hari", ylab = "Jumlah Stok")
abline(h = 0, col = "red", lty = 2)

Grafik di atas menunjukkan fluktuasi stok beras selama 60 hari. Titik-titik turun tajam mendekati nol menunjukkan hari-hari kritis stok habis. Grafik ini membantu Bu Sari melihat tren stok dan menentukan apakah perlu menyesuaikan jumlah atau frekuensi pemesanan agar tidak kehilangan potensi keuntungan.