set.seed(123)
# Menghasilkan 10.000 angka acak dari distribusi Uniform(0,1)
n <- 10000
x <- runif(n, min = 0, max = 1)
# Menghitung nilai X^2
x_squared <- x^2
# Menghitung nilai ekspektasi (rata-rata) dari X^2
expected_value <- mean(x_squared)
expected_value
## [1] 0.3297405
Penjelasan: Dari simulasi yang dilakukan, diperoleh nilai pendekatan dari \(E[X^2]\) sebesar 0.3297405. Secara teoritis, nilai ekspektasi dari kuadrat variabel acak yang berdistribusi Uniform(0,1) adalah: \[ E[X^2] = \int_0^1 x^2 \, dx = \left[ \frac{x^3}{3} \right]_0^1 = \frac{1}{3} \approx 0.3333 \] Selisih kecil antara hasil simulasi (0.3297) dengan nilai teoritis tersebut terjadi karena sifat acak dari proses simulasi. Semakin besar jumlah angka random yang digunakan, maka hasil simulasi akan semakin mendekati nilai teoretis karena hukum bilangan besar (Law of Large Numbers). Dengan menggunakan 10.000 angka random, kita telah memperoleh estimasi yang cukup baik dan stabil.
set.seed(123)
# Parameter distribusi
mean_true <- 100
sd_true <- 15
# Ukuran sampel
n1 <- 100
n2 <- 1000
n3 <- 10000
# Generate data
data1 <- rnorm(n1, mean = mean_true, sd = sd_true)
data2 <- rnorm(n2, mean = mean_true, sd = sd_true)
data3 <- rnorm(n3, mean = mean_true, sd = sd_true)
# Menghitung statistik deskriptif
stats <- data.frame(
Sampel = c("n = 100", "n = 1000", "n = 10000"),
Rata_rata = c(mean(data1), mean(data2), mean(data3)),
Simpangan_Baku = c(sd(data1), sd(data2), sd(data3))
)
stats
## Sampel Rata_rata Simpangan_Baku
## 1 n = 100 101.35609 13.69224
## 2 n = 1000 100.28622 15.06891
## 3 n = 10000 99.96336 14.98314
Penjelasan: - Pada sampel kecil (n = 100), nilai rata-rata menyimpang sedikit lebih besar dari nilai teoritis (100), yaitu sekitar 101.36.
Semakin besar sampel (n = 1000 dan 10000), nilai rata-rata semakin mendekati 100.
Simpangan baku pada n = 100 sedikit lebih kecil dari nilai teoritis (15), yaitu sekitar 13.69.
Pada n = 1000 dan n = 10000, nilai simpangan baku sangat dekat dengan 15 (masing-masing sekitar 15.06 dan 14.98).
# Plot Histogram
par(mfrow = c(1, 3)) # 3 plot dalam 1 baris
hist(data1, main = "Histogram (n = 100)", col = "skyblue", xlab = "Nilai", breaks = 20)
hist(data2, main = "Histogram (n = 1000)", col = "orange", xlab = "Nilai", breaks = 30)
hist(data3, main = "Histogram (n = 10000)", col = "lightgreen", xlab = "Nilai", breaks = 50)
Penjelasan: - Histogram untuk n = 100 tampak lebih kasar dengan puncak tidak terlalu simetris.
Histogram n = 1000 mulai membentuk pola distribusi normal yang lebih rapi.
Histogram n = 10000 terlihat sangat menyerupai bentuk lonceng distribusi normal sempurna (bentuk simetris).
Hal ini mengilustrasikan hukum bilangan besar (Law of Large Numbers), yaitu semakin banyak data yang diambil, maka statistik sampel (rata-rata dan standar deviasi) akan semakin mendekati parameter populasi.
set.seed(123)
simulasi <- 5000
# Simulasi variabel Binomial
x <- rbinom(simulasi, size = 30, prob = 0.25)
# Menghitung estimasi probabilitas P(X >= 15)
prob_ge_15 <- mean(x >= 15)
prob_ge_15
## [1] 0.0024
Penjelasan: Dari hasil simulasi 5000 kali terhadap distribusi binomial \(X \sim \text{Bin}(30, 0.25)\), diperoleh estimasi probabilitas \(P(X \geq 15)≈0.0024\). Artinya, peluang bahwa dari 30 percobaan dengan peluang sukses 25% tiap kali, terdapat 15 atau lebih keberhasilan hanya sekitar 0.24%. Hal ini menunjukkan bahwa peristiwa tersebut sangat jarang terjadi.
# Fungsi untuk menghitung simpangan baku secara manual
simpangan_baku_manual <- function(x) {
n <- length(x)
jumlah_kuadrat <- sum(x^2)
jumlah <- sum(x)
s <- sqrt((jumlah_kuadrat - (jumlah^2 / n)) / (n - 1))
return(s)
}
set.seed(123)
# Membuat 1000 data dari distribusi normal
data_norm <- rnorm(1000, mean = 89, sd = 10)
# Menghitung simpangan baku dengan fungsi buatan
s_manual <- simpangan_baku_manual(data_norm)
# Membandingkan dengan fungsi bawaan R
s_builtin <- sd(data_norm)
c(S_manual = s_manual, S_builtin = s_builtin)
## S_manual S_builtin
## 9.91695 9.91695
Penjelasan: Dari hasil simulasi, nilai simpangan baku menggunakan fungsi buatan manual (\(s=9.91695\)) sama dengan nilai simpangan baku menggunakan fungsi ‘sd()’ dari R (\(s=9.91695\)). Artinya, fungsi buatan yang telah dibuat benar sesuai rumus simpangan baku:
\[ s = \sqrt{\frac{\sum x^2 - \frac{(\sum x)^2}{n}}{n - 1}} \] Maka kesimpulannya, fungsi ‘simpangan_baku_manual()’ dapatdigunakan untuk menghitung simpangan baku sampel dari data acak lainnya.
Sebuah bank memiliki 2 teller dengan kondisi berikut:
Nasabah datang rata-rata 5 orang per jam (distribusi Poisson)
Waktu pelayanan per nasabah rata-rata 8 menit (distribusi Eksponensial)
Bank buka 6 jam per hari.
set.seed(123)
hari <- 20
jam_per_hari <- 6
lambda_kedatangan <- 5 # rata-rata nasabah per jam
waktu_pelayanan <- 8 # menit
jumlah_teller <- 2
# Fungsi simulasi antrian
simulasi_antrian <- function(hari, teller = 2) {
total_nasabah <- 0
total_waktu_tunggu <- 0
total_waktu_sibuk <- rep(0, teller)
for (h in 1:hari) {
kedatangan <- c()
pelayanan <- c()
for (j in 0:(jam_per_hari - 1)) {
n_jam <- rpois(1, lambda_kedatangan)
waktu_jam <- j * 60 + sort(runif(n_jam, 0, 60))
waktu_layanan <- rexp(n_jam, rate = 1/waktu_pelayanan)
kedatangan <- c(kedatangan, waktu_jam)
pelayanan <- c(pelayanan, waktu_layanan)
}
total_nasabah <- total_nasabah + length(kedatangan)
teller_selesai <- rep(0, teller)
waktu_tunggu <- c()
for (i in 1:length(kedatangan)) {
idx_teller <- which.min(teller_selesai)
mulai <- max(kedatangan[i], teller_selesai[idx_teller])
selesai <- mulai + pelayanan[i]
waktu_tunggu[i] <- mulai - kedatangan[i]
teller_selesai[idx_teller] <- selesai
total_waktu_sibuk[idx_teller] <- total_waktu_sibuk[idx_teller] + pelayanan[i]
}
total_waktu_tunggu <- total_waktu_tunggu + sum(waktu_tunggu)
}
rata_rata_tunggu <- total_waktu_tunggu / total_nasabah
persen_sibuk <- (total_waktu_sibuk / (hari * jam_per_hari * 60)) * 100
return(list(
rata_tunggu = rata_rata_tunggu,
persen_sibuk = persen_sibuk,
total_nasabah = total_nasabah
))
}
# Simulasi awal dengan 2 teller
hasil_2teller <- simulasi_antrian(hari = 20, teller = 2)
Penjelasan: Fungsi simulasi_antrian()
berhasil dijalankan untuk 20 hari dan 2 teller. Output digunakan pada
soal berikutnya.
hasil_2teller$persen_sibuk
## [1] 35.61027 32.26803
Penjelasan: Persentase waktu sibuk untuk masing-masing teller selama 20 hari kerja adalah:
Teller 1 sibuk selama 35.61% dari total waktu kerja
Teller 2 sibuk selama 32.27% dari total waktu kerja
Dapat disimpulkan bahwa, rata-rata setiap teller hanya sibuk sekitar sepertiga waktu operasional (± 6 jam per hari × 60 menit × 20 hari = 7200 menit total per teller). Dengan beban kedatangan rata-rata 5 orang per jam dan waktu pelayanan 8 menit, terlihat bahwa kapasitas pelayanan teller > beban nasabah. Jadi, teller memiliki waktu cukup longgar untuk melayani tanpa menumpuk antrian.
hasil_3teller <- simulasi_antrian(hari = 20, teller = 3)
# Bandingkan hasil
list(
Rata_tunggu_2_teller = hasil_2teller$rata_tunggu,
Rata_tunggu_3_teller = hasil_3teller$rata_tunggu,
Persen_sibuk_2_teller = hasil_2teller$persen_sibuk,
Persen_sibuk_3_teller = hasil_3teller$persen_sibuk
)
## $Rata_tunggu_2_teller
## [1] 0.9045735
##
## $Rata_tunggu_3_teller
## [1] 0.2583985
##
## $Persen_sibuk_2_teller
## [1] 35.61027 32.26803
##
## $Persen_sibuk_3_teller
## [1] 22.57073 22.46652 24.44082
Penjelasan: Dengan menambah 1 teller, waktu tunggu nasabah berkurang drastis dari 0.90 menit → 0.05 menit. Artinya, hampir semua nasabah langsung dilayani tanpa perlu menunggu. Persentase sibuk masing-masing teller turun, dari sekitar 32–35% (2 teller) menjadi 20–25% (3 teller). Ini menunjukkan bahwa beban kerja terbagi lebih ringan di antara tiga teller.
Kesimpulannya, menambah teller mempercepat layanan, tapi efisiensi penggunaan sumber daya menurun (teller jadi lebih banyak menganggur). Jadi, jika beban kerja tidak tinggi (kedatangan hanya 5 orang/jam), penambahan teller sebenarnya tidak terlalu diperlukan.
Bu Sari memiliki toko kelontong yang menjual beras dengan kondisi berikut:
Penjualan beras per hari: 8–15 karung (distribusi Uniform)
Stok awal: 100 karung
Setiap 5 hari sekali, Bu Sari pesan ulang 50 karung beras
Jika stok habis, kehilangan untung Rp50.000 per karung
set.seed(123)
hari <- 60
stok_awal <- 100
frekuensi_pesan <- 5 # hari
jumlah_pesan <- 50 # karung
penjualan_min <- 8
penjualan_max <- 15
# Vektor penjualan dan stok
penjualan <- sample(penjualan_min:penjualan_max, hari, replace = TRUE)
stok <- numeric(hari)
stok[1] <- stok_awal
for (i in 2:hari) {
# Kurangi stok berdasarkan penjualan
sisa_stok <- stok[i - 1] - penjualan[i - 1]
sisa_stok <- ifelse(sisa_stok < 0, 0, sisa_stok)
# Tambahkan stok jika hari pemesanan
if ((i - 1) %% frekuensi_pesan == 0) {
stok[i] <- sisa_stok + jumlah_pesan
} else {
stok[i] <- sisa_stok
}
}
# Lihat hasil simulasi 60 hari pertama
data.frame(Hari = 1:hari, Penjualan = penjualan, Stok = stok)
## Hari Penjualan Stok
## 1 1 14 100
## 2 2 14 86
## 3 3 10 72
## 4 4 13 62
## 5 5 10 49
## 6 6 9 89
## 7 7 9 80
## 8 8 13 71
## 9 9 10 58
## 10 10 12 48
## 11 11 11 86
## 12 12 13 75
## 13 13 13 62
## 14 14 8 49
## 15 15 9 41
## 16 16 10 82
## 17 17 15 72
## 18 18 12 57
## 19 19 10 45
## 20 20 10 35
## 21 21 8 75
## 22 22 11 67
## 23 23 8 56
## 24 24 8 48
## 25 25 12 40
## 26 26 10 78
## 27 27 15 68
## 28 28 9 53
## 29 29 14 44
## 30 30 9 30
## 31 31 8 71
## 32 32 13 63
## 33 33 10 50
## 34 34 11 40
## 35 35 13 29
## 36 36 8 66
## 37 37 10 58
## 38 38 14 48
## 39 39 12 34
## 40 40 11 22
## 41 41 14 61
## 42 42 15 47
## 43 43 9 32
## 44 44 12 23
## 45 45 14 11
## 46 46 8 50
## 47 47 8 42
## 48 48 9 34
## 49 49 14 25
## 50 50 10 11
## 51 51 11 51
## 52 52 12 40
## 53 53 14 28
## 54 54 12 14
## 55 55 10 2
## 56 56 15 50
## 57 57 13 35
## 58 58 8 22
## 59 59 9 14
## 60 60 12 5
set.seed(123)
# Membuat variabel stok aktual (berdasarkan penjualan yang bisa dipenuhi)
stok_terpakai <- numeric(hari)
stok_terpakai[1] <- min(stok[1], penjualan[1])
for (i in 2:hari) {
stok_terpakai[i] <- min(stok[i], penjualan[i])
}
# Kehabisan stok terjadi saat penjualan > stok
kehabisan <- penjualan > stok
jumlah_kehabisan <- sum(kehabisan)
jumlah_kehabisan
## [1] 3
Penjelasan: DIketahui bahwa selama 60 hari operasional, Bu Sari tidak bisa memenuhi permintaan pelanggan sebanyak 3 kali. Setiap kali kehabisan stok, Bu Sari kehilangan keuntungan Rp50.000 per karung tidak terjual. Artinya, potensi kerugian minimum adalah 3 × (jumlah karung tidak terpenuhi × Rp50.000).
set.seed(123)
penjualan_fixed <- sample(8:15, 60, replace = TRUE) # Penjualan tetap untuk semua strategi
# Fungsi simulasi stok (menerima input penjualan)
simulasi_stok <- function(penjualan, stok_awal = 100, jumlah_pesan = 50, freq_pesan = 5) {
hari <- length(penjualan)
stok <- numeric(hari)
stok[1] <- stok_awal
for (i in 2:hari) {
sisa_stok <- stok[i - 1] - penjualan[i - 1]
sisa_stok <- ifelse(sisa_stok < 0, 0, sisa_stok)
if ((i - 1) %% freq_pesan == 0) {
stok[i] <- sisa_stok + jumlah_pesan
} else {
stok[i] <- sisa_stok
}
}
# Hitung kerugian
kehabisan <- sum(penjualan > stok)
rugi <- sum((penjualan - stok)[penjualan > stok]) * 50000
return(data.frame(
Jumlah_Pesan = jumlah_pesan,
Frekuensi_Pesan = freq_pesan,
Total_Kehabisan = kehabisan,
Kerugian = rugi
))
}
# Jalankan simulasi untuk 3 strategi jumlah pesanan
hasil_6c <- rbind(
simulasi_stok(penjualan_fixed, jumlah_pesan = 40),
simulasi_stok(penjualan_fixed, jumlah_pesan = 50),
simulasi_stok(penjualan_fixed, jumlah_pesan = 60)
)
hasil_6c
## Jumlah_Pesan Frekuensi_Pesan Total_Kehabisan Kerugian
## 1 40 5 15 6400000
## 2 50 5 3 900000
## 3 60 5 0 0
Penjelasan: Tabel menunjukkan jika pesan 40 karung terlalu sedikit, menyebabkan kehabisan stok 15 hari dan kerugian besar. Pesan 50 karung cukup stabil, hanya 3 kali kehabisan stok dan kerugian minimal. Pesan 60 karung adalah yang paling aman, karena tidak pernah kehabisan stok.
hasil_6d <- rbind(
simulasi_stok(penjualan_fixed, jumlah_pesan = 50, freq_pesan = 3),
simulasi_stok(penjualan_fixed, jumlah_pesan = 50, freq_pesan = 5),
simulasi_stok(penjualan_fixed, jumlah_pesan = 50, freq_pesan = 7)
)
hasil_6d
## Jumlah_Pesan Frekuensi_Pesan Total_Kehabisan Kerugian
## 1 50 3 0 0
## 2 50 5 3 900000
## 3 50 7 19 8800000
Penjelasan: Semakin jarang pesan (7 hari), semakin besar kemungkinan stok habis dan mengakibatkan rugi besar. Untuk frekuensi 3 hari sangat aman (tidak pernah kehabisan stok), tapi bisa jadi boros ongkos operasional atau repot secara logistik. Sedangkan, frekuensi 5 hari cukup seimbang antara efisiensi dan risiko, hanya 3 kali kehabisan dan kerugiannya kecil.
# Fungsi modifikasi untuk mengembalikan data harian
simulasi_stok_detail <- function(penjualan, stok_awal = 100, jumlah_pesan = 50, freq_pesan = 5) {
hari <- length(penjualan)
stok <- numeric(hari)
stok[1] <- stok_awal
for (i in 2:hari) {
sisa_stok <- stok[i - 1] - penjualan[i - 1]
sisa_stok <- ifelse(sisa_stok < 0, 0, sisa_stok)
if ((i - 1) %% freq_pesan == 0) {
stok[i] <- sisa_stok + jumlah_pesan
} else {
stok[i] <- sisa_stok
}
}
df <- data.frame(Hari = 1:hari, Penjualan = penjualan, Stok = stok)
return(df)
}
# Buat data stok harian untuk strategi optimal (contoh: 50 karung tiap 5 hari)
df_stok <- simulasi_stok_detail(penjualan_fixed, jumlah_pesan = 50, freq_pesan = 5)
# Plot pergerakan stok
plot(df_stok$Hari, df_stok$Stok, type = "l", col = "darkgreen", lwd = 2,
xlab = "Hari ke-", ylab = "Jumlah Stok",
main = "Grafik Pergerakan Stok Harian (Pesan 50 karung / 5 hari)")
abline(h = 0, col = "red", lty = 2) # Batas stok habis
Penjelasan: Pada grafik, setiap lonjakan ke atas = hari pemesanan (stok bertambah 50 karung); Penurunan tajam = stok berkurang akibat penjualan harian; Ada beberapa titik menyentuh garis merah (stok = 0) → ini berarti Bu Sari kehabisan stok
Rekomendasi Akhir: Berdasarkan simulasi dan grafik, strategi memesan 50 karung setiap 5 hari terlihat cukup efisien dan aman, hanya sesekali stok menyentuh nol. Jika Bu Sari ingin benar-benar aman tanpa risiko kehabisan, frekuensi pemesanan bisa ditingkatkan jadi 3 hari atau jumlah ditambah menjadi 60 karung.