#SOAL NO 1
Disimulasikan 1.000 data dari distribusi normal dengan rata-rata μ=75 dan simpangan baku σ=10. Kemudian dihitung rata-ratanya sebagai estimasi parameter populasi.
Gunakan simulasi untuk menghitung nilai pendekatan dari:
\[\mathbb{E}[X^2] = \int_0^1 x^2 \, dx = \frac{1}{3}, \text{ dengan } X \sim U(0,1)\]
Gunakan 10.000 angka random.
Penyelesaian Teoretis
Jika variabel acak \(X\) mengikuti distribusi uniform kontinu \(U(0,1)\) maka nilai harapan kuadratnya adalah:
\(\bar{x} = \frac{1}{n} \sum_{i=1}^{n} x_i\)
\[\mathbb{E}[X^2] = \int_0^1 x^2 \, dx = \left[ \frac{x^3}{3} \right]_0^1 = \frac{1}{3}\]
Penyelesaian Simulasi Menggunakan R
# Jumlah data simulasi
n <- 10000
# Simulasi bilangan acak dari distribusi Uniform(0,1)
x <- runif(n, min = 0, max = 1)
# Hitung nilai E[X^2] secara empiris
ex2 <- mean(x^2)
# Tampilkan hasil simulasi dan nilai teoritis
cat("Pendekatan E[X^2] dari simulasi =", ex2, "\n")
## Pendekatan E[X^2] dari simulasi = 0.3298796
cat("Nilai teoritis E[X^2] =", 1/3, "\n")
## Nilai teoritis E[X^2] = 0.3333333
Hasil Simulasi dan Interpretasi
Hasil simulasi memberikan:
\(\mathbb{E}[X^2] \approx 0.3345\)
Sedangkan nilai teoritisnya adalah:
\(\mathbb{E}[X^2] = \frac{1}{3} \approx 0.3333\)
Dengan demikian, hasil simulasi sangat mendekati nilai teoretis. Hal ini menunjukkan bahwa pendekatan Monte Carlo dengan menggunakan 10.000 angka random dari distribusi seragam \(U(0,1)\)memberikan estimasi yang cukup akurat terhadap nilai harapan \(\mathbb{E}[X^2]\)
#NO 2
Buat data random dari distribusi normal \(X \sim N(100, 15^2)\) untuk:
\(n_1 = 100\quad\)
\(n_2 = 1{,}000\)
\(\quad n_3 = 10{,}000\)
Hitung:
Rata-rata sampel (mean)
Simpangan baku sampel (standard deviation)
Lalu:
Plot histogram untuk masing-masing data
Jelaskan hasil yang diperoleh.
# Set seed untuk reproduktibilitas
set.seed(123)
# Parameter distribusi normal
mean_val <- 100
sd_val <- 15
# Ukuran sampel
n1 <- 100
n2 <- 1000
n3 <- 10000
# Simulasi data
data1 <- rnorm(n1, mean = mean_val, sd = sd_val)
data2 <- rnorm(n2, mean = mean_val, sd = sd_val)
data3 <- rnorm(n3, mean = mean_val, sd = sd_val)
# Hitung rata-rata dan simpangan baku
cat("n1 = 100 | Mean =", mean(data1), "| SD =", sd(data1), "\n")
## n1 = 100 | Mean = 101.3561 | SD = 13.69224
cat("n2 = 1000 | Mean =", mean(data2), "| SD =", sd(data2), "\n")
## n2 = 1000 | Mean = 100.2862 | SD = 15.06891
cat("n3 = 10000 | Mean =", mean(data3), "| SD =", sd(data3), "\n")
## n3 = 10000 | Mean = 99.96336 | SD = 14.98314
# Plot histogram
par(mfrow = c(1, 1)) # Membuat layout 1 baris 3 kolom
hist(data1, main = "Histogram n = 100", col = "skyblue", xlab = "Nilai", breaks = 20)
hist(data2, main = "Histogram n = 1.000", col = "salmon", xlab = "Nilai", breaks = 30)
hist(data3, main = "Histogram n = 10.000", col = "lightgreen", xlab = "Nilai", breaks = 40)
Lakukan simulasi dari distribusi binomial:
Sebanyak 5.000 kali percobaan (simulasi), kemudian:
Tentukan estimasi dari:
Penjelasan Hasil Secara umum, hasil dari simulasi ini menunjukkan:
Untuk Histogram terlihat agak kasar dan tidak terlalu menyerupai bentuk lonceng (normal), karena ukuran sampel yang kecil membuat distribusi empiris lebih rentan terhadap fluktuasi acak.
Untuk $𝑛= 1.000 $ Bentuk histogram mulai menyerupai kurva normal. Rata-rata dan simpangan baku mendekati nilai teoritis yaitu \(𝜇= 100 μ=100,𝜎= 15 σ=15.\)
Untuk \(𝑛= 10.000\) Distribusi semakin halus dan sangat menyerupai distribusi normal. Estimasi nilai rata-rata dan simpangan baku menjadi sangat dekat dengan nilai sebenarnya.
# Set seed untuk reprodusibilitas
set.seed(123)
# Parameter distribusi
n <- 30
p <- 0.25
simulasi <- 5000
# Simulasi data dari distribusi binomial
data_binom <- rbinom(simulasi, size = n, prob = p)
# Hitung estimasi peluang P(X ≥ 15)
estimasi_prob <- mean(data_binom >= 15)
# Tampilkan hasil
cat("Estimasi P(X ≥ 15) =", estimasi_prob, "\n")
## Estimasi P(X ≥ 15) = 0.0024
# Nilai teoretis
1 - pbinom(14, size = 30, prob = 0.25)
## [1] 0.002749534
untuk menghitung simpangan baku (standar deviasi sampel) berdasarkan rumus berikut:
# Fungsi simpangan baku menggunakan rumus manual
simpangan_baku_manual <- function(x) {
n <- length(x)
jumlah_x <- sum(x)
jumlah_x2 <- sum(x^2)
s <- sqrt((jumlah_x2 - (jumlah_x^2 / n)) / (n - 1))
return(s)
}
# Set seed untuk reprodusibilitas
set.seed(123)
# Bangkitkan 1.000 data dari distribusi normal N(89, 10^2)
data_normal <- rnorm(1000, mean = 89, sd = 10)
# Hitung simpangan baku menggunakan fungsi manual
s_manual <- simpangan_baku_manual(data_normal)
# Bandingkan dengan fungsi sd() bawaan R
s_builtin <- sd(data_normal)
# Tampilkan hasil
cat("Simpangan baku (manual):", s_manual, "\n")
## Simpangan baku (manual): 9.91695
cat("Simpangan baku (builtin):", s_builtin, "\n")
## Simpangan baku (builtin): 9.91695
\(s = \sqrt{\frac{n \sum x^2 - (\sum x)^2}{n(n - 1)}}\)
Spesifikasi Sistem:
Jumlah teller: 2 (dengan skenario tambahan 1 teller)
Kedatangan nasabah: Poisson, rata-rata 5 orang/jam
Waktu layanan: Eksponensial, rata-rata 8 menit
Jam kerja: 6 jam per hari
Durasi simulasi: 20 hari
library(simmer)
library(ggplot2)
# Parameter
set.seed(123)
lama_buka_jam <- 6
waktu_pelayanan <- 8 # menit
kedatangan_per_jam <- 5
hari_kerja <- 20
total_menit <- lama_buka_jam * 60 * hari_kerja
# Trajektori nasabah
nasabah_traj <- trajectory("nasabah") %>%
seize("teller", 1) %>%
timeout(function() rexp(1, 1/waktu_pelayanan)) %>%
release("teller", 1)
# Fungsi simulasi
simulasi_antrian <- function(jumlah_teller) {
env <- simmer("bank_simulasi")
env %>%
add_resource("teller", capacity = jumlah_teller) %>%
add_generator("nasabah", nasabah_traj, function() rexp(1, kedatangan_per_jam / 60)) %>%
run(until = total_menit)
return(env)
}
jumlah_hari <- 20 # jumlah hari simulasi
waktu_buka <- 8 * 60 # 8 jam kerja dikonversi ke menit
rata_kedatangan_per_menit <- 1/5 # misalnya 1 nasabah setiap 5 menit
total_kedatangan <- c() # inisialisasi vektor kosong
simulasi_2_teller <- simulasi_antrian(2)
for (hari in 1:jumlah_hari) {
waktu <- 0
kedatangan <- c()
while (waktu < waktu_buka) {
antar_kedatangan <- rexp(1, rate = rata_kedatangan_per_menit)
waktu <- waktu + antar_kedatangan
if (waktu < waktu_buka) {
kedatangan <- c(kedatangan, waktu)
}
}
total_kedatangan <- c(total_kedatangan, kedatangan)
}
cat("Total nasabah datang selama", jumlah_hari, "hari:", length(total_kedatangan), "orang\n")
## Total nasabah datang selama 20 hari: 1897 orang
# b. Rata-rata waktu tunggu nasabah
arrivals_2 <- get_mon_arrivals(simulasi_2_teller)
arrivals_2$waktu_tunggu <- arrivals_2$end_time - arrivals_2$start_time - arrivals_2$activity_time
rata2_tunggu_2 <- mean(arrivals_2$waktu_tunggu)
cat("Rata-rata waktu tunggu (2 teller):", round(rata2_tunggu_2, 2), "menit\n")
## Rata-rata waktu tunggu (2 teller): 0.94 menit
\(\bar{Q} = \frac{1}{n} \sum_{i=1}^{n} Q_i\)
# c. Persentase waktu teller sibuk
resource_2 <- get_mon_resources(simulasi_2_teller)
total_busy_2 <- tail(subset(resource_2, resource == "teller")$server, 1)
persen_sibuk_2 <- total_busy_2 / (2 * total_menit) * 100
cat("Persentase waktu teller sibuk (2 teller):", round(persen_sibuk_2, 2), "%\n")
## Persentase waktu teller sibuk (2 teller): 0.01 %
d. Bandingkan dengan 3 Teller
# d. Simulasi ulang dengan 3 teller
simulasi_3_teller <- simulasi_antrian(3)
arrivals_3 <- get_mon_arrivals(simulasi_3_teller)
arrivals_3$waktu_tunggu <- arrivals_3$end_time - arrivals_3$start_time - arrivals_3$activity_time
rata2_tunggu_3 <- mean(arrivals_3$waktu_tunggu)
cat("Rata-rata waktu tunggu (3 teller):", round(rata2_tunggu_3, 2), "menit\n")
## Rata-rata waktu tunggu (3 teller): 0.04 menit
resource_3 <- get_mon_resources(simulasi_3_teller)
total_busy_3 <- tail(subset(resource_3, resource == "teller")$server, 1)
persen_sibuk_3 <- total_busy_3 / (3 * total_menit) * 100
cat("Persentase waktu teller sibuk (3 teller):", round(persen_sibuk_3, 2), "%\n")
## Persentase waktu teller sibuk (3 teller): 0 %
e. Grafik Panjang Antrian
library(simmer)
library(ggplot2)
library(dplyr)
##
## Attaching package: 'dplyr'
## The following object is masked from 'package:simmer':
##
## select
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(lubridate)
##
## Attaching package: 'lubridate'
## The following objects are masked from 'package:simmer':
##
## now, rollback
## The following objects are masked from 'package:base':
##
## date, intersect, setdiff, union
library(scales)
set.seed(42)
sim_time <- 360 # 6 jam (9:00–15:00)
# Jam awal operasional: pukul 9:00
start_time <- as.POSIXct("2025-06-20 09:00:00")
# Fungsi simulasi
create_bank <- function(n_teller, label) {
env <- simmer(paste0("bank_", label))
customer <- trajectory("nasabah") %>%
seize("teller", 1) %>%
timeout(function() rexp(1, rate = 1/8)) %>% # waktu pelayanan rata-rata 8 menit
release("teller", 1)
env %>%
add_resource("teller", capacity = n_teller) %>%
add_generator("customer", customer, function() rexp(1, rate = 5/60)) %>% # 5 orang per jam
run(until = sim_time)
# Ambil data queue dan ubah menit ke waktu jam
get_mon_resources(env) %>%
filter(resource == "teller") %>%
mutate(
label = paste(n_teller, "Teller"),
real_time = start_time + dseconds(time * 60)
) %>%
select(real_time, queue, label)
}
# Simulasi
data_2 <- create_bank(2, "2")
data_3 <- create_bank(3, "3")
# Gabungkan
combined <- bind_rows(data_2, data_3)
# Visualisasi
ggplot(combined, aes(x = real_time, y = queue, color = label, fill = label)) +
geom_area(alpha = 0.3, position = "identity") +
geom_line(size = 1) +
facet_wrap(~label, ncol = 1, scales = "free_y") +
scale_x_datetime(
breaks = date_breaks("1 hour"),
labels = date_format("%H:%M")
) +
scale_color_manual(values = c("2 Teller" = "darkgreen", "3 Teller" = "steelblue")) +
scale_fill_manual(values = c("2 Teller" = "lightgreen", "3 Teller" = "lightblue")) +
labs(
title = "📊 Perbandingan Panjang Antrian Teller (Simulasi Jam 09:00–15:00)",
subtitle = "2 vs 3 Teller dalam 1 Hari Operasional (6 Jam)",
x = "Waktu (Jam)",
y = "Jumlah Nasabah dalam Antrian",
color = "Jumlah Teller",
fill = "Jumlah Teller"
) +
theme_minimal(base_size = 13) +
theme(
plot.title = element_text(face = "bold", color = "#003366", size = 16),
plot.subtitle = element_text(color = "#004080", face = "italic"),
legend.position = "top",
strip.text = element_text(face = "bold", size = 14)
)
## 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.
Penjualan harian acak dari distribusi uniform (8–15 karung).
Pemesanan ulang sesuai skenario.
Perhitungan stok harian.
Evaluasi kehilangan keuntungan jika stok habis.
set.seed(123)
simulate_stock <- function(days = 60, order_qty = 50, order_freq = 5) {
stock <- numeric(days)
stock[1] <- 100 # stok awal
for (day in 2:days) {
demand <- sample(8:15, 1) # permintaan acak
stock[day] <- stock[day - 1] - demand
if (day %% order_freq == 0) {
stock[day] <- stock[day] + order_qty
}
if (stock[day] < 0) stock[day] <- 0
}
return(stock)
}
# Simulasi untuk soal a
stock_a <- simulate_stock()
print(stock_a)
## [1] 100 86 72 62 99 89 80 71 58 98 86 75 62 49 91 82 72 57 45
## [20] 85 75 67 56 48 90 78 68 53 44 80 71 63 50 40 79 66 58 48
## [39] 34 72 61 47 32 23 61 47 39 31 22 58 48 37 25 11 49 39 24
## [58] 11 3 44
Pada bagian ini kita mensimulasikan stok harian selama 60 hari, dengan:
Penjualan acak 8–15 karung per hari (distribusi seragam).
Pengisian ulang setiap 5 hari sebanyak 50 karung.
Stok awal 100 karung.
Hasil simulasi menunjukkan fluktuasi stok yang menurun akibat permintaan harian dan kemudian meningkat kembali saat restock setiap 5 hari. Kita bisa melihat adanya potensi stok turun ke titik nol, meskipun tidak setiap hari.
simulate_stock_loss <- function(days = 60, order_qty = 50, order_freq = 5) {
stock <- 100
out_of_stock_days <- 0
loss <- 0
for (day in 1:days) {
demand <- sample(8:15, 1)
if (stock < demand) {
loss <- loss + (demand - stock) * 50000
out_of_stock_days <- out_of_stock_days + 1
stock <- 0
} else {
stock <- stock - demand
}
if (day %% order_freq == 0) stock <- stock + order_qty
}
return(list(out_of_stock_days = out_of_stock_days, loss = loss))
}
# Simulasi untuk soal b
result_b <- simulate_stock_loss()
print(result_b)
## $out_of_stock_days
## [1] 6
##
## $loss
## [1] 2800000
Hari kehabisan stok menunjukkan seberapa sering toko tidak bisa memenuhi permintaan pelanggan karena stok habis.
Kerugian dihitung berdasarkan hilangnya potensi keuntungan sebesar Rp50.000 per karung yang tidak terpenuhi.
Contoh hasil:
Toko kehabisan stok sebanyak 6 hari dalam 60 hari dan mengalami kerugian sekitar Rp700.000.
Ini menunjukkan perlunya manajemen stok yang lebih hati-hati agar tidak kehilangan keuntungan.
results_c <- sapply(c(40, 50, 60), function(qty) {
result <- simulate_stock_loss(order_qty = qty)
return(c(qty, result$out_of_stock_days, result$loss))
})
colnames(results_c) <- c("40 Karung", "50 Karung", "60 Karung")
rownames(results_c) <- c("Jumlah Pesan", "Hari Kehabisan", "Kerugian (Rp)")
print(results_c)
## 40 Karung 50 Karung 60 Karung
## Jumlah Pesan 40 50 60
## Hari Kehabisan 19 8 0
## Kerugian (Rp) 9450000 2550000 0
Semakin banyak karung yang dipesan, semakin kecil kemungkinan kehabisan stok dan kerugian. Namun, perlu dicatat bahwa biaya penyimpanan yang tidak dihitung di sini bisa meningkat jika stok terlalu banyak. Strategi 50–60 karung adalah yang paling seimbang.
results_d <- sapply(c(3, 5, 7), function(freq) {
result <- simulate_stock_loss(order_freq = freq)
return(c(freq, result$out_of_stock_days, result$loss))
})
colnames(results_d) <- c("Setiap 3 Hari", "Setiap 5 Hari", "Setiap 7 Hari")
rownames(results_d) <- c("Frekuensi", "Hari Kehabisan", "Kerugian (Rp)")
print(results_d)
## Setiap 3 Hari Setiap 5 Hari Setiap 7 Hari
## Frekuensi 3 5e+00 7
## Hari Kehabisan 0 3e+00 19
## Kerugian (Rp) 0 1e+06 8650000
library(ggplot2)
# Ambil strategi terbaik (misal: pesan 50 tiap 5 hari)
best_stock_e <- simulate_stock(order_qty = 50, order_freq = 5)
stock_df <- data.frame(
Hari = 1:60,
Stok = best_stock_e
)
ggplot(stock_df, aes(x = Hari, y = Stok)) +
geom_line(color = "steelblue", size = 1.2) +
geom_point(color = "darkblue") +
labs(
title = "📦 Grafik Pergerakan Stok Beras Bu Sari",
x = "Hari ke-",
y = "Jumlah Karung"
) +
theme_minimal(base_size = 14)
Grafik menunjukkan fluktuasi stok dari hari ke hari. Polanya:
Stok menurun tajam selama 4 hari karena permintaan harian.
Lalu naik kembali saat pesanan datang setiap 5 hari.
Grafik ini membantu Bu Sari memantau tren kehabisan stok, dan menjadi dasar keputusan strategi pemesanan di masa depan.
Jika grafik sering menyentuh angka nol, maka itu alarm penting bahwa strategi saat ini tidak memadai.
Strategi terbaik (dalam hal meminimalkan kerugian karena kehabisan stok):
Jumlah pemesanan: 60 karung
Frekuensi pemesanan: setiap 3 hari
Namun, jika ingin strategi seimbang antara efisiensi dan biaya operasional, maka: