Data berikut merupakan catatan volume produksi air minum Perusahaan Umum Daerah Air Minum (PDAM) Kabupaten Serang periode Januari 2022 hingga Desember 2024 (36 bulan pengamatan) dalam satuan ribu \(\text{m}^3\)/bulan:
# Input data bulanan volume produksi air minum PDAM (ribu m3/bulan)
pdam_2022 <- c(410, 415, 405, 420, 430, 445, 455, 440, 425, 420, 418, 435)
pdam_2023 <- c(440, 445, 438, 452, 462, 478, 488, 472, 458, 452, 450, 468)
pdam_2024 <- c(470, 476, 468, 483, 494, 510, 521, 504, 489, 483, 480, 499)
bulan <- c("Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Agu", "Sep", "Okt", "Nov", "Des")
# Tabel data runtun waktu
tabel_pdam <- rbind(
"2022" = format(pdam_2022, big.mark = ".", scientific = FALSE),
"2023" = format(pdam_2023, big.mark = ".", scientific = FALSE),
"2024" = format(pdam_2024, big.mark = ".", scientific = FALSE)
)
colnames(tabel_pdam) <- bulan
kable(tabel_pdam, caption = "Tabel 1: Data Volume Produksi Air Minum PDAM Kabupaten Serang (ribu m³/bulan)")
| Jan | Feb | Mar | Apr | Mei | Jun | Jul | Agu | Sep | Okt | Nov | Des | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2022 | 410 | 415 | 405 | 420 | 430 | 445 | 455 | 440 | 425 | 420 | 418 | 435 |
| 2023 | 440 | 445 | 438 | 452 | 462 | 478 | 488 | 472 | 458 | 452 | 450 | 468 |
| 2024 | 470 | 476 | 468 | 483 | 494 | 510 | 521 | 504 | 489 | 483 | 480 | 499 |
ts dan Dekomposisi
AdditiveDekomposisi runtun waktu bertujuan memecah deret pengamatan asli (\(Y_t\)) menjadi komponen-komponen penyusunnya. Pada model dekomposisi aditif (additive decomposition), deret waktu diasumsikan sebagai hasil penjumlahan dari tiga komponen:
\[Y_t = T_t + S_t + R_t\]
di mana:
Model aditif dipilih karena besar (amplitudo) variasi musiman dari tahun ke tahun tampak relatif stabil dan tidak membesar secara proporsional terhadap kenaikan level tren.
tsData bulanan periode Januari 2022 hingga Desember 2024 digabungkan
menjadi sebuah objek deret waktu (ts) dengan frekuensi
\(12\) (monthly data),
kemudian didekomposisi menggunakan fungsi decompose()
dengan argumen type = "additive".
# Menggabungkan data menjadi satu vektor
total_produksi <- c(pdam_2022, pdam_2023, pdam_2024)
# 1. Membuat objek time series
pdam_ts <- ts(total_produksi, start = c(2022, 1), frequency = 12)
# Menampilkan objek time series
print(pdam_ts)
## Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
## 2022 410 415 405 420 430 445 455 440 425 420 418 435
## 2023 440 445 438 452 462 478 488 472 458 452 450 468
## 2024 470 476 468 483 494 510 521 504 489 483 480 499
# 2. Dekomposisi aditif menggunakan decompose()
decomp_pdam <- decompose(pdam_ts, type = "additive")
Plot di bawah ini menyajikan data aktual volume produksi air minum bulanan beserta garis tren linear regresi:
# Konfigurasi label sumbu X
waktu_label <- c("Jan 22", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Agu", "Sep", "Okt", "Nov", "Des",
"Jan 23", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Agu", "Sep", "Okt", "Nov", "Des",
"Jan 24", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Agu", "Sep", "Okt", "Nov", "Des")
plot(pdam_ts,
type = "o",
pch = 19,
col = "#1e40af",
lwd = 2,
ylim = c(395, 535),
main = "Runtun Waktu Volume Produksi Air Minum PDAM Kab. Serang (2022–2024)",
xlab = "Bulan dan Tahun",
ylab = "Volume Produksi (ribu m³/bulan)",
xaxt = "n")
# Sumbu waktu dan grid
axis(1, at = seq(2022, 2024 + 11/12, by = 1/12), labels = waktu_label, las = 2, cex.axis = 0.75)
grid(col = "#cbd5e1", lty = "dotted")
# Menambahkan garis regresi tren linear
fit_trend <- lm(pdam_ts ~ time(pdam_ts))
abline(fit_trend, col = "#dc2626", lty = 2, lwd = 2)
# Legenda
legend("topleft",
legend = c("Produksi Aktual (ribu m³)", "Garis Tren Linear"),
col = c("#1e40af", "#dc2626"),
pch = c(19, NA),
lty = c(1, 2),
lwd = 2,
bty = "n")
Fungsi bawaan plot(decomp_pdam) menampilkan keempat
komponen dekomposisi secara simultan:
# Visualisasi hasil dekomposisi aditif
plot(decomp_pdam, col = "#1e40af", lwd = 1.6)
Pada fungsi decompose(), komponen tren diestimasi
menggunakan filter rata-rata bergerak terpusat \(2 \times 12\text{-MA}\). Karena filter ini
memerlukan 6 titik data di sisi kiri dan 6 titik di sisi kanan, maka 6
bulan pertama (Januari–Juni 2022) dan 6 bulan terakhir (Juli–Desember
2024) bernilai NA.
Berikut nilai komponen tren yang dihasilkan:
# Menampilkan nilai tren dalam bentuk matriks tahun x bulan
tren_matrix <- matrix(round(decomp_pdam$trend, 2), nrow = 3, byrow = TRUE)
rownames(tren_matrix) <- c("2022", "2023", "2024")
colnames(tren_matrix) <- bulan
kable(tren_matrix, caption = "Tabel 2: Nilai Komponen Tren Volume Produksi (ribu m³/bulan)")
| Jan | Feb | Mar | Apr | Mei | Jun | Jul | Agu | Sep | Okt | Nov | Des | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2022 | NA | NA | NA | NA | NA | NA | 427.75 | 430.25 | 432.87 | 435.58 | 438.25 | 440.96 |
| 2023 | 443.71 | 446.42 | 449.12 | 451.83 | 454.50 | 457.21 | 459.83 | 462.38 | 464.92 | 467.46 | 470.08 | 472.75 |
| 2024 | 475.46 | 478.17 | 480.79 | 483.38 | 485.92 | 488.46 | NA | NA | NA | NA | NA | NA |
Grafik berikut membandingkan secara langsung kurva data aktual, kurva komponen tren hasil dekomposisi (\(T_t\)), dan garis tren linear:
plot(pdam_ts,
type = "l",
col = "#94a3b8",
lwd = 1.5,
lty = 1,
ylim = c(400, 530),
main = "Kurva Komponen Tren Volume Produksi Air Minum PDAM Kab. Serang",
xlab = "Bulan dan Tahun",
ylab = "Volume Produksi (ribu m³/bulan)",
xaxt = "n")
grid(col = "#cbd5e1", lty = "dotted")
axis(1, at = seq(2022, 2024 + 11/12, by = 1/12), labels = waktu_label, las = 2, cex.axis = 0.75)
# Menambahkan komponen tren hasil dekomposisi
lines(decomp_pdam$trend, col = "#1e40af", lwd = 3.2)
# Menambahkan garis tren regresi linear
abline(fit_trend, col = "#dc2626", lty = 2, lwd = 2)
# Legenda
legend("topleft",
legend = c("Data Aktual (Observed)", "Komponen Tren (2x12-MA)", "Garis Tren Linear"),
col = c("#94a3b8", "#1e40af", "#dc2626"),
lty = c(1, 1, 2),
lwd = c(1.5, 3.2, 2),
bty = "n")
Pada model dekomposisi aditif, indeks musiman (\(S_m\)) menyatakan penambahan atau pengurangan volume produksi (dalam ribu \(\text{m}^3\)) relatif terhadap nilai tren rata-rata. Jumlah total indeks musiman dalam satu siklus tahunan adalah nol (\(\sum_{m=1}^{12} S_m = 0\)).
# Mengambil 12 indeks musiman
indeks_musiman <- decomp_pdam$seasonal[1:12]
names(indeks_musiman) <- bulan
# Membuat tabel ringkasan indeks musiman
tabel_musiman <- data.frame(
Bulan = bulan,
Indeks_Musiman = round(indeks_musiman, 4),
Keterangan = ifelse(indeks_musiman > 0,
sprintf("+%.2f ribu m³ di atas tren", indeks_musiman),
sprintf("%.2f ribu m³ di bawah tren", indeks_musiman))
)
kable(tabel_musiman, caption = "Tabel 4: Indeks Musiman Aditif Bulanan PDAM Kabupaten Serang")
| Bulan | Indeks_Musiman | Keterangan | |
|---|---|---|---|
| Jan | Jan | -4.5399 | -4.54 ribu m³ di bawah tren |
| Feb | Feb | -1.7483 | -1.75 ribu m³ di bawah tren |
| Mar | Mar | -11.9149 | -11.91 ribu m³ di bawah tren |
| Apr | Apr | -0.0608 | -0.06 ribu m³ di bawah tren |
| Mei | Mei | 7.8351 | +7.84 ribu m³ di atas tren |
| Jun | Jun | 21.2101 | +21.21 ribu m³ di atas tren |
| Jul | Jul | 27.7517 | +27.75 ribu m³ di atas tren |
| Agu | Agu | 9.7309 | +9.73 ribu m³ di atas tren |
| Sep | Sep | -7.3524 | -7.35 ribu m³ di bawah tren |
| Okt | Okt | -15.4774 | -15.48 ribu m³ di bawah tren |
| Nov | Nov | -20.1233 | -20.12 ribu m³ di bawah tren |
| Des | Des | -5.3108 | -5.31 ribu m³ di bawah tren |
cat("Total Penjumlahan Indeks Musiman (harus mendekati 0):", sum(indeks_musiman))
## Total Penjumlahan Indeks Musiman (harus mendekati 0): 0
val_max <- max(indeks_musiman)
val_min <- min(indeks_musiman)
warna_bar <- ifelse(indeks_musiman == val_max, "#1e3a8a",
ifelse(indeks_musiman == val_min, "#dc2626",
ifelse(indeks_musiman > 0, "#60a5fa", "#94a3b8")))
bp <- barplot(indeks_musiman,
col = warna_bar,
border = NA,
ylim = c(-25, 35),
main = "Indeks Musiman Bulanan Volume Produksi Air Minum PDAM Kab. Serang",
xlab = "Bulan",
ylab = "Efek Musiman (ribu m³/bulan)")
grid(col = "#cbd5e1", lty = "dotted")
abline(h = 0, col = "#1e293b", lwd = 1.5)
# Label nilai di atas/bawah batang
text(bp, indeks_musiman + ifelse(indeks_musiman >= 0, 2.5, -2.8),
labels = sprintf("%+.1f", indeks_musiman), cex = 0.85, font = 2)
legend("topleft",
legend = c("Tertinggi (Juli)", "Terendah (November)", "Di Atas Tren (+)", "Di Bawah Tren (-)"),
fill = c("#1e3a8a", "#dc2626", "#60a5fa", "#94a3b8"),
bty = "n")
Untuk melihat konsistensi perulangan pola musiman setiap tahunnya, grafik musiman (seasonal plot) disajikan di bawah ini:
seasonplot(pdam_ts,
col = c("#93c5fd", "#3b82f6", "#1e3a8a"),
lwd = 2.2,
pch = 19,
type = "o",
ylim = c(395, 530),
year.labels = FALSE,
main = "Seasonal Plot: Pola Bulanan Volume Produksi per Tahun",
xlab = "Bulan",
ylab = "Volume Produksi (ribu m³/bulan)")
grid(col = "#cbd5e1", lty = "dotted")
legend("topleft",
legend = c("Tahun 2022", "Tahun 2023", "Tahun 2024"),
col = c("#93c5fd", "#3b82f6", "#1e3a8a"),
lwd = 2.2, pch = 19, bty = "n")
Berdasarkan Tabel 4 dan grafik di atas:
Komponen residu (random/irregular component) dihitung dengan mengurangkan komponen tren dan musiman dari data aktual:
\[R_t = Y_t - T_t - S_t\]
Nilai residu pada 6 bulan awal dan 6 bulan akhir adalah
NA mengikuti nilai komponen tren:
residu <- decomp_pdam$random
residu_matrix <- matrix(round(residu, 4), nrow = 3, byrow = TRUE)
rownames(residu_matrix) <- c("2022", "2023", "2024")
colnames(residu_matrix) <- bulan
kable(residu_matrix, caption = "Tabel 5: Nilai Komponen Residu Volume Produksi (ribu m³/bulan)")
| Jan | Feb | Mar | Apr | Mei | Jun | Jul | Agu | Sep | Okt | Nov | Des | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2022 | NA | NA | NA | NA | NA | NA | -0.5017 | 0.0191 | -0.5226 | -0.1059 | -0.1267 | -0.6476 |
| 2023 | 0.8316 | 0.3316 | 0.7899 | 0.2274 | -0.3351 | -0.4184 | 0.4149 | -0.1059 | 0.4358 | 0.0191 | 0.0399 | 0.5608 |
| 2024 | -0.9184 | -0.4184 | -0.8767 | -0.3142 | 0.2483 | 0.3316 | NA | NA | NA | NA | NA | NA |
Berikut ringkasan statistik deskriptif (five-number summary, nilai rata-rata, dan simpangan baku) dari komponen residu:
# Ringkasan statistik 5 angka
summary_res <- summary(residu)
# Simpangan baku dan rata-rata
sd_res <- sd(residu, na.rm = TRUE)
mean_res <- mean(residu, na.rm = TRUE)
n_valid <- sum(!is.na(residu))
df_stat_residu <- data.frame(
Ukuran_Statistik = c("Jumlah Observasi Valid", "Minimum", "Kuartil 1 (Q1)",
"Median", "Mean (Rata-rata)", "Kuartil 3 (Q3)",
"Maksimum", "Simpangan Baku (SD)"),
Nilai_Ribu_m3 = c(n_valid,
min(residu, na.rm = TRUE),
quantile(residu, probs = 0.25, na.rm = TRUE),
median(residu, na.rm = TRUE),
mean_res,
quantile(residu, probs = 0.75, na.rm = TRUE),
max(residu, na.rm = TRUE),
sd_res)
)
kable(df_stat_residu, digits = 4,
col.names = c("Ukuran Statistik", "Nilai (ribu m³/bulan)"),
caption = "Tabel 6: Ringkasan Statistik Komponen Residu")
| Ukuran Statistik | Nilai (ribu m³/bulan) |
|---|---|
| Jumlah Observasi Valid | 24.0000 |
| Minimum | -0.9184 |
| Kuartil 1 (Q1) | -0.4184 |
| Median | -0.0434 |
| Mean (Rata-rata) | -0.0434 |
| Kuartil 3 (Q3) | 0.3316 |
| Maksimum | 0.8316 |
| Simpangan Baku (SD) | 0.4863 |
Plot runtun waktu berikut memperlihatkan posisi pergerakan residu terhadap garis nol (\(y = 0\)) beserta batas kontrol \(\pm 2\) simpangan baku (\(\pm 2\text{SD}\)):
plot(residu,
type = "o",
pch = 19,
col = "#1e40af",
lwd = 2,
ylim = c(-1.5, 1.5),
main = "Komponen Residu (Random/Irregular) Volume Produksi Air Minum",
xlab = "Bulan dan Tahun",
ylab = "Residu (ribu m³/bulan)",
xaxt = "n")
grid(col = "#cbd5e1", lty = "dotted")
axis(1, at = seq(2022, 2024 + 11/12, by = 1/12), labels = waktu_label, las = 2, cex.axis = 0.75)
# Garis referensi nol dan batas 2 SD
abline(h = 0, col = "#dc2626", lwd = 2, lty = 2)
abline(h = c(-2 * sd_res, 2 * sd_res), col = "#475569", lty = 3, lwd = 1.5)
# Legenda
legend("topright",
legend = c("Nilai Residu (R_t)", "Garis Nol (Target Rata-rata)", "Batas ±2 SD (±0.9725)"),
col = c("#1e40af", "#dc2626", "#475569"),
pch = c(19, NA, NA),
lty = c(1, 2, 3),
lwd = c(2, 2, 1.5),
bty = "n")
Ya, komponen residu tampak berfluktuasi secara acak di sekitar nol.
Hal ini didasarkan pada empat pertimbangan statistik berikut:
Rata-Rata dan Median Sangat Dekat dengan Nol: Nilai rata-rata (mean) residu adalah \(-0{,}0434\) ribu \(\text{m}^3\) dan median residu adalah \(-0{,}0434\) ribu \(\text{m}^3\). Kedua nilai pemusatan ini berada tepat di sekitar angka nol, yang menandakan tidak ada bias sistematis (unbiased) dalam model dekomposisi.
Magnitudo Residu Sangat Kecil Relatif terhadap Data:
Penyebaran Residu Berada di Dalam Batas Toleransi: Seluruh titik observasi residu berada rapat di dalam batas toleransi \(\pm 2\text{SD}\) (antara \(-0{,}9725\) hingga \(+0{,}9725\)). Tidak ada satupun pencilan (outlier) ekstrem.
Ketiadaan Pola Tertinggal (White Noise Behavior): Pada grafik, titik-titik residu bergerak bergantian melintasi garis merah putus-putus (\(y=0\)) tanpa membentuk pola gelombang, tren berlanjut, maupun osilasi musiman yang tertinggal. Residu murni mencerminkan goncangan acak sesaat (random shocks), seperti perbaikan pipa darurat atau fluktuasi cuaca lokal yang wajar.
Berdasarkan keseluruhan tahapan analisis dekomposisi aditif di atas, dapat dirangkum kesimpulan sebagai berikut: