set.seed(1)
x <- runif(10000, 0, 1)
EX2 <- mean(x^2)
EX2
## [1] 0.3348666
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.
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.
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.
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.
# 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.
# 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.
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.
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.
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.
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.
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.
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.