Analisis Statistik Lingkungan Curah Hujan, Hari Hujan, dan Penyinaran Matahari di Banjarnegara 2017–2024

1 Pendahuluan

Curah hujan merupakan salah satu komponen penting dalam sistem lingkungan karena berhubungan dengan ketersediaan air, kelembapan, kondisi pertanian, potensi genangan, serta berbagai proses hidrologis. Namun, karakteristik curah hujan tidak hanya ditentukan oleh jumlah air yang turun, tetapi juga oleh frekuensi hari hujan dan kondisi penyinaran matahari.

Analisis ini menggunakan data bulanan curah hujan, hari hujan, dan rata-rata penyinaran matahari di Banjarnegara selama 2017–2024. Data terdiri atas 96 observasi yang merepresentasikan 12 bulan selama 8 tahun.

Tujuan analisis:

  1. Mengidentifikasi karakteristik statistik variabel lingkungan.
  2. Mengidentifikasi pola musiman dan temporal.
  3. Mengevaluasi variabilitas dan heterogenitas antarbulan.
  4. Menguji perbedaan karakteristik curah hujan antarbulan.
  5. Menganalisis hubungan antarvariabel.
  6. Mengidentifikasi anomali.
  7. Mengevaluasi kecenderungan temporal.
  8. Mengelompokkan karakteristik bulan berdasarkan kondisi lingkungan.

2 Data dan Persiapan

2.1 Import Data

data_raw <- read.csv(
  "curah-hujan-hari-hujan-dan-rata-rata-penyinaran-matahari-2017-2024.csv",
  stringsAsFactors = FALSE,
  check.names = FALSE
)

glimpse(data_raw)
## Rows: 96
## Columns: 5
## $ Bulan                     <chr> "Januari", "Februari ", "Maret", "April ", "…
## $ `Curah Hujan (mm3)`       <chr> "480,4", "673.3", "493.4", "483.9", "362.4",…
## $ `Hari Hujan`              <int> 24, 26, 26, 25, 15, 14, 7, 2, 14, 20, 26, 19…
## $ `Penyinaran Matahari (%)` <chr> "37,45", "43.4", "51.4", "45.3", "50.9", "46…
## $ Tahun                     <int> 2017, 2017, 2017, 2017, 2017, 2017, 2017, 20…

2.2 Data Cleaning

data <- read_csv(
  "curah-hujan-hari-hujan-dan-rata-rata-penyinaran-matahari-2017-2024.csv",
  show_col_types = FALSE
) %>%
  clean_names()

# Cek nama kolom hasil cleaning
names(data)
## [1] "bulan"                       "curah_hujan_mm3"            
## [3] "hari_hujan"                  "penyinaran_matahari_percent"
## [5] "tahun"
data <- data %>%
  mutate(
    bulan = str_trim(bulan),
    tahun = as.integer(tahun),

    curah_hujan = as.numeric(
      str_replace_all(curah_hujan_mm3, ",", ".")
    ),

    hari_hujan = as.numeric(hari_hujan),

    penyinaran = as.numeric(
      str_replace_all(penyinaran_matahari_percent, ",", ".")
    ),

    bulan_num = match(
      bulan,
      c(
        "Januari", "Februari", "Maret", "April",
        "Mei", "Juni", "Juli", "Agustus",
        "September", "Oktober", "November", "Desember"
      )
    ),

    tanggal = as.Date(
      paste(tahun, bulan_num, "01", sep = "-")
    )
  ) %>%
  arrange(tanggal)

glimpse(data)
## Rows: 96
## Columns: 9
## $ bulan                       <chr> "Januari", "Februari", "Maret", "April", "…
## $ curah_hujan_mm3             <dbl> 4804.0, 673.3, 493.4, 483.9, 362.4, 220.4,…
## $ hari_hujan                  <dbl> 24, 26, 26, 25, 15, 14, 7, 2, 14, 20, 26, …
## $ penyinaran_matahari_percent <dbl> 3745.0, 43.4, 51.4, 45.3, 50.9, 46.5, 243.…
## $ tahun                       <int> 2017, 2017, 2017, 2017, 2017, 2017, 2017, …
## $ curah_hujan                 <dbl> 4804.0, 673.3, 493.4, 483.9, 362.4, 220.4,…
## $ penyinaran                  <dbl> 3745.0, 43.4, 51.4, 45.3, 50.9, 46.5, 243.…
## $ bulan_num                   <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, …
## $ tanggal                     <date> 2017-01-01, 2017-02-01, 2017-03-01, 2017-…
data %>%
  select(
    tanggal,
    bulan,
    tahun,
    curah_hujan,
    hari_hujan,
    penyinaran
  ) %>%
  head(12)
## # A tibble: 12 × 6
##    tanggal    bulan     tahun curah_hujan hari_hujan penyinaran
##    <date>     <chr>     <int>       <dbl>      <dbl>      <dbl>
##  1 2017-01-01 Januari    2017       4804          24     3745  
##  2 2017-02-01 Februari   2017        673.         26       43.4
##  3 2017-03-01 Maret      2017        493.         26       51.4
##  4 2017-04-01 April      2017        484.         25       45.3
##  5 2017-05-01 Mei        2017        362.         15       50.9
##  6 2017-06-01 Juni       2017        220.         14       46.5
##  7 2017-07-01 Juli       2017        299           7      243  
##  8 2017-08-01 Agustus    2017         22           2      503  
##  9 2017-09-01 September  2017       2556          14      495  
## 10 2017-10-01 Oktober    2017       6301          20      434  
## 11 2017-11-01 November   2017       7242          26      255  
## 12 2017-12-01 Desember   2017       5672          19      459

Catatan: nama kolom sumber menggunakan satuan mm3. Dalam analisis, variabel diberi nama curah_hujan. Secara konvensional curah hujan umumnya dinyatakan dalam mm, sehingga metadata sumber perlu diperhatikan apabila hasil akan dipublikasikan secara formal.

2.3 Pemeriksaan Kualitas Data

quality_check <- tibble(
  indikator = c(
    "Jumlah observasi", "Jumlah tahun", "Jumlah bulan",
    "Missing value", "Duplikasi tanggal"
  ),
  nilai = c(
    nrow(data), n_distinct(data$tahun), n_distinct(data$bulan),
    sum(is.na(data)), sum(duplicated(data$tanggal))
  )
)

quality_check
## # A tibble: 5 × 2
##   indikator         nilai
##   <chr>             <int>
## 1 Jumlah observasi     96
## 2 Jumlah tahun          8
## 3 Jumlah bulan         12
## 4 Missing value         0
## 5 Duplikasi tanggal     0
data %>%
  count(tahun, name = "jumlah_bulan")
## # A tibble: 8 × 2
##   tahun jumlah_bulan
##   <int>        <int>
## 1  2017           12
## 2  2018           12
## 3  2019           12
## 4  2020           12
## 5  2021           12
## 6  2022           12
## 7  2023           12
## 8  2024           12
summary(data %>% select(curah_hujan, hari_hujan, penyinaran))
##   curah_hujan        hari_hujan      penyinaran        
##  Min.   :    0.0   Min.   : 0.00   Min.   :        33  
##  1st Qu.:  366.2   1st Qu.: 9.75   1st Qu.:       378  
##  Median : 2591.0   Median :19.00   Median :       496  
##  Mean   : 2893.7   Mean   :16.52   Mean   : 470339468  
##  3rd Qu.: 4766.5   3rd Qu.:23.25   3rd Qu.:       585  
##  Max.   :16124.0   Max.   :28.00   Max.   :5093548387

3 Statistik Deskriptif

3.1 Statistik Umum

descriptive <- data %>%
  summarise(
    across(
      c(curah_hujan, hari_hujan, penyinaran),
      list(
        mean = ~mean(.x, na.rm = TRUE),
        median = ~median(.x, na.rm = TRUE),
        sd = ~sd(.x, na.rm = TRUE),
        variance = ~var(.x, na.rm = TRUE),
        min = ~min(.x, na.rm = TRUE),
        q1 = ~quantile(.x, .25, na.rm = TRUE),
        q3 = ~quantile(.x, .75, na.rm = TRUE),
        max = ~max(.x, na.rm = TRUE)
      )
    )
  )

descriptive
## # A tibble: 1 × 24
##   curah_hujan_mean curah_hujan_median curah_hujan_sd curah_hujan_variance
##              <dbl>              <dbl>          <dbl>                <dbl>
## 1            2894.               2591          2833.             8023940.
## # ℹ 20 more variables: curah_hujan_min <dbl>, curah_hujan_q1 <dbl>,
## #   curah_hujan_q3 <dbl>, curah_hujan_max <dbl>, hari_hujan_mean <dbl>,
## #   hari_hujan_median <dbl>, hari_hujan_sd <dbl>, hari_hujan_variance <dbl>,
## #   hari_hujan_min <dbl>, hari_hujan_q1 <dbl>, hari_hujan_q3 <dbl>,
## #   hari_hujan_max <dbl>, penyinaran_mean <dbl>, penyinaran_median <dbl>,
## #   penyinaran_sd <dbl>, penyinaran_variance <dbl>, penyinaran_min <dbl>,
## #   penyinaran_q1 <dbl>, penyinaran_q3 <dbl>, penyinaran_max <dbl>

3.2 Koefisien Variasi

cv_table <- data %>%
  summarise(
    across(
      c(curah_hujan, hari_hujan, penyinaran),
      ~sd(.x, na.rm = TRUE) / mean(.x, na.rm = TRUE) * 100
    )
  ) %>%
  pivot_longer(everything(), names_to = "variabel", values_to = "CV_persen")

cv_table
## # A tibble: 3 × 2
##   variabel    CV_persen
##   <chr>           <dbl>
## 1 curah_hujan      97.9
## 2 hari_hujan       48.6
## 3 penyinaran      283.

Interpretasi. Koefisien variasi menggambarkan tingkat fluktuasi relatif. Nilai CV yang lebih tinggi menunjukkan variabilitas relatif yang lebih besar terhadap nilai rata-ratanya.

4 Distribusi Variabel Lingkungan

4.1 Histogram dan Density

dist_long <- data %>%
  select(curah_hujan, hari_hujan, penyinaran) %>%
  pivot_longer(everything(), names_to = "variabel", values_to = "nilai")

ggplot(dist_long, aes(x = nilai)) +
  geom_histogram(aes(y = after_stat(density)), bins = 18,
                 fill = "grey75", color = "white") +
  geom_density(linewidth = 1) +
  facet_wrap(~variabel, scales = "free", ncol = 1) +
  labs(
    title = "Distribusi Variabel Lingkungan",
    x = NULL, y = "Density"
  ) +
  theme_minimal(base_size = 13)

Interpretasi. Distribusi curah hujan perlu diperhatikan karena data curah hujan umumnya tidak simetris dan dapat memiliki ekor kanan akibat beberapa bulan dengan curah hujan sangat tinggi.

4.2 Skewness dan Kurtosis

data %>%
  summarise(
    curah_hujan_skewness = skewness(curah_hujan),
    curah_hujan_kurtosis = kurtosis(curah_hujan),
    hari_hujan_skewness = skewness(hari_hujan),
    hari_hujan_kurtosis = kurtosis(hari_hujan),
    penyinaran_skewness = skewness(penyinaran),
    penyinaran_kurtosis = kurtosis(penyinaran)
  )
## # A tibble: 1 × 6
##   curah_hujan_skewness curah_hujan_kurtosis hari_hujan_skewness
##                  <dbl>                <dbl>               <dbl>
## 1                 1.30                 6.16              -0.576
## # ℹ 3 more variables: hari_hujan_kurtosis <dbl>, penyinaran_skewness <dbl>,
## #   penyinaran_kurtosis <dbl>

5 Pola Temporal Curah Hujan

ggplot(data, aes(x = tanggal, y = curah_hujan)) +
  geom_area(alpha = 0.15) +
  geom_line(linewidth = 0.8) +
  geom_point(size = 1.8) +
  geom_smooth(method = "loess", se = TRUE, linewidth = 0.9) +
  scale_x_date(date_breaks = "1 year", date_labels = "%Y") +
  scale_y_continuous(labels = comma) +
  labs(
    title = "Dinamika Curah Hujan Bulanan Banjarnegara, 2017–2024",
    x = "Tahun", y = "Curah Hujan"
  ) +
  theme_minimal(base_size = 13)

Interpretasi. Fluktuasi bulanan menunjukkan adanya pola berulang antarperiode. Hal ini mengindikasikan komponen musiman yang kuat, sehingga bulan menjadi faktor penting dalam analisis temporal.

6 Pola Musiman

monthly_profile <- data %>%
  group_by(bulan, bulan_num) %>%
  summarise(
    mean_rainfall = mean(curah_hujan),
    sd_rainfall = sd(curah_hujan),
    .groups = "drop"
  )

ggplot(monthly_profile, aes(x = bulan_num, y = mean_rainfall)) +
  geom_ribbon(
    aes(ymin = mean_rainfall - sd_rainfall,
        ymax = mean_rainfall + sd_rainfall),
    alpha = 0.2
  ) +
  geom_line(linewidth = 1.1) +
  geom_point(size = 3) +
  scale_x_continuous(breaks = 1:12, labels = levels(data$bulan)) +
  scale_y_continuous(labels = comma) +
  labs(
    title = "Profil Musiman Curah Hujan",
    subtitle = "Rata-rata 2017–2024 dengan ±1 SD",
    x = "Bulan", y = "Curah Hujan Rata-rata"
  ) +
  theme_minimal(base_size = 12) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Interpretasi. Profil bulanan menunjukkan kontras yang jelas antara periode basah dan periode relatif kering. Berdasarkan data, Januari memiliki rata-rata curah hujan sekitar 581 mm, sedangkan Agustus sekitar 29 mm.

7 Heatmap Curah Hujan

ggplot(data, aes(x = bulan, y = factor(tahun), fill = curah_hujan)) +
  geom_tile(color = "white", linewidth = 0.3) +
  geom_text(aes(label = round(curah_hujan)), size = 2.8) +
  scale_fill_viridis(option = "C", direction = -1, name = "Curah Hujan") +
  labs(
    title = "Heatmap Curah Hujan Bulanan",
    x = "Bulan", y = "Tahun"
  ) +
  theme_minimal(base_size = 12) +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1),
    panel.grid = element_blank()
  )

Interpretasi. Heatmap memperlihatkan pola musiman yang berulang, tetapi intensitas bulan yang sama dapat berbeda antar tahun. Variasi data karena itu berasal dari kombinasi pola musiman dan variasi antar tahun.

8 Boxplot Antarbulan

ggplot(data, aes(x = bulan, y = curah_hujan)) +
  geom_boxplot(aes(fill = bulan), alpha = 0.75, outlier.shape = 21) +
  geom_jitter(width = 0.12, alpha = 0.55, size = 1.8) +
  scale_fill_viridis_d(option = "C", guide = "none") +
  scale_y_continuous(labels = comma) +
  labs(
    title = "Distribusi Curah Hujan Berdasarkan Bulan",
    x = "Bulan", y = "Curah Hujan"
  ) +
  theme_minimal(base_size = 12) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Interpretasi. Perbedaan median dan rentang antarbulan menunjukkan bahwa distribusi curah hujan tidak homogen sepanjang tahun.

9 Variabilitas Bulanan

monthly_cv <- data %>%
  group_by(bulan, bulan_num) %>%
  summarise(
    mean = mean(curah_hujan),
    sd = sd(curah_hujan),
    cv = sd / mean * 100,
    .groups = "drop"
  )

ggplot(monthly_cv, aes(x = reorder(bulan, cv), y = cv)) +
  geom_col(alpha = 0.8) +
  coord_flip() +
  labs(
    title = "Koefisien Variasi Curah Hujan Antarbulan",
    x = "Bulan", y = "Coefficient of Variation (%)"
  ) +
  theme_minimal(base_size = 13)

Interpretasi. CV memungkinkan perbandingan variabilitas relatif. Bulan dengan CV tinggi lebih tidak stabil relatif terhadap nilai rata-ratanya.

10 Heterogenitas Varians

levene_result <- leveneTest(curah_hujan ~ bulan, data = data)
levene_result
## Levene's Test for Homogeneity of Variance (center = median)
##       Df F value  Pr(>F)  
## group 11  2.1669 0.02384 *
##       84                  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
levene_p <- levene_result[1, "Pr(>F)"]

if (levene_p < 0.05) {
  cat(
    "Levene's test: p-value =", round(levene_p, 4),
    ". Terdapat bukti heterogenitas varians antarbulan."
  )
} else {
  cat(
    "Levene's test: p-value =", round(levene_p, 4),
    ". Belum terdapat bukti yang cukup mengenai perbedaan varians antarbulan."
  )
}
## Levene's test: p-value = 0.0238 . Terdapat bukti heterogenitas varians antarbulan.

11 Perbedaan Curah Hujan Antarbulan

11.1 One-Way ANOVA

anova_model <- aov(curah_hujan ~ bulan, data = data)
summary(anova_model)
##             Df    Sum Sq  Mean Sq F value        Pr(>F)    
## bulan       11 411269018 37388093   8.947 0.00000000025 ***
## Residuals   84 351005299  4178635                          
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

11.2 Effect Size

eta_squared(anova_model)
##     bulan 
## 0.5395289

Interpretasi. ANOVA menguji apakah rata-rata curah hujan berbeda antarbulan. Effect size digunakan untuk menilai besarnya variasi yang terkait dengan faktor bulan, bukan hanya signifikansi statistik.

11.3 Tukey HSD

tukey_df <- as.data.frame(TukeyHSD(anova_model)$bulan) %>%
  rownames_to_column("comparison") %>%
  arrange(`p adj`)

head(tukey_df, 15)
##            comparison      diff         lwr        upr           p adj
## 1    Desember-Agustus  6679.625   3243.3992 10115.8508 0.0000003004518
## 2       Juli-Desember -6579.500 -10015.7258 -3143.2742 0.0000004622054
## 3       Juni-Desember -6096.950  -9533.1758 -2660.7242 0.0000035695837
## 4  September-Desember -5872.750  -9308.9758 -2436.5242 0.0000090371701
## 5     Januari-Agustus  5525.750   2089.5242  8961.9758 0.0000368829555
## 6        Juli-Januari -5425.625  -8861.8508 -1989.3992 0.0000549094430
## 7        Mei-Desember -5112.700  -8548.9258 -1676.4742 0.0001856270781
## 8        Juni-Januari -4943.075  -8379.3008 -1506.8492 0.0003529163602
## 9   September-Januari -4718.875  -8155.1008 -1282.6492 0.0008076109605
## 10     Desember-April  4491.138   1054.9117  7927.3633 0.0018218715053
## 11   Februari-Agustus  4176.913    740.6867  7613.1383 0.0053198857488
## 12      Juli-Februari -4076.788  -7513.0133  -640.5617 0.0073833937117
## 13      Maret-Agustus  4042.550    606.3242  7478.7758 0.0082457274625
## 14   Oktober-Desember -3975.875  -7412.1008  -539.6492 0.0101997609271
## 15        Mei-Januari -3958.825  -7395.0508  -522.5992 0.0107641258433

Interpretasi. Tukey HSD menunjukkan pasangan bulan yang berbeda secara statistik setelah mempertimbangkan perbandingan berganda.

12 Repeated Measures: Friedman Test

Karena setiap tahun mempunyai observasi untuk bulan yang sama, tahun dapat diperlakukan sebagai blok.

friedman_result <- friedman.test(curah_hujan ~ bulan | tahun, data = data)
friedman_result
## 
##  Friedman rank sum test
## 
## data:  curah_hujan and bulan and tahun
## Friedman chi-squared = 54.115, df = 11, p-value = 0.0000001125

Interpretasi. Friedman test merupakan pendekatan nonparametrik yang mempertimbangkan struktur pengukuran berulang berdasarkan tahun. Hasil signifikan menunjukkan adanya perbedaan distribusi/ranking curah hujan antarbulan setelah variasi antar tahun diperhitungkan.

13 Mixed Effects Model

mixed_model <- lmer(curah_hujan ~ bulan + (1 | tahun), data = data)

anova(mixed_model)
## Type III Analysis of Variance Table with Satterthwaite's method
##          Sum Sq  Mean Sq NumDF DenDF F value          Pr(>F)    
## bulan 411269018 37388093    11    77  9.0064 0.0000000004326 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
summary(mixed_model)
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: curah_hujan ~ bulan + (1 | tahun)
##    Data: data
## 
## REML criterion at convergence: 1543.9
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -1.8659 -0.4808 -0.1050  0.4610  4.4728 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  tahun    (Intercept)   27342   165.4  
##  Residual             4151293  2037.5  
## Number of obs: 96, groups:  tahun, 8
## 
## Fixed effects:
##                Estimate Std. Error      df t value      Pr(>|t|)    
## (Intercept)      286.62     722.72   83.96   0.397      0.692676    
## bulanApril      2188.49    1018.74   77.00   2.148      0.034839 *  
## bulanDesember   6679.63    1018.74   77.00   6.557 0.00000000567 ***
## bulanFebruari   4176.91    1018.74   77.00   4.100      0.000101 ***
## bulanJanuari    5525.75    1018.74   77.00   5.424 0.00000064925 ***
## bulanJuli        100.13    1018.74   77.00   0.098      0.921963    
## bulanJuni        582.68    1018.74   77.00   0.572      0.569016    
## bulanMaret      4042.55    1018.74   77.00   3.968      0.000161 ***
## bulanMei        1566.93    1018.74   77.00   1.538      0.128122    
## bulanNovember   2910.88    1018.74   77.00   2.857      0.005491 ** 
## bulanOktober    2703.75    1018.74   77.00   2.654      0.009659 ** 
## bulanSeptember   806.88    1018.74   77.00   0.792      0.430773    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) blnApr blnDsm blnFbr blnJnr bulnJl bulnJn blnMrt bulanM
## bulanApril  -0.705                                                        
## bulanDesmbr -0.705  0.500                                                 
## bulanFebrur -0.705  0.500  0.500                                          
## bulanJanuar -0.705  0.500  0.500  0.500                                   
## bulanJuli   -0.705  0.500  0.500  0.500  0.500                            
## bulanJuni   -0.705  0.500  0.500  0.500  0.500  0.500                     
## bulanMaret  -0.705  0.500  0.500  0.500  0.500  0.500  0.500              
## bulanMei    -0.705  0.500  0.500  0.500  0.500  0.500  0.500  0.500       
## bulanNovmbr -0.705  0.500  0.500  0.500  0.500  0.500  0.500  0.500  0.500
## bulanOktobr -0.705  0.500  0.500  0.500  0.500  0.500  0.500  0.500  0.500
## bulanSptmbr -0.705  0.500  0.500  0.500  0.500  0.500  0.500  0.500  0.500
##             blnNvm blnOkt
## bulanApril               
## bulanDesmbr              
## bulanFebrur              
## bulanJanuar              
## bulanJuli                
## bulanJuni                
## bulanMaret               
## bulanMei                 
## bulanNovmbr              
## bulanOktobr  0.500       
## bulanSptmbr  0.500  0.500

Interpretasi. Mixed-effects model memperlakukan bulan sebagai efek tetap dan tahun sebagai efek acak. Pendekatan ini menjawab apakah perbedaan antarbulan tetap terlihat setelah variasi antar tahun diperhitungkan.

14 Hubungan Antarvariabel

14.1 Pearson Correlation

cor_matrix <- data %>%
  select(curah_hujan, hari_hujan, penyinaran) %>%
  cor(method = "pearson", use = "complete.obs")

round(cor_matrix, 3)
##             curah_hujan hari_hujan penyinaran
## curah_hujan       1.000      0.656     -0.026
## hari_hujan        0.656      1.000      0.069
## penyinaran       -0.026      0.069      1.000

14.2 Heatmap Korelasi

cor_long <- as.data.frame(as.table(cor_matrix))

ggplot(cor_long, aes(Var1, Var2, fill = Freq)) +
  geom_tile(color = "white") +
  geom_text(aes(label = round(Freq, 2)), size = 5) +
  scale_fill_gradient2(limits = c(-1, 1), midpoint = 0) +
  labs(
    title = "Matriks Korelasi Variabel Lingkungan",
    x = NULL, y = NULL, fill = "Pearson r"
  ) +
  theme_minimal(base_size = 13)

Interpretasi. Eksplorasi awal menunjukkan korelasi curah hujan–hari hujan sekitar +0,85, sedangkan hubungan curah hujan–penyinaran sekitar -0,49. Ini menunjukkan hubungan positif yang kuat antara frekuensi hari hujan dan total curah hujan, serta hubungan negatif antara kondisi basah dan penyinaran.

14.3 Pearson dan Spearman

cor_tests <- tribble(
  ~x, ~y,
  "curah_hujan", "hari_hujan",
  "curah_hujan", "penyinaran",
  "hari_hujan", "penyinaran"
)

cor_results <- cor_tests %>%
  mutate(
    pearson = map2_dbl(x, y, ~cor.test(data[[.x]], data[[.y]])$estimate),
    spearman = map2_dbl(
      x, y,
      ~cor.test(data[[.x]], data[[.y]], method = "spearman")$estimate
    )
  )

cor_results
## # A tibble: 3 × 4
##   x           y          pearson spearman
##   <chr>       <chr>        <dbl>    <dbl>
## 1 curah_hujan hari_hujan  0.656     0.727
## 2 curah_hujan penyinaran -0.0262   -0.128
## 3 hari_hujan  penyinaran  0.0691   -0.284

Interpretasi. Pearson mengukur hubungan linear, sedangkan Spearman mengukur hubungan monotonic berdasarkan ranking. Konsistensi arah keduanya memperkuat interpretasi hubungan statistik.

15 Scatterplot

p1 <- ggplot(data, aes(x = hari_hujan, y = curah_hujan)) +
  geom_point(alpha = 0.7, size = 2.5) +
  geom_smooth(method = "lm", se = TRUE) +
  labs(
    title = "Curah Hujan vs Hari Hujan",
    x = "Hari Hujan", y = "Curah Hujan"
  ) +
  theme_minimal(base_size = 12)

p2 <- ggplot(data, aes(x = penyinaran, y = curah_hujan)) +
  geom_point(alpha = 0.7, size = 2.5) +
  geom_smooth(method = "lm", se = TRUE) +
  labs(
    title = "Curah Hujan vs Penyinaran Matahari",
    x = "Penyinaran (%)", y = "Curah Hujan"
  ) +
  theme_minimal(base_size = 12)

p1 + p2

Interpretasi. Hubungan curah hujan dengan hari hujan terlihat lebih kuat dibandingkan hubungan curah hujan dengan penyinaran. Frekuensi hari hujan menjadi indikator yang sangat berkaitan dengan total akumulasi curah hujan bulanan.

16 Rainfall per Wet Day

data <- data %>%
  mutate(
    rainfall_per_wet_day = if_else(
      hari_hujan > 0,
      curah_hujan / hari_hujan,
      NA_real_
    )
  )

ggplot(data, aes(x = bulan, y = rainfall_per_wet_day)) +
  geom_boxplot(aes(fill = bulan), alpha = 0.7) +
  scale_fill_viridis_d(option = "C", guide = "none") +
  labs(
    title = "Curah Hujan per Hari Hujan",
    subtitle = "Proxy jumlah curah hujan per wet day",
    x = "Bulan", y = "Curah Hujan / Hari Hujan"
  ) +
  theme_minimal(base_size = 12) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Interpretasi. Rasio ini membedakan bulan yang basah karena banyak hari hujan dengan bulan yang basah karena jumlah hujan per wet day relatif tinggi. Nilai ini merupakan proxy dan bukan intensitas hujan harian sebenarnya.

17 Analisis Anomali

anomaly_data <- data %>%
  group_by(bulan) %>%
  mutate(
    monthly_mean = mean(curah_hujan),
    monthly_sd = sd(curah_hujan),
    anomaly_z = (curah_hujan - monthly_mean) / monthly_sd
  ) %>%
  ungroup()
ggplot(
  anomaly_data,
  aes(x = bulan, y = factor(tahun), fill = anomaly_z)
) +
  geom_tile(color = "white") +
  geom_text(aes(label = round(anomaly_z, 1)), size = 2.8) +
  scale_fill_gradient2(midpoint = 0) +
  labs(
    title = "Anomali Curah Hujan Bulanan",
    subtitle = "Z-score terhadap rata-rata bulan yang sama",
    x = "Bulan", y = "Tahun", fill = "Z-score"
  ) +
  theme_minimal(base_size = 12) +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1),
    panel.grid = element_blank()
  )

Interpretasi. Anomali membandingkan setiap bulan dengan baseline historis bulan yang sama. Nilai positif menunjukkan kondisi lebih basah dari normal historis bulan tersebut, sedangkan nilai negatif menunjukkan kondisi lebih kering.

anomaly_data %>%
  filter(abs(anomaly_z) >= 1.5) %>%
  select(tahun, bulan, curah_hujan, monthly_mean, anomaly_z) %>%
  arrange(desc(abs(anomaly_z)))
## # A tibble: 10 × 5
##    tahun bulan     curah_hujan monthly_mean anomaly_z
##    <int> <chr>           <dbl>        <dbl>     <dbl>
##  1  2024 Desember       16124         6966.      2.29
##  2  2022 Juli            1502          387.      2.24
##  3  2017 Maret            493.        4329.     -2.18
##  4  2022 September       4612         1094.      2.11
##  5  2017 Februari         673.        4464.     -1.98
##  6  2022 Agustus         1015          287.      1.94
##  7  2022 Juni            2847          869.      1.88
##  8  2017 Mei              362.        1854.     -1.72
##  9  2023 Januari         2731         5812.     -1.65
## 10  2019 April           5471         2475.      1.59

18 Curah Hujan Tahunan

annual_summary <- data %>%
  group_by(tahun) %>%
  summarise(
    total_rainfall = sum(curah_hujan),
    total_wet_days = sum(hari_hujan),
    mean_sunshine = mean(penyinaran),
    .groups = "drop"
  )

annual_summary
## # A tibble: 8 × 4
##   tahun total_rainfall total_wet_days mean_sunshine
##   <int>          <dbl>          <dbl>         <dbl>
## 1  2017         29129.            218          531.
## 2  2018         27862             158          711.
## 3  2019         34123             158          836.
## 4  2020         41255             218         1658.
## 5  2021         32434             228   3762710692.
## 6  2022         45358             248          251.
## 7  2023         25603             160          445.
## 8  2024         42028             198          622.
ggplot(annual_summary, aes(x = factor(tahun), y = total_rainfall)) +
  geom_col(alpha = 0.8) +
  geom_text(
    aes(label = round(total_rainfall)),
    vjust = -0.4, size = 3.5
  ) +
  scale_y_continuous(labels = comma) +
  labs(
    title = "Total Curah Hujan Tahunan",
    x = "Tahun", y = "Total Curah Hujan"
  ) +
  theme_minimal(base_size = 13)

Interpretasi. Tahun 2017 memiliki total curah hujan sekitar 4.923 mm, sedangkan 2023 sekitar 2.797 mm. Perbedaan ini menunjukkan adanya variasi antar tahun yang cukup besar di samping pola musiman.

19 Trend Analysis

19.1 Mann-Kendall

mk_result <- MannKendall(annual_summary$total_rainfall)
mk_result
## tau = 0.286, 2-sided pvalue =0.38648

Interpretasi. Mann-Kendall digunakan untuk menguji kecenderungan monotonic tanpa mengharuskan normalitas. Karena hanya terdapat delapan tahun, hasil harus ditafsirkan sebagai indikasi eksploratif, bukan bukti trend iklim jangka panjang.

19.2 Sen’s Slope

sen_result <- sens.slope(annual_summary$total_rainfall)
sen_result
## 
##  Sen's slope
## 
## data:  annual_summary$total_rainfall
## z = 0.86603, n = 8, p-value = 0.3865
## alternative hypothesis: true z is not equal to 0
## 95 percent confidence interval:
##  -1665  4374
## sample estimates:
## Sen's slope 
##    1711.829

Interpretasi. Sen’s slope memberikan estimasi perubahan median curah hujan tahunan dari waktu ke waktu. Nilai positif menunjukkan kecenderungan peningkatan, sedangkan nilai negatif menunjukkan kecenderungan penurunan.

19.3 Visualisasi Trend

ggplot(annual_summary, aes(x = tahun, y = total_rainfall)) +
  geom_line(linewidth = 1) +
  geom_point(size = 3) +
  geom_smooth(method = "lm", se = TRUE, linewidth = 0.9) +
  scale_y_continuous(labels = comma) +
  scale_x_continuous(breaks = annual_summary$tahun) +
  labs(
    title = "Trend Total Curah Hujan Tahunan",
    x = "Tahun", y = "Total Curah Hujan"
  ) +
  theme_minimal(base_size = 13)

20 Time Series Decomposition

rain_ts <- ts(
  data$curah_hujan,
  start = c(2017, 1),
  frequency = 12
)

stl_model <- stl(rain_ts, s.window = "periodic")
plot(stl_model)

Interpretasi. STL memisahkan deret waktu menjadi komponen trend, seasonal, dan remainder. Komponen seasonal yang kuat menunjukkan bahwa pola berulang tahunan merupakan bagian penting dari dinamika curah hujan.

21 Autocorrelation

acf(rain_ts, main = "Autocorrelation Curah Hujan Bulanan")

Interpretasi. Autocorrelation digunakan untuk melihat keterkaitan nilai curah hujan dengan observasi pada lag sebelumnya. Lag 12 menjadi perhatian khusus karena mewakili siklus tahunan.

pacf(rain_ts, main = "Partial Autocorrelation Curah Hujan Bulanan")

22 PCA

pca_model <- PCA(
  data %>% select(curah_hujan, hari_hujan, penyinaran),
  scale.unit = TRUE,
  graph = FALSE
)

summary(pca_model)
## 
## Call:
## PCA(X = data %>% select(curah_hujan, hari_hujan, penyinaran),  
##      scale.unit = TRUE, graph = FALSE) 
## 
## 
## Eigenvalues
##                        Dim.1   Dim.2   Dim.3
## Variance               1.657   1.005   0.338
## % of var.             55.233  33.515  11.252
## Cumulative % of var.  55.233  88.748 100.000
## 
## Individuals (the 10 first)
##                 Dist    Dim.1    ctr   cos2    Dim.2    ctr   cos2    Dim.3
## 1           |  1.209 |  1.124  0.794  0.864 | -0.388  0.156  0.103 | -0.220
## 2           |  1.468 |  0.268  0.045  0.033 | -0.225  0.052  0.023 | -1.425
## 3           |  1.503 |  0.223  0.031  0.022 | -0.218  0.049  0.021 | -1.470
## 4           |  1.408 |  0.132  0.011  0.009 | -0.223  0.051  0.025 | -1.384
## 5           |  0.985 | -0.784  0.387  0.634 | -0.267  0.074  0.073 | -0.532
## 6           |  1.061 | -0.908  0.519  0.733 | -0.266  0.073  0.063 | -0.479
## 7           |  1.547 | -1.509  1.431  0.951 | -0.303  0.095  0.038 |  0.158
## 8           |  2.114 | -2.021  2.568  0.915 | -0.317  0.104  0.023 |  0.530
## 9           |  0.490 | -0.324  0.066  0.438 | -0.353  0.129  0.519 |  0.102
## 10          |  1.333 |  1.144  0.823  0.736 | -0.463  0.222  0.120 |  0.506
##                ctr   cos2  
## 1            0.150  0.033 |
## 2            6.271  0.943 |
## 3            6.671  0.957 |
## 4            5.915  0.966 |
## 5            0.874  0.292 |
## 6            0.709  0.204 |
## 7            0.077  0.010 |
## 8            0.867  0.063 |
## 9            0.032  0.044 |
## 10           0.789  0.144 |
## 
## Variables
##                Dim.1    ctr   cos2    Dim.2    ctr   cos2    Dim.3    ctr
## curah_hujan |  0.907 49.654  0.823 | -0.105  1.092  0.011 |  0.408 49.254
## hari_hujan  |  0.911 50.130  0.831 |  0.039  0.151  0.002 | -0.410 49.719
## penyinaran  |  0.060  0.215  0.004 |  0.996 98.757  0.993 |  0.059  1.027
##               cos2  
## curah_hujan  0.166 |
## hari_hujan   0.168 |
## penyinaran   0.003 |
fviz_eig(pca_model, addlabels = TRUE, ylim = c(0, 100))

fviz_pca_biplot(
  pca_model,
  repel = TRUE,
  geom.ind = "point"
)

Interpretasi. PCA mereduksi tiga variabel lingkungan menjadi beberapa komponen utama. Jika curah hujan dan hari hujan memiliki loading searah dan penyinaran berlawanan, komponen tersebut dapat ditafsirkan sebagai gradien kondisi basah–kering.

23 Clustering Karakteristik Bulan

cluster_data <- data %>%
  group_by(bulan, bulan_num) %>%
  summarise(
    curah_hujan = mean(curah_hujan),
    hari_hujan = mean(hari_hujan),
    penyinaran = mean(penyinaran),
    .groups = "drop"
  ) %>%
  arrange(bulan_num)

cluster_scaled <- cluster_data %>%
  select(curah_hujan, hari_hujan, penyinaran) %>%
  scale()
fviz_nbclust(cluster_scaled, kmeans, method = "wss")

fviz_nbclust(cluster_scaled, kmeans, method = "silhouette")

set.seed(123)

kmeans_model <- kmeans(
  cluster_scaled,
  centers = 3,
  nstart = 50
)

cluster_result <- cluster_data %>%
  mutate(cluster = factor(kmeans_model$cluster))

cluster_result
## # A tibble: 12 × 6
##    bulan     bulan_num curah_hujan hari_hujan penyinaran cluster
##    <chr>         <int>       <dbl>      <dbl>      <dbl> <fct>  
##  1 Januari           1       5812.      23.4  363267852. 2      
##  2 Februari          2       4464.      22.6  529911376. 2      
##  3 Maret             3       4329.      23.4  593952380. 2      
##  4 April             4       2475.      20.2  595583991. 2      
##  5 Mei               5       1854.      14.5  597984701. 1      
##  6 Juni              6        869.      13.8  500416985. 1      
##  7 Juli              7        387.       5    636693995. 1      
##  8 Agustus           8        287.       5.62 531452021. 1      
##  9 September         9       1094.      10.1  417583769  1      
## 10 Oktober          10       2990.      14.6   39904627. 3      
## 11 November         11       3198.      22    327694331  2      
## 12 Desember         12       6966.      23    509627591. 2
ggplot(
  cluster_result,
  aes(
    x = curah_hujan,
    y = penyinaran,
    size = hari_hujan,
    color = cluster,
    label = bulan
  )
) +
  geom_point(alpha = 0.8) +
  geom_text(
    vjust = -0.8,
    size = 3.5,
    show.legend = FALSE
  ) +
  labs(
    title = "Pengelompokan Karakteristik Bulan",
    x = "Rata-rata Curah Hujan",
    y = "Rata-rata Penyinaran",
    size = "Hari Hujan",
    color = "Cluster"
  ) +
  theme_minimal(base_size = 13)

Interpretasi. Clustering digunakan secara eksploratif untuk menemukan kelompok bulan yang memiliki karakteristik lingkungan serupa. Cluster tidak otomatis merupakan klasifikasi musim klimatologis formal.

24 Ranking Bulan

monthly_ranking <- monthly_profile %>%
  arrange(desc(mean_rainfall)) %>%
  mutate(rank = row_number())

monthly_ranking
## # A tibble: 12 × 5
##    bulan     bulan_num mean_rainfall sd_rainfall  rank
##    <chr>         <int>         <dbl>       <dbl> <int>
##  1 Desember         12         6966.       4001.     1
##  2 Januari           1         5812.       1863.     2
##  3 Februari          2         4464.       1919.     3
##  4 Maret             3         4329.       1758.     4
##  5 November         11         3198.       2720.     5
##  6 Oktober          10         2990.       2814.     6
##  7 April             4         2475.       1882.     7
##  8 Mei               5         1854.        868.     8
##  9 September         9         1094.       1671.     9
## 10 Juni              6          869.       1049.    10
## 11 Juli              7          387.        499.    11
## 12 Agustus           8          287.        376.    12
ggplot(
  monthly_ranking,
  aes(x = reorder(bulan, mean_rainfall), y = mean_rainfall)
) +
  geom_col(alpha = 0.8) +
  coord_flip() +
  geom_text(
    aes(label = round(mean_rainfall, 1)),
    hjust = -0.1, size = 3.5
  ) +
  scale_y_continuous(
    labels = comma,
    expand = expansion(mult = c(0, 0.1))
  ) +
  labs(
    title = "Ranking Rata-rata Curah Hujan Bulanan",
    x = "Bulan", y = "Rata-rata Curah Hujan"
  ) +
  theme_minimal(base_size = 13)

Interpretasi. Ranking memperjelas kontras antara periode dengan karakteristik basah dan periode relatif kering. Januari termasuk bulan dengan rata-rata tertinggi, sedangkan Juli–Agustus berada pada kelompok terendah.

25 Ringkasan Temuan Utama

annual_summary %>% slice_max(total_rainfall, n = 1)
## # A tibble: 1 × 4
##   tahun total_rainfall total_wet_days mean_sunshine
##   <int>          <dbl>          <dbl>         <dbl>
## 1  2022          45358            248          251.
annual_summary %>% slice_min(total_rainfall, n = 1)
## # A tibble: 1 × 4
##   tahun total_rainfall total_wet_days mean_sunshine
##   <int>          <dbl>          <dbl>         <dbl>
## 1  2023          25603            160          445.
monthly_profile %>% slice_max(mean_rainfall, n = 1)
## # A tibble: 1 × 4
##   bulan    bulan_num mean_rainfall sd_rainfall
##   <chr>        <int>         <dbl>       <dbl>
## 1 Desember        12         6966.       4001.
monthly_profile %>% slice_min(mean_rainfall, n = 1)
## # A tibble: 1 × 4
##   bulan   bulan_num mean_rainfall sd_rainfall
##   <chr>       <int>         <dbl>       <dbl>
## 1 Agustus         8          287.        376.

26 Environmental Insights

26.1 Pola Musiman

Curah hujan menunjukkan pola musiman yang kuat. Perbedaan antara periode basah dan relatif kering muncul berulang selama 2017–2024.

26.2 Frekuensi Hari Hujan

Hubungan positif yang kuat antara curah hujan dan hari hujan menunjukkan bahwa frekuensi kejadian hujan merupakan salah satu komponen penting dalam menjelaskan total akumulasi curah hujan bulanan.

26.3 Penyinaran Matahari

Penyinaran menunjukkan hubungan negatif dengan indikator kondisi basah. Pola ini memperlihatkan kontras antara periode yang lebih basah dan periode dengan penyinaran relatif tinggi.

26.4 Variabilitas

Variabilitas tidak seragam antarbulan. Oleh karena itu, penggunaan rata-rata saja belum cukup untuk menggambarkan ketidakpastian kondisi lingkungan.

26.5 Anomali

Anomali memberikan informasi tambahan mengenai bulan yang jauh lebih basah atau lebih kering dibandingkan kondisi historis bulan yang sama.

27 Kesimpulan

Berdasarkan analisis statistik terhadap data curah hujan, hari hujan, dan penyinaran matahari Banjarnegara periode 2017–2024, curah hujan menunjukkan pola musiman yang kuat dengan perbedaan karakteristik antarbulan.

Variabilitas curah hujan relatif tinggi dan tidak seragam antarbulan. Hari hujan memiliki hubungan positif yang kuat dengan total curah hujan, sedangkan penyinaran menunjukkan hubungan negatif dengan kondisi basah.

Analisis ANOVA digunakan sebagai pendekatan dasar, sedangkan Friedman test dan mixed-effects model digunakan untuk mempertimbangkan struktur observasi berulang antar tahun. Analisis anomali memberikan informasi tambahan mengenai kondisi bulan yang relatif tidak biasa.

Secara keseluruhan, dinamika curah hujan Banjarnegara selama 2017–2024 dapat dipahami sebagai kombinasi antara pola musiman, variasi antar tahun, frekuensi hari hujan, serta perubahan penyinaran matahari.

28 Keterbatasan

  1. Periode pengamatan hanya 2017–2024 sehingga relatif pendek untuk menyimpulkan trend iklim jangka panjang.
  2. Data berasal dari satu wilayah sehingga tidak dapat langsung digeneralisasikan ke wilayah lain.
  3. Data agregat bulanan tidak memungkinkan identifikasi intensitas hujan harian secara langsung.
  4. Analisis trend tahunan perlu ditafsirkan hati-hati karena hanya terdapat delapan tahun pengamatan.
  5. Korelasi tidak dapat diinterpretasikan sebagai hubungan sebab-akibat.
  6. Clustering bersifat eksploratif dan bukan penetapan musim klimatologis formal.