Data berikut merupakan catatan historis 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 |
Dekomposisi runtun waktu (time series decomposition) adalah metode statistika klasik yang bertujuan memisahkan deret observasi aktual (\(Y_t\)) menjadi komponen-komponen penyusunnya: 1. Tren-Siklis (\(T_t\)): Arah pergerakan jangka panjang (long-term trend) yang mencerminkan pertumbuhan atau penurunan berkelanjutan serta fluktuasi siklis jangka menengah. 2. Musiman (\(S_t\)): Pola fluktuasi yang berulang secara periodik dan teratur dalam siklus waktu tetap (pada data bulanan, periodenya adalah 12 bulan). 3. Residu / Acak (\(R_t\) atau \(I_t\)): Variasi irregular sisa yang bersifat acak (random shock) setelah pengaruh tren dan musiman dieliminasi.
Berdasarkan cara interaksi antar-komponennya, terdapat dua pendekatan utama dekomposisi:
Pada model aditif, nilai observasi diasumsikan sebagai hasil penjumlahan ketiga komponen:
\[Y_t = T_t + S_t + R_t\]
Pada model multiplikatif, nilai observasi diasumsikan sebagai hasil perkalian ketiga komponen:
\[Y_t = T_t \times S_t \times R_t\]
Tabel berikut merangkum perbedaan prinsipil kedua pendekatan:
| Aspek Pembanding | Dekomposisi Aditif | Dekomposisi Multiplikatif |
|---|---|---|
| Persamaan Matematis | \(Y_t = T_t + S_t + R_t\) | \(Y_t = T_t \times S_t \times R_t\) |
| Amplitudo Musiman | Konstan / stabil dari tahun ke tahun | Berubah proporsional terhadap level tren |
| Satuan Indeks Musiman | Sama dengan data asli (ribu \(\text{m}^3\)/bulan) | Rasio / pengali (proporsi / persentase) |
| Pusat Indeks Musiman | Berpusat di \(0\) (\(\sum S_m = 0\)) | Berpusat di \(1{,}0\) (\(\sum S_m = 12\)) |
| Pusat Residu (\(R_t\)) | Berfluktuasi di sekitar \(0\) (\(E[R_t]=0\)) | Berfluktuasi di sekitar \(1{,}0\) (\(E[R_t]=1\)) |
| Formula Desesonalisasi | \(Y_t - S_t = T_t + R_t\) | \(Y_t / S_t = T_t \times R_t\) |
| Kesesuaian Data | Rentang musiman absolut stabil | Rentang musiman melebar saat tren naik |
ts dan Eksekusi Kedua ModelSeluruh 36 observasi bulanan (2022–2024) digabungkan menjadi satu
objek time series ts dengan frekuensi 12:
# Menggabungkan data menjadi satu vektor runtut
total_produksi <- c(pdam_2022, pdam_2023, pdam_2024)
# 1. Membuat objek time series bulanan
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
Dekomposisi dijalankan menggunakan fungsi standar
decompose() dalam base R dengan parameter
type = "additive" dan
type = "multiplicative":
# 2. Dekomposisi Aditif
decomp_add <- decompose(pdam_ts, type = "additive")
# 3. Dekomposisi Multiplikatif
decomp_mult <- decompose(pdam_ts, type = "multiplicative")
Grafik berikut menyajikan pergerakan aktual volume produksi air minum bulanan beserta garis tren linear regresi:
# Konfigurasi label sumbu X (36 bulan)
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 kisi-kisi (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"
)
# Visualisasi hasil dekomposisi aditif
plot(decomp_add, col = "#1e40af", lwd = 1.6)
# Visualisasi hasil dekomposisi multiplikatif
plot(decomp_mult, col = "#0d9488", lwd = 1.6)
Perbandingan kedua plot di atas memperlihatkan perbedaan fundamental pada skala sumbu Y komponen:
Pada fungsi decompose(), komponen tren diestimasi
menggunakan filter rata-rata bergerak terpusat \(2 \times 12\text{-MA}\) (two-by-twelve
moving average). Filter ini menggunakan bobot:
\[T_t = \frac{\frac{1}{2}Y_{t-6} + Y_{t-5} + \dots + Y_{t} + \dots + Y_{t+5} + \frac{1}{2}Y_{t+6}}{12}\]
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. Nilai tren pada
model aditif dan multiplikatif adalah sama persis.
Berikut matriks nilai komponen tren:
# Matriks komponen tren (tahun x bulan)
tren_matrix <- matrix(round(decomp_add$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 regresi:
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_add$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"
)
Tabel berikut menyajikan nilai indeks musiman dari model aditif (\(S_{add}\)) dan multiplikatif (\(S_{mult}\)):
# Mengambil 12 indeks musiman dari kedua model
indeks_add <- decomp_add$seasonal[1:12]
indeks_mult <- decomp_mult$seasonal[1:12]
names(indeks_add) <- bulan
names(indeks_mult) <- bulan
# Efek persentase pada model multiplikatif
efek_persen_mult <- (indeks_mult - 1) * 100
# Menyusun data frame komparasi
df_musiman_komparasi <- data.frame(
Bulan = bulan,
Indeks_Aditif = round(indeks_add, 4),
Keterangan_Aditif = ifelse(indeks_add > 0,
sprintf("+%.2f ribu m³ di atas tren", indeks_add),
sprintf("%.2f ribu m³ di bawah tren", indeks_add)
),
Indeks_Multiplikatif = round(indeks_mult, 4),
Deviasi_Persen = sprintf("%+.2f%%", efek_persen_mult),
Keterangan_Multiplikatif = ifelse(indeks_mult > 1,
sprintf("+%.2f%% di atas tren", efek_persen_mult),
sprintf("%.2f%% di bawah tren", abs(efek_persen_mult))
)
)
kable(
df_musiman_komparasi[, c(
"Bulan", "Indeks_Aditif", "Keterangan_Aditif",
"Indeks_Multiplikatif", "Deviasi_Persen", "Keterangan_Multiplikatif"
)],
caption = "Tabel 4: Perbandingan Indeks Musiman Aditif dan Multiplikatif Bulanan"
)
| Bulan | Indeks_Aditif | Keterangan_Aditif | Indeks_Multiplikatif | Deviasi_Persen | Keterangan_Multiplikatif | |
|---|---|---|---|---|---|---|
| Jan | Jan | -4.5399 | -4.54 ribu m³ di bawah tren | 0.9902 | -0.98% | 0.98% di bawah tren |
| Feb | Feb | -1.7483 | -1.75 ribu m³ di bawah tren | 0.9963 | -0.37% | 0.37% di bawah tren |
| Mar | Mar | -11.9149 | -11.91 ribu m³ di bawah tren | 0.9744 | -2.56% | 2.56% di bawah tren |
| Apr | Apr | -0.0608 | -0.06 ribu m³ di bawah tren | 0.9999 | -0.01% | 0.01% di bawah tren |
| Mei | Mei | 7.8351 | +7.84 ribu m³ di atas tren | 1.0167 | +1.67% | +1.67% di atas tren |
| Jun | Jun | 21.2101 | +21.21 ribu m³ di atas tren | 1.0449 | +4.49% | +4.49% di atas tren |
| Jul | Jul | 27.7517 | +27.75 ribu m³ di atas tren | 1.0626 | +6.26% | +6.26% di atas tren |
| Agu | Agu | 9.7309 | +9.73 ribu m³ di atas tren | 1.0218 | +2.18% | +2.18% di atas tren |
| Sep | Sep | -7.3524 | -7.35 ribu m³ di bawah tren | 0.9836 | -1.64% | 1.64% di bawah tren |
| Okt | Okt | -15.4774 | -15.48 ribu m³ di bawah tren | 0.9657 | -3.43% | 3.43% di bawah tren |
| Nov | Nov | -20.1233 | -20.12 ribu m³ di bawah tren | 0.9556 | -4.44% | 4.44% di bawah tren |
| Des | Des | -5.3108 | -5.31 ribu m³ di bawah tren | 0.9883 | -1.17% | 1.17% di bawah tren |
Secara teoritis, normalisasi indeks musiman harus memenuhi kondisi berikut:
sum_add <- sum(indeks_add)
mean_mult <- mean(indeks_mult)
sum_mult <- sum(indeks_mult)
cat(sprintf("1. Penjumlahan Indeks Musiman Aditif : %.6f (harus tepat 0)\n", sum_add))
## 1. Penjumlahan Indeks Musiman Aditif : 0.000000 (harus tepat 0)
cat(sprintf("2. Rata-rata Indeks Musiman Multiplikatif : %.6f (harus tepat 1.0)\n", mean_mult))
## 2. Rata-rata Indeks Musiman Multiplikatif : 1.000000 (harus tepat 1.0)
cat(sprintf("3. Penjumlahan Indeks Musiman Multiplikatif : %.6f (harus tepat 12.0)\n", sum_mult))
## 3. Penjumlahan Indeks Musiman Multiplikatif : 12.000000 (harus tepat 12.0)
Kedua model memenuhi sifat normalisasi matematis dengan sempurna.
Grafik batang berdampingan berikut memperjelas perbedaan unit pengukuran kedua model:
par(mfrow = c(1, 2), mar = c(4.5, 4.2, 3.5, 1.5))
# 1. Barplot Aditif
val_max_add <- max(indeks_add)
val_min_add <- min(indeks_add)
warna_add <- ifelse(indeks_add == val_max_add, "#1e3a8a",
ifelse(indeks_add == val_min_add, "#dc2626",
ifelse(indeks_add > 0, "#60a5fa", "#94a3b8")
)
)
bp1 <- barplot(indeks_add,
col = warna_add,
border = NA,
ylim = c(-26, 36),
main = "Indeks Musiman Aditif\n(ribu m³/bulan)",
xlab = "Bulan",
ylab = "Efek Selisih terhadap Tren (ribu m³)",
cex.names = 0.8
)
grid(col = "#cbd5e1", lty = "dotted")
abline(h = 0, col = "#1e293b", lwd = 1.4)
text(bp1, indeks_add + ifelse(indeks_add >= 0, 2.5, -2.8),
labels = sprintf("%+.1f", indeks_add), cex = 0.75, font = 2
)
# 2. Barplot Multiplikatif (dalam persentase deviasi dari 100%)
val_max_mult <- max(efek_persen_mult)
val_min_mult <- min(efek_persen_mult)
warna_mult <- ifelse(efek_persen_mult == val_max_mult, "#0f766e",
ifelse(efek_persen_mult == val_min_mult, "#dc2626",
ifelse(efek_persen_mult > 0, "#2dd4bf", "#94a3b8")
)
)
bp2 <- barplot(efek_persen_mult,
col = warna_mult,
border = NA,
ylim = c(-6.5, 8.5),
main = "Indeks Musiman Multiplikatif\n(% Deviasi dari Tren)",
xlab = "Bulan",
ylab = "Persentase terhadap Tren (%)",
cex.names = 0.8
)
grid(col = "#cbd5e1", lty = "dotted")
abline(h = 0, col = "#1e293b", lwd = 1.4)
text(bp2, efek_persen_mult + ifelse(efek_persen_mult >= 0, 0.65, -0.75),
labels = sprintf("%+.1f%%", efek_persen_mult), cex = 0.75, font = 2
)
par(mfrow = c(1, 1))
Untuk melihat konsistensi perulangan kurva 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 kedua grafik di atas, kedua model mengidentifikasi bulan puncak dan lembah yang persis sama:
Berikut matriks nilai residu dari kedua model:
residu_add <- decomp_add$random
residu_mult <- decomp_mult$random
mat_res_add <- matrix(round(residu_add, 4), nrow = 3, byrow = TRUE)
mat_res_mult <- matrix(round(residu_mult, 4), nrow = 3, byrow = TRUE)
rownames(mat_res_add) <- rownames(mat_res_mult) <- c("2022", "2023", "2024")
colnames(mat_res_add) <- colnames(mat_res_mult) <- bulan
kable(mat_res_add, caption = "Tabel 5A: Nilai Residu Aditif (ribu m³/bulan, berpusat di 0)")
| 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 |
kable(mat_res_mult, caption = "Tabel 5B: Nilai Residu Multiplikatif (Rasio, berpusat di 1.0)")
| Jan | Feb | Mar | Apr | Mei | Jun | Jul | Agu | Sep | Okt | Nov | Des | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2022 | NA | NA | NA | NA | NA | NA | 1.0010 | 1.0008 | 0.9982 | 0.9985 | 0.9981 | 0.9981 |
| 2023 | 1.0015 | 1.0006 | 1.0008 | 1.0005 | 0.9998 | 1.0006 | 0.9987 | 0.9990 | 1.0016 | 1.0013 | 1.0017 | 1.0016 |
| 2024 | 0.9983 | 0.9992 | 0.9990 | 0.9993 | 1.0000 | 0.9992 | NA | NA | NA | NA | NA | NA |
Ringkasan statistik (five-number summary, rata-rata, dan simpangan baku) disajikan berdampingan:
sd_res_add <- sd(residu_add, na.rm = TRUE)
mean_res_add <- mean(residu_add, na.rm = TRUE)
sd_res_mult <- sd(residu_mult, na.rm = TRUE)
mean_res_mult <- mean(residu_mult, na.rm = TRUE)
n_valid <- sum(!is.na(residu_add))
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)"
),
Model_Aditif = c(
n_valid,
min(residu_add, na.rm = TRUE),
quantile(residu_add, probs = 0.25, na.rm = TRUE),
median(residu_add, na.rm = TRUE),
mean_res_add,
quantile(residu_add, probs = 0.75, na.rm = TRUE),
max(residu_add, na.rm = TRUE),
sd_res_add
),
Model_Multiplikatif = c(
n_valid,
min(residu_mult, na.rm = TRUE),
quantile(residu_mult, probs = 0.25, na.rm = TRUE),
median(residu_mult, na.rm = TRUE),
mean_res_mult,
quantile(residu_mult, probs = 0.75, na.rm = TRUE),
max(residu_mult, na.rm = TRUE),
sd_res_mult
)
)
kable(df_stat_residu,
digits = 6,
col.names = c("Ukuran Statistik", "Model Aditif (ribu m³)", "Model Multiplikatif (Rasio)"),
caption = "Tabel 6: Ringkasan Statistik Komparatif Komponen Residu"
)
| Ukuran Statistik | Model Aditif (ribu m³) | Model Multiplikatif (Rasio) |
|---|---|---|
| Jumlah Observasi Valid | 24.000000 | 24.000000 |
| Minimum | -0.918403 | 0.998070 |
| Kuartil 1 (Q1) | -0.418403 | 0.998898 |
| Median | -0.043403 | 0.999893 |
| Mean (Rata-rata) | -0.043403 | 0.999893 |
| Kuartil 3 (Q3) | 0.331597 | 1.000887 |
| Maksimum | 0.831597 | 1.001715 |
| Simpangan Baku (SD) | 0.486262 | 0.001249 |
Dua plot berikut menampilkan deret waktu residu aditif (terhadap baseline \(y=0\)) dan residu multiplikatif (terhadap baseline \(y=1{,}0\)) lengkap dengan batas kendali \(\pm 2\text{SD}\):
par(mfrow = c(2, 1), mar = c(4.2, 4.2, 2.8, 1.5))
# 1. Residu Aditif
plot(residu_add,
type = "o",
pch = 19,
col = "#1e40af",
lwd = 1.8,
ylim = c(-1.5, 1.5),
main = "Komponen Residu Aditif (Baseline = 0)",
xlab = "",
ylab = "Residu (ribu m³)",
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.7)
abline(h = 0, col = "#dc2626", lwd = 2, lty = 2)
abline(h = c(-2 * sd_res_add, 2 * sd_res_add), col = "#475569", lty = 3, lwd = 1.5)
legend("topright",
legend = c("Residu Aditif (R_add)", "Garis Nol", sprintf("Batas ±2 SD (±%.4f)", 2 * sd_res_add)),
col = c("#1e40af", "#dc2626", "#475569"),
pch = c(19, NA, NA), lty = c(1, 2, 3), lwd = c(1.8, 2, 1.5), bty = "n", cex = 0.8
)
# 2. Residu Multiplikatif
plot(residu_mult,
type = "o",
pch = 19,
col = "#0d9488",
lwd = 1.8,
ylim = c(0.996, 1.004),
main = "Komponen Residu Multiplikatif (Baseline = 1.0)",
xlab = "Bulan dan Tahun",
ylab = "Residu (Rasio)",
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.7)
abline(h = 1, col = "#dc2626", lwd = 2, lty = 2)
abline(h = c(1 - 2 * sd_res_mult, 1 + 2 * sd_res_mult), col = "#475569", lty = 3, lwd = 1.5)
legend("topright",
legend = c("Residu Multiplikatif (R_mult)", "Garis Satu (Target)", sprintf("Batas ±2 SD (1 ± %.4f)", 2 * sd_res_mult)),
col = c("#0d9488", "#dc2626", "#475569"),
pch = c(19, NA, NA), lty = c(1, 2, 3), lwd = c(1.8, 2, 1.5), bty = "n", cex = 0.8
)
par(mfrow = c(1, 1))
Berdasarkan analisis statistik dan grafik residu kedua model:
Data penyesuaian musiman (seasonally adjusted data / desesonalisasi) adalah deret waktu yang telah dibersihkan dari pengaruh musim. Data ini sangat penting bagi manajemen PDAM untuk mengevaluasi apakah fluktuasi produksi pada suatu bulan murni merupakan perubahan kinerja riil atau sekadar pengaruh musim rutin tahunan.
# Menghitung deret penyesuaian musiman
sa_add <- pdam_ts - decomp_add$seasonal
sa_mult <- pdam_ts / decomp_mult$seasonal
plot(pdam_ts,
type = "l",
col = "#94a3b8",
lwd = 1.4,
lty = 1,
ylim = c(400, 530),
main = "Data Aktual vs Data Penyesuaian Musiman (Seasonally Adjusted)",
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)
# Kurva Desesonalisasi Aditif
lines(sa_add, col = "#1e40af", lwd = 2.4)
# Kurva Desesonalisasi Multiplikatif
lines(sa_mult, col = "#0d9488", lwd = 2, lty = 2)
# Kurva Tren 2x12-MA
lines(decomp_add$trend, col = "#dc2626", lwd = 2.5)
legend("topleft",
legend = c(
"Data Aktual (Musiman Ada)", "Penyesuaian Musiman Aditif (Y - S)",
"Penyesuaian Musiman Multiplikatif (Y / S)", "Komponen Tren (2x12-MA)"
),
col = c("#94a3b8", "#1e40af", "#0d9488", "#dc2626"),
lty = c(1, 1, 2, 1),
lwd = c(1.4, 2.4, 2, 2.5),
bty = "n"
)
Setelah variasi musiman dieliminasi, kurva penyesuaian musiman dari kedua model bergerak sangat berdekatan dan nyaris berimpit dengan kurva tren, mengonfirmasi kestabilan pertumbuhan riil produksi air minum PDAM Kabupaten Serang.
Untuk menentukan apakah Model Aditif atau Model Multiplikatif yang lebih cocok bagi volume produksi air minum PDAM Kabupaten Serang, kita melakukan dua evaluasi komprehensif:
Kriteria utama dalam memilih model dekomposisi adalah perilaku variabilitas musiman terhadap kenaikan level tren: - Jika selisih antara nilai puncak dan nilai terendah (peak-to-trough amplitude) dalam tiap tahun bernilai konstan absolut, maka Model Aditif adalah model yang tepat. - Jika selisih absolut melebar seiring naiknya tren namun persentase rasionya konstan, maka Model Multiplikatif lebih tepat.
Mari kita hitung amplitudo musiman riil tahunan:
rentang_2022 <- max(pdam_2022) - min(pdam_2022)
rentang_2023 <- max(pdam_2023) - min(pdam_2023)
rentang_2024 <- max(pdam_2024) - min(pdam_2024)
rasio_2022 <- (rentang_2022 / mean_2022) * 100
rasio_2023 <- (rentang_2023 / mean_2023) * 100
rasio_2024 <- (rentang_2024 / mean_2024) * 100
df_amplitudo <- data.frame(
Tahun = c("2022", "2023", "2024"),
Rata_Rata_Tren = c(mean_2022, mean_2023, mean_2024),
Nilai_Maksimum_Juli = c(pdam_2022[7], pdam_2023[7], pdam_2024[7]),
Nilai_Minimum_Maret = c(pdam_2022[3], pdam_2023[3], pdam_2024[3]),
Rentang_Musiman_Absolut = c(rentang_2022, rentang_2023, rentang_2024),
Rasio_Rentang_terhadap_Rata2 = sprintf("%.2f%%", c(rasio_2022, rasio_2023, rasio_2024))
)
kable(df_amplitudo,
col.names = c(
"Tahun", "Rata-rata (ribu m³)", "Puncak Juli", "Lembah Maret",
"Amplitudo Absolut (ribu m³)", "Rasio terhadap Rata-rata (%)"
),
caption = "Tabel 7: Evaluasi Kestabilan Amplitudo Musiman per Tahun"
)
| Tahun | Rata-rata (ribu m³) | Puncak Juli | Lembah Maret | Amplitudo Absolut (ribu m³) | Rasio terhadap Rata-rata (%) |
|---|---|---|---|---|---|
| 2022 | 426.5000 | 455 | 405 | 50 | 11.72% |
| 2023 | 458.5833 | 488 | 438 | 50 | 10.90% |
| 2024 | 489.7500 | 521 | 468 | 53 | 10.82% |
Nilai kecocokan (fitted values) dari masing-masing model dihitung sebagai kombinasi komponen tren dan musiman: * Fitted Aditif: \(\hat{Y}_{add, t} = T_t + S_{add, t}\) * Fitted Multiplikatif: \(\hat{Y}_{mult, t} = T_t \times S_{mult, t}\)
Galat (error) dihitung terhadap data aktual yang memiliki nilai tren valid (24 bulan pengamatan, Juli 2022 – Juni 2024): \[e_{add, t} = Y_t - \hat{Y}_{add, t} \qquad \text{dan} \qquad e_{mult, t} = Y_t - \hat{Y}_{mult, t}\]
Kriteria akurasi yang digunakan: 1. Mean Absolute Error (MAE): \(\text{MAE} = \frac{1}{n} \sum |e_t|\) 2. Mean Squared Error (MSE): \(\text{MSE} = \frac{1}{n} \sum e_t^2\) 3. Root Mean Squared Error (RMSE): \(\text{RMSE} = \sqrt{\text{MSE}}\) 4. Mean Absolute Percentage Error (MAPE): \(\text{MAPE} = \frac{1}{n} \sum \left|\frac{e_t}{Y_t}\right| \times 100\%\)
# Menghitung fitted values
fitted_add <- decomp_add$trend + decomp_add$seasonal
fitted_mult <- decomp_mult$trend * decomp_mult$seasonal
# Mengambil indeks yang tidak NA (24 observasi valid)
valid_idx <- which(!is.na(decomp_add$trend))
y_val <- pdam_ts[valid_idx]
fit_add_val <- fitted_add[valid_idx]
fit_mult_val <- fitted_mult[valid_idx]
# Galat / Error
err_add <- y_val - fit_add_val
err_mult <- y_val - fit_mult_val
# Perhitungan metrik
mae_add <- mean(abs(err_add))
mae_mult <- mean(abs(err_mult))
mse_add <- mean(err_add^2)
mse_mult <- mean(err_mult^2)
rmse_add <- sqrt(mse_add)
rmse_mult <- sqrt(mse_mult)
mape_add <- mean(abs(err_add / y_val)) * 100
mape_mult <- mean(abs(err_mult / y_val)) * 100
df_evaluasi <- data.frame(
Metrik_Evaluasi = c(
"Mean Absolute Error (MAE)",
"Mean Squared Error (MSE)",
"Root Mean Squared Error (RMSE)",
"Mean Absolute Percentage Error (MAPE)"
),
Model_Aditif = c(
sprintf("%.4f ribu m³", mae_add),
sprintf("%.4f", mse_add),
sprintf("%.4f ribu m³", rmse_add),
sprintf("%.4f%%", mape_add)
),
Model_Multiplikatif = c(
sprintf("%.4f ribu m³", mae_mult),
sprintf("%.4f", mse_mult),
sprintf("%.4f ribu m³", rmse_mult),
sprintf("%.4f%%", mape_mult)
),
Model_Terbaik = c(
"Aditif (Lebih Kecil 20.5%)",
"Aditif (Lebih Kecil 24.9%)",
"Aditif (Lebih Kecil 13.4%)",
"Aditif (Lebih Kecil 21.4%)"
)
)
kable(df_evaluasi,
col.names = c("Kriteria Evaluasi Akurasi", "Model Aditif", "Model Multiplikatif", "Keunggulan Relatif"),
caption = "Tabel 8: Perbandingan Metrik Akurasi Dekomposisi Aditif vs Multiplikatif"
)
| Kriteria Evaluasi Akurasi | Model Aditif | Model Multiplikatif | Keunggulan Relatif |
|---|---|---|---|
| Mean Absolute Error (MAE) | 0.3976 ribu m³ | 0.5000 ribu m³ | Aditif (Lebih Kecil 20.5%) |
| Mean Squared Error (MSE) | 0.2285 | 0.3044 | Aditif (Lebih Kecil 24.9%) |
| Root Mean Squared Error (RMSE) | 0.4780 ribu m³ | 0.5517 ribu m³ | Aditif (Lebih Kecil 13.4%) |
| Mean Absolute Percentage Error (MAPE) | 0.0868% | 0.1105% | Aditif (Lebih Kecil 21.4%) |
Berdasarkan perbandingan komprehensif di atas:
Dari keseluruhan tahapan analisis dekomposisi aditif dan multiplikatif yang telah dilakukan terhadap data volume produksi air minum PDAM Kabupaten Serang periode 2022–2024, dapat disimpulkan poin-poin utama sebagai berikut: