Transformasi, Differencing, dan Evaluasi Ramalan Harga GKP Kabupaten Serang

1 Gambaran Umum

Analisis ini membahas harga Gabah Kering Panen (GKP) di tingkat petani Kabupaten Serang selama Januari 2023 sampai Desember 2024.

Data terdiri atas 24 observasi bulanan. Analisis diarahkan pada tiga pertanyaan utama:

  1. Bagaimana karakteristik pergerakan harga GKP sepanjang periode pengamatan?
  2. Apakah transformasi logaritma dan differencing dapat membantu menstabilkan runtun waktu?
  3. Seberapa besar kesalahan yang dihasilkan oleh naive forecast pada tiga bulan terakhir?

Workflow analisis:

Data GKP
   ↓
Time Series
   ↓
Eksplorasi Visual
   ↓
Transformasi Logaritma
   ↓
First Differencing
   ↓
Train–Test Split
   ↓
Naive Forecast
   ↓
ME • MAE • MSE • RMSE • MAPE
   ↓
Interpretasi

Fokus analisis

Transformasi log digunakan untuk mengevaluasi kestabilan variansi, sedangkan differencing digunakan untuk melihat apakah kecenderungan/tren pada mean dapat dikurangi. Setelah itu, evaluasi forecast dilakukan menggunakan data aktual pada tiga periode terakhir.

2 Data dan Pembentukan Runtun Waktu

2.1 Input Data

Data harga GKP diberikan dalam satuan Rp/kg.

gkp <- c(
  5200, 5150, 5300, 5400, 5250, 5350,
  5450, 5500, 5400, 5550, 5600, 5700,
  5650, 5700, 5800, 5900, 5750, 5850,
  5950, 6000, 5900, 6050, 6150, 6300
)

tanggal <- seq(
  from = as.Date("2023-01-01"),
  by = "month",
  length.out = length(gkp)
)

gkp_df <- data.frame(
  tanggal = tanggal,
  tahun = format(tanggal, "%Y"),
  bulan = format(tanggal, "%b"),
  harga = gkp
)

gkp_ts <- ts(
  gkp,
  start = c(2023, 1),
  frequency = 12
)

2.2 Struktur Data

overview <- tibble(
  Informasi = c(
    "Periode",
    "Jumlah observasi",
    "Frekuensi",
    "Harga minimum",
    "Harga maksimum",
    "Harga rata-rata"
  ),
  Nilai = c(
    "Januari 2023 – Desember 2024",
    length(gkp_ts),
    "Bulanan",
    paste0("Rp ", comma(min(gkp_ts))),
    paste0("Rp ", comma(max(gkp_ts))),
    paste0("Rp ", comma(round(mean(gkp_ts), 2)))
  )
)

kable(
  overview,
  align = c("l", "l"),
  caption = "Ringkasan Data Harga GKP"
) |>
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width = FALSE
  )
Ringkasan Data Harga GKP
Informasi Nilai
Periode Januari 2023 – Desember 2024
Jumlah observasi 24
Frekuensi Bulanan
Harga minimum Rp 5,150
Harga maksimum Rp 6,300
Harga rata-rata Rp 5,660

2.3 Plot Runtun Waktu

Visualisasi pertama digunakan untuk melihat pola data sebelum dilakukan transformasi apa pun.

ggplot(gkp_df, aes(tanggal, harga)) +
  geom_area(
    aes(y = harga),
    alpha = 0.12
  ) +
  geom_line(
    linewidth = 1
  ) +
  geom_point(
    size = 2.4
  ) +
  geom_smooth(
    method = "loess",
    se = FALSE,
    linewidth = 0.8,
    linetype = "dashed"
  ) +
  scale_y_continuous(
    labels = label_number(big.mark = "."),
    expand = expansion(mult = c(0.02, 0.06))
  ) +
  scale_x_date(
    date_breaks = "3 months",
    date_labels = "%b\n%Y"
  ) +
  labs(
    title = "Harga GKP Menunjukkan Kecenderungan Meningkat",
    subtitle = "Pergerakan bulanan dengan garis tren lokal sebagai panduan visual",
    x = NULL,
    y = "Harga (Rp/kg)",
    caption = "Sumber: Data latihan Analisis Deret Waktu"
  ) +
  theme_minimal(base_size = 12) +
  theme(
    axis.text.x = element_text(angle = 0),
    plot.title = element_text(face = "bold", size = 15),
    plot.subtitle = element_text(color = "grey40"),
    panel.grid.minor = element_blank()
  )
Pergerakan harga GKP Kabupaten Serang, Januari 2023–Desember 2024.

Pergerakan harga GKP Kabupaten Serang, Januari 2023–Desember 2024.

2.3.1 Pembacaan Awal

Secara visual, harga GKP bergerak pada level yang lebih rendah di awal 2023 dan mencapai level yang lebih tinggi pada akhir 2024. Dengan demikian, terdapat kecenderungan naik secara keseluruhan, meskipun beberapa bulan mengalami penurunan sementara.

Pola tersebut menjadi alasan untuk melanjutkan analisis ke tahap transformasi dan differencing.

3 Transformasi Logaritma

3.1 Mengapa Logaritma?

Transformasi logaritma digunakan untuk melihat apakah perubahan pada skala data dapat dibuat lebih proporsional terhadap level pengamatan.

Secara matematis:

\[ W_t = \ln(Z_t) \]

Transformasi ini terutama relevan ketika fluktuasi absolut cenderung meningkat bersama level data.

log_gkp <- log(gkp_ts)

gkp_df <- gkp_df |>
  mutate(
    log_harga = as.numeric(log_gkp)
  )

3.2 Perbandingan Skala Asli dan Logaritmik

plot_data <- gkp_df |>
  select(tanggal, harga, log_harga) |>
  pivot_longer(
    cols = c(harga, log_harga),
    names_to = "series",
    values_to = "nilai"
  ) |>
  mutate(
    series = recode(
      series,
      harga = "Harga asli",
      log_harga = "Logaritma harga"
    )
  )

ggplot(plot_data, aes(tanggal, nilai)) +
  geom_line(linewidth = 1) +
  geom_point(size = 1.8) +
  facet_wrap(
    ~series,
    scales = "free_y",
    ncol = 1
  ) +
  scale_x_date(
    date_breaks = "3 months",
    date_labels = "%b\n%Y"
  ) +
  labs(
    title = "Perbandingan Sebelum dan Sesudah Transformasi Log",
    subtitle = "Transformasi mengubah skala, bukan urutan waktu pengamatan",
    x = NULL,
    y = NULL
  ) +
  theme_minimal(base_size = 12) +
  theme(
    plot.title = element_text(face = "bold", size = 15),
    strip.text = element_text(face = "bold"),
    panel.grid.minor = element_blank()
  )

3.3 Perbandingan Penyebaran

variability <- tibble(
  Series = c(
    "Harga asli",
    "Log harga"
  ),
  Mean = c(
    mean(gkp_ts),
    mean(log_gkp)
  ),
  SD = c(
    sd(gkp_ts),
    sd(log_gkp)
  )
)

kable(
  variability,
  digits = 4,
  caption = "Perbandingan ukuran penyebaran sebelum dan sesudah transformasi"
) |>
  kable_styling(
    bootstrap_options = c("striped", "hover"),
    full_width = FALSE
  )
Perbandingan ukuran penyebaran sebelum dan sesudah transformasi
Series Mean SD
Harga asli 5660.42 314.1514
Log harga 8.64 0.0554

Catatan interpretasi

Perbandingan standar deviasi antar-skala perlu dibaca dengan hati-hati karena harga asli dan log harga memiliki satuan/skala yang berbeda. Oleh sebab itu, keberhasilan transformasi tidak ditentukan hanya dari angka SD yang lebih kecil, tetapi juga dari pola visual penyebaran data setelah transformasi.

4 First Differencing

4.1 Differencing pada Data Logaritmik

Setelah transformasi logaritma, dilakukan differencing tingkat pertama:

\[ \Delta W_t = W_t-W_{t-1} \]

atau:

\[ \Delta\ln(Z_t) = \ln(Z_t)-\ln(Z_{t-1}) \]

Dalam konteks ini, perubahan tersebut juga dapat dibaca sebagai ukuran perubahan relatif antarperiode.

diff_log_gkp <- diff(log_gkp)

diff_df <- data.frame(
  tanggal = tanggal[-1],
  diff_log = as.numeric(diff_log_gkp)
)

4.2 Visualisasi Differencing

ggplot(diff_df, aes(tanggal, diff_log)) +
  geom_hline(
    yintercept = 0,
    linetype = "dashed",
    linewidth = 0.7
  ) +
  geom_col(
    alpha = 0.65,
    width = 20
  ) +
  geom_line(
    linewidth = 0.8
  ) +
  scale_x_date(
    date_breaks = "3 months",
    date_labels = "%b\n%Y"
  ) +
  scale_y_continuous(
    labels = percent_format(accuracy = 0.1)
  ) +
  labs(
    title = "First Difference dari Log Harga GKP",
    subtitle = "Perubahan relatif antarbulan setelah transformasi logaritma",
    x = NULL,
    y = "Δ log(GKP)",
    caption = "Nilai positif menunjukkan kenaikan relatif dari bulan sebelumnya."
  ) +
  theme_minimal(base_size = 12) +
  theme(
    plot.title = element_text(face = "bold", size = 15),
    panel.grid.minor = element_blank()
  )

4.3 Ringkasan Hasil Differencing

diff_summary <- tibble(
  Statistik = c(
    "Rata-rata",
    "Standar deviasi",
    "Minimum",
    "Maksimum"
  ),
  Nilai = c(
    mean(diff_log_gkp),
    sd(diff_log_gkp),
    min(diff_log_gkp),
    max(diff_log_gkp)
  )
)

kable(
  diff_summary,
  digits = 5,
  caption = "Ringkasan first difference log harga"
) |>
  kable_styling(
    bootstrap_options = c("striped", "hover"),
    full_width = FALSE
  )
Ringkasan first difference log harga
Statistik Nilai
Rata-rata 0.00834
Standar deviasi 0.01726
Minimum -0.02817
Maksimum 0.02871

4.3.1 Apakah Tren Sudah Hilang?

Setelah differencing, runtun waktu tidak lagi memperlihatkan kecenderungan naik yang sama seperti pada data level. Nilai hasil differencing berfluktuasi di sekitar nol dengan perubahan positif dan negatif.

Hal ini menunjukkan bahwa first differencing terhadap log harga berhasil mengurangi pola tren pada mean.

Namun, untuk tugas ini, kesimpulan tersebut didasarkan terutama pada pemeriksaan visual dan karakteristik hasil differencing, bukan pada pengujian formal stasioneritas.

5 Naive Forecast

5.1 Pembagian Data Latih dan Data Uji

Soal menetapkan:

  • 21 observasi pertama sebagai training set
  • 3 observasi terakhir sebagai testing set

Dengan demikian, periode training berakhir pada September 2024, sedangkan periode pengujian mencakup Oktober–Desember 2024.

n_train <- 21

train <- head(gkp, n_train)
test <- tail(gkp, 3)

train_dates <- head(tanggal, n_train)
test_dates <- tail(tanggal, 3)

split_df <- tibble(
  tanggal = tanggal,
  harga = gkp,
  kelompok = if_else(
    seq_along(tanggal) <= n_train,
    "Training",
    "Testing"
  )
)

5.2 Visualisasi Train–Test Split

ggplot(split_df, aes(tanggal, harga, group = 1)) +
  geom_line(linewidth = 0.9) +
  geom_point(
    aes(shape = kelompok),
    size = 3
  ) +
  geom_vline(
    xintercept = as.numeric(min(test_dates)),
    linetype = "dashed",
    linewidth = 0.8
  ) +
  scale_shape_manual(
    values = c(
      "Training" = 16,
      "Testing" = 17
    )
  ) +
  scale_y_continuous(
    labels = label_number(big.mark = ".")
  ) +
  scale_x_date(
    date_breaks = "3 months",
    date_labels = "%b\n%Y"
  ) +
  labs(
    title = "Pembagian Training dan Testing",
    subtitle = "21 observasi digunakan untuk membentuk baseline forecast",
    x = NULL,
    y = "Harga GKP (Rp/kg)",
    shape = "Data"
  ) +
  theme_minimal(base_size = 12) +
  theme(
    plot.title = element_text(face = "bold", size = 15),
    panel.grid.minor = element_blank()
  )

5.3 Membentuk Naive Forecast

Naive forecast menggunakan nilai aktual terakhir dari data training sebagai ramalan untuk seluruh periode berikutnya.

Secara matematis:

\[ \hat{Y}_{t+h}=Y_t \]

last_train <- tail(train, 1)

naive_forecast <- rep(
  last_train,
  length(test)
)

forecast_df <- tibble(
  tanggal = test_dates,
  aktual = test,
  ramalan_naif = naive_forecast
)

last_train
## [1] 5900

Dengan demikian, forecast untuk ketiga bulan pengujian menggunakan nilai September 2024 sebesar Rp5.900/kg sebagai baseline.

5.4 Aktual vs Forecast

kable(
  forecast_df |>
    mutate(
      tanggal = format(tanggal, "%B %Y")
    ),
  col.names = c(
    "Periode",
    "Aktual (Rp/kg)",
    "Naive Forecast (Rp/kg)"
  ),
  format.args = list(big.mark = "."),
  caption = "Perbandingan aktual dan naive forecast"
) |>
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width = FALSE
  )
Perbandingan aktual dan naive forecast
Periode Aktual (Rp/kg) Naive Forecast (Rp/kg)
October 2024 6.050 5.900
November 2024 6.150 5.900
December 2024 6.300 5.900

5.5 Visualisasi Forecast

ggplot() +
  geom_line(
    data = gkp_df,
    aes(tanggal, harga),
    linewidth = 0.9
  ) +
  geom_point(
    data = gkp_df,
    aes(tanggal, harga),
    size = 1.8
  ) +
  geom_line(
    data = forecast_df,
    aes(tanggal, ramalan_naif),
    linewidth = 1.1,
    linetype = "dashed"
  ) +
  geom_point(
    data = forecast_df,
    aes(tanggal, aktual),
    size = 3
  ) +
  geom_point(
    data = forecast_df,
    aes(tanggal, ramalan_naif),
    size = 2.5,
    shape = 1
  ) +
  geom_vline(
    xintercept = as.numeric(min(test_dates)),
    linetype = "dotted",
    linewidth = 0.8
  ) +
  annotate(
    "text",
    x = min(test_dates),
    y = max(gkp) + 100,
    label = "Awal periode testing",
    hjust = 0,
    size = 3.5
  ) +
  scale_y_continuous(
    labels = label_number(big.mark = "."),
    limits = c(
      min(gkp) - 100,
      max(gkp) + 250
    )
  ) +
  scale_x_date(
    date_breaks = "3 months",
    date_labels = "%b\n%Y"
  ) +
  labs(
    title = "Naive Forecast vs Harga Aktual",
    subtitle = "Forecast mempertahankan harga terakhir pada training set",
    x = NULL,
    y = "Harga GKP (Rp/kg)"
  ) +
  theme_minimal(base_size = 12) +
  theme(
    plot.title = element_text(face = "bold", size = 15),
    panel.grid.minor = element_blank()
  )

6 Evaluasi Akurasi Ramalan

6.1 Forecast Error

Kesalahan ramalan didefinisikan sebagai:

\[ e_t=Y_t-\hat{Y}_t \]

error_df <- forecast_df |>
  mutate(
    error = aktual - ramalan_naif,
    abs_error = abs(error),
    squared_error = error^2,
    percentage_error = abs(error / aktual) * 100
  )

kable(
  error_df |>
    mutate(
      tanggal = format(tanggal, "%B %Y")
    ),
  digits = 2,
  col.names = c(
    "Periode",
    "Aktual",
    "Forecast",
    "Error",
    "|Error|",
    "Error²",
    "APE (%)"
  ),
  caption = "Perhitungan error naive forecast"
) |>
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width = TRUE
  )
Perhitungan error naive forecast
Periode Aktual Forecast Error &#124;Error&#124; Error² APE (%)
October 2024 6050 5900 150 150 22500 2.48
November 2024 6150 5900 250 250 62500 4.07
December 2024 6300 5900 400 400 160000 6.35

6.2 Lima Metrik Evaluasi

ME <- mean(error_df$error)
MAE <- mean(error_df$abs_error)
MSE <- mean(error_df$squared_error)
RMSE <- sqrt(MSE)
MAPE <- mean(error_df$percentage_error)

metrics <- tibble(
  Metrik = c(
    "ME",
    "MAE",
    "MSE",
    "RMSE",
    "MAPE"
  ),
  Nilai = c(
    ME,
    MAE,
    MSE,
    RMSE,
    MAPE
  ),
  Interpretasi = c(
    "Arah bias forecast",
    "Rata-rata besar kesalahan absolut",
    "Rata-rata kuadrat kesalahan",
    "Akar rata-rata kuadrat kesalahan",
    "Rata-rata kesalahan absolut dalam persen"
  )
)

kable(
  metrics,
  digits = 2,
  caption = "Hasil evaluasi naive forecast"
) |>
  kable_styling(
    bootstrap_options = c("striped", "hover"),
    full_width = FALSE
  )
Hasil evaluasi naive forecast
Metrik Nilai Interpretasi
ME 266.7 Arah bias forecast
MAE 266.7 Rata-rata besar kesalahan absolut
MSE 81666.7 Rata-rata kuadrat kesalahan
RMSE 285.8 Akar rata-rata kuadrat kesalahan
MAPE 4.3 Rata-rata kesalahan absolut dalam persen

7 Membaca Hasil Evaluasi

7.0.1 ME = 266,67

Nilai ME positif menunjukkan bahwa aktual secara rata-rata berada di atas hasil ramalan. Dengan kata lain, naive forecast cenderung under-forecast pada tiga bulan pengujian.

7.0.2 MAE = Rp266,67/kg

Secara absolut, kesalahan rata-rata naive forecast adalah sekitar Rp266,67/kg.

7.0.3 MSE = 81.666,67

MSE memberikan penalti lebih besar terhadap kesalahan yang besar karena error dikuadratkan.

7.0.4 RMSE = Rp285,77/kg

RMSE menunjukkan besarnya kesalahan forecast pada skala yang sama dengan harga GKP, yaitu sekitar Rp285,77/kg.

7.0.5 MAPE = 4,30%

Secara relatif, naive forecast menghasilkan rata-rata kesalahan absolut sekitar 4,30% terhadap harga aktual pada tiga observasi testing.

8 Ringkasan Analisis

final_summary <- tibble(
  Tahap = c(
    "Data asli",
    "Transformasi",
    "Differencing",
    "Forecast",
    "Evaluasi"
  ),
  Temuan = c(
    "Harga GKP menunjukkan kecenderungan meningkat sepanjang periode pengamatan.",
    "Logaritma mengubah skala data dan digunakan untuk mengevaluasi kestabilan variansi.",
    "First differencing pada log harga membuat perubahan berfluktuasi di sekitar nol dan mengurangi tren.",
    "Naive forecast menggunakan Rp5.900/kg sebagai ramalan untuk Oktober–Desember 2024.",
    "MAPE sebesar 4,30% dengan ME positif menunjukkan adanya kecenderungan under-forecast."
  )
)

kable(
  final_summary,
  col.names = c("Tahap Analisis", "Temuan Utama"),
  caption = "Ringkasan hasil analisis"
) |>
  kable_styling(
    bootstrap_options = c("striped", "hover"),
    full_width = TRUE
  )
Ringkasan hasil analisis
Tahap Analisis Temuan Utama
Data asli Harga GKP menunjukkan kecenderungan meningkat sepanjang periode pengamatan.
Transformasi Logaritma mengubah skala data dan digunakan untuk mengevaluasi kestabilan variansi.
Differencing First differencing pada log harga membuat perubahan berfluktuasi di sekitar nol dan mengurangi tren.
Forecast Naive forecast menggunakan Rp5.900/kg sebagai ramalan untuk Oktober–Desember 2024.
Evaluasi MAPE sebesar 4,30% dengan ME positif menunjukkan adanya kecenderungan under-forecast.

8.1 Kesimpulan

Berdasarkan analisis yang dilakukan, harga GKP Kabupaten Serang selama Januari 2023–Desember 2024 memperlihatkan kecenderungan meningkat dari waktu ke waktu. Kondisi tersebut menunjukkan adanya komponen tren pada data level.

Transformasi logaritma kemudian digunakan untuk mengubah skala data sehingga perubahan relatif dapat diamati dengan lebih baik. Selanjutnya, first differencing diterapkan pada data hasil transformasi. Hasil differencing berfluktuasi di sekitar nol dan tidak lagi memperlihatkan pola tren naik yang kuat seperti pada data awal.

Untuk evaluasi forecasting, sebanyak 21 observasi pertama digunakan sebagai training set dan tiga observasi terakhir sebagai testing set. Metode naive forecast mempertahankan nilai terakhir training, yaitu Rp5.900/kg, sebagai ramalan untuk ketiga bulan pengujian.

Hasil evaluasi menghasilkan ME sebesar Rp266,67/kg, MAE sebesar Rp266,67/kg, MSE sebesar 81.666,67, RMSE sebesar Rp285,77/kg, dan MAPE sebesar 4,30%. ME yang positif menunjukkan bahwa baseline naive cenderung menghasilkan ramalan yang lebih rendah daripada nilai aktual pada periode pengujian.

Key takeaway

Naive forecast memberikan baseline yang sederhana untuk mengukur kemampuan peramalan. Hasil ini belum dimaksudkan sebagai model terbaik, melainkan sebagai benchmark awal yang nantinya dapat dibandingkan dengan metode forecasting yang lebih kompleks.

9 Lampiran: Reproduksibilitas

Seluruh analisis dalam dokumen ini dapat direproduksi dengan menjalankan kembali seluruh chunk R secara berurutan.

sessionInfo()
## R version 4.5.0 (2025-04-11 ucrt)
## Platform: x86_64-w64-mingw32/x64
## Running under: Windows 11 x64 (build 26200)
## 
## Matrix products: default
##   LAPACK version 3.12.1
## 
## locale:
## [1] LC_COLLATE=English_United States.utf8 
## [2] LC_CTYPE=English_United States.utf8   
## [3] LC_MONETARY=English_United States.utf8
## [4] LC_NUMERIC=C                          
## [5] LC_TIME=English_United States.utf8    
## 
## time zone: Asia/Jakarta
## tzcode source: internal
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] plotly_4.12.0    scales_1.4.0     kableExtra_1.4.1 knitr_1.51      
## [5] tidyr_1.3.2      dplyr_1.2.0      ggplot2_4.0.2   
## 
## loaded via a namespace (and not attached):
##  [1] sass_0.4.10        generics_0.1.4     xml2_1.4.0         lattice_0.22-6    
##  [5] stringi_1.8.7      digest_0.6.37      magrittr_2.0.3     evaluate_1.0.5    
##  [9] grid_4.5.0         RColorBrewer_1.1-3 bookdown_0.46      fastmap_1.2.0     
## [13] Matrix_1.7-3       jsonlite_2.0.0     httr_1.4.7         mgcv_1.9-1        
## [17] purrr_1.1.0        viridisLite_0.4.2  lazyeval_0.2.2     textshaping_1.0.3 
## [21] jquerylib_0.1.4    cli_3.6.5          rlang_1.1.7        splines_4.5.0     
## [25] withr_3.0.2        cachem_1.1.0       yaml_2.3.10        otel_0.2.0        
## [29] tools_4.5.0        vctrs_0.7.1        R6_2.6.1           lifecycle_1.0.5   
## [33] stringr_1.6.0      htmlwidgets_1.6.4  pkgconfig_2.0.3    pillar_1.11.0     
## [37] bslib_0.9.0        gtable_0.3.6       glue_1.8.0         data.table_1.17.8 
## [41] rmdformats_1.0.4   systemfonts_1.3.2  xfun_0.53          tibble_3.3.0      
## [45] tidyselect_1.2.1   rstudioapi_0.17.1  farver_2.1.2       nlme_3.1-168      
## [49] htmltools_0.5.8.1  labeling_0.4.3     rmarkdown_2.29     svglite_2.2.2     
## [53] compiler_4.5.0     S7_0.2.1

Analisis Deret Waktu — STA623303
Transformasi, Differencing, dan Metrik Evaluasi Model Peramalan