Pendahuluan

Data meteorologi merupakan data multidimensi yang terdiri atas banyak variabel saling berkorelasi, seperti suhu, tekanan udara, kelembaban, dan kecepatan angin. Penelitian ini menerapkan Principal Component Analysis (PCA) dan Factor Analysis (FA) pada Max Planck Weather Dataset (stasiun Jena, Jerman, 2009–2016) dengan tiga tujuan:

  1. Mereduksi 14 variabel meteorologi menjadi komponen utama tanpa kehilangan informasi substansial.
  2. Mengidentifikasi faktor laten yang membentuk pola variabilitas atmosfer.
  3. Mengevaluasi efektivitas PCA dan FA dalam menyederhanakan struktur data cuaca.

1. Library dan Dataset

Load Library

library(psych)        # u/ KMO, Bartlett, FA
library(FactoMineR)   # u/ PCA
library(factoextra)   # u/ Visualisasi PCA
## Loading required package: ggplot2
## 
## Attaching package: 'ggplot2'
## The following objects are masked from 'package:psych':
## 
##     %+%, alpha
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
library(corrplot)     # u/ Heatmap korelasi
## corrplot 0.95 loaded
library(tidyverse)    # u/ Manipulasi data
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.2.0     ✔ readr     2.2.0
## ✔ forcats   1.0.1     ✔ stringr   1.6.0
## ✔ lubridate 1.9.5     ✔ tibble    3.3.1
## ✔ purrr     1.2.1     ✔ tidyr     1.3.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ ggplot2::%+%()   masks psych::%+%()
## ✖ ggplot2::alpha() masks psych::alpha()
## ✖ dplyr::filter()  masks stats::filter()
## ✖ dplyr::lag()     masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors

Load Dataset

df_raw <- read.csv("max_planck_weather_ts.csv", stringsAsFactors = FALSE)
cat("\nDimensi data:", dim(df_raw), "\n")
## 
## Dimensi data: 420551 15

Dataset bersumber dari Kaggle - Max Planck Weather Dataset, berisi 420.551 observasi dengan interval pencatatan setiap 10 menit selama 8 tahun (2009–2016).


2. Preprocessing

#Seleksi variabel
df_numeric <- df_raw %>% select(where(is.numeric))
cat("Variabel yang digunakan:\n"); print(names(df_numeric))
## Variabel yang digunakan:
##  [1] "p..mbar."        "T..degC."        "Tpot..K."        "Tdew..degC."    
##  [5] "rh...."          "VPmax..mbar."    "VPact..mbar."    "VPdef..mbar."   
##  [9] "sh..g.kg."       "H2OC..mmol.mol." "rho..g.m..3."    "wv..m.s."       
## [13] "max..wv..m.s."   "wd..deg."
#Mengecek missing values
print(colSums(is.na(df_numeric)))
##        p..mbar.        T..degC.        Tpot..K.     Tdew..degC.          rh.... 
##               0               0               0               0               0 
##    VPmax..mbar.    VPact..mbar.    VPdef..mbar.       sh..g.kg. H2OC..mmol.mol. 
##               0               0               0               0               0 
##    rho..g.m..3.        wv..m.s.   max..wv..m.s.        wd..deg. 
##               0               0               0               0
#Menghapus missing values dan anomali -9999
df_clean <- df_numeric %>%
  filter(if_all(everything(), ~ . > -999))
cat("Observasi setelah melakukan filter anomali:", nrow(df_clean), "\n")
## Observasi setelah melakukan filter anomali: 420531
#Sampling
set.seed(123)
n_sample <- min(10000, nrow(df_clean))
df_sample <- df_clean %>%
  slice_sample(n = n_sample)
cat("Jumlah sampel:", nrow(df_sample))
## Jumlah sampel: 10000

Dari 420.551 observasi awal, 20 data teridentifikasi anomali sensor dan dihapus, menyisakan 420.531 observasi bersih. Sampel acak 10.000 diambil dengan set.seed(123) untuk menjamin reprodusibilitas.


3. Statistika Deskriptif

desc_stats <- describe(df_sample)
print(desc_stats[, c("n", "mean", "sd", "min", "max", "skew", "kurtosis")])
##                     n    mean    sd     min     max  skew kurtosis
## p..mbar.        10000  989.17  8.33  948.90 1015.29 -0.33     0.64
## T..degC.        10000    9.54  8.45  -23.01   35.36 -0.05    -0.17
## Tpot..K.        10000  283.59  8.53  250.60  309.66 -0.07    -0.12
## Tdew..degC.     10000    5.04  6.76  -25.01   23.06 -0.42     0.06
## rh....          10000   76.00 16.49   14.30  100.00 -0.66    -0.42
## VPmax..mbar.    10000   13.66  7.76    0.95   57.42  1.27     2.12
## VPact..mbar.    10000    9.59  4.20    0.79   28.24  0.55    -0.21
## VPdef..mbar.    10000    4.07  4.88    0.00   40.45  2.26     6.49
## sh..g.kg.       10000    6.06  2.67    0.50   18.07  0.56    -0.18
## H2OC..mmol.mol. 10000    9.70  4.26    0.80   28.73  0.55    -0.20
## rho..g.m..3.    10000 1215.61 40.11 1102.46 1392.10  0.33     0.15
## wv..m.s.        10000    2.14  1.54    0.00   13.95  1.46     2.88
## max..wv..m.s.   10000    3.54  2.35    0.00   20.49  1.33     2.41
## wd..deg.        10000  176.67 86.17    0.00  359.90 -0.49    -0.53

Interpretasi:

  1. T (°C): skewness ≈ 0 -> distribusi hampir simetris sempurna, mencerminkan variasi musiman yang seimbang antara musim panas dan dingin
  2. VPdef: skewness 2,26 dan kurtosis 6,49 -> distribusi paling ekstrem, defisit uap air tinggi hanya terjadi saat hari musim panas panas-kering
  3. wv & max.wv: skewness 1,46 dan 1,33 -> angin umumnya lemah namun sesekali sangat kencang (right-skewed)
  4. wd (°): mean 176,67° ≈ arah selatan, SD 86,17 -> arah angin sangat acak dan tersebar
Distribusi Variabel
df_long <- df_sample %>%
  pivot_longer(cols=everything(), names_to="Variabel", values_to="Nilai")

p_hist <- df_long %>%
  ggplot(aes(x = Nilai, fill = Variabel)) +
  geom_histogram(bins = 30, show.legend = FALSE, color = "white", alpha = 0.8) +
  facet_wrap(~Variabel, scales = "free") +
  theme_minimal(base_size = 9) +
  labs(title = "Gambar 1. Distribusi Frekuensi Variabel Cuaca") +
  scale_fill_brewer(palette = "Set3")
print(p_hist)
## Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Set3 is 12
## Returning the palette you asked for with that many colors
Gambar 1. Distribusi Variabel Cuaca (Histogram)

Gambar 1. Distribusi Variabel Cuaca (Histogram)

Histogram sebelum standardisasi memperlihatkan variabel suhu (T, Tpot, Tdew) dan tekanan udara (p, rho) mendekati distribusi normal simetris, mencerminkan variasi musiman yang teratur. Sebaliknya, variabel kecepatan angin (wv, max.wv), defisit tekanan uap (VPdef), dan tekanan uap maksimum (VPmax) menunjukkan distribusi miring kanan (right-skewed), mengindikasikan kondisi ekstrem yang jarang namun mungkin terjadi. Arah angin (wd) terdistribusi relatif merata (uniform), konsisten dengan sifat angin yang dapat bertiup dari segala arah.


4. Standardisasi

df_scaled <- as.data.frame(scale(df_sample))
cat("Range mean:", round(range(colMeans(df_scaled)),5), "(harus ~0)\n")
## Range mean: 0 0 (harus ~0)
cat("Range SD  :", round(range(apply(df_scaled,2,sd)),5), "(harus ~1)\n")
## Range SD  : 1 1 (harus ~1)

Range mean = 0 0 dan range SD = 1 1 -> standardisasi berhasil sempurna, seluruh 14 variabel kini setara secara skala.


5. Matriks Korelasi

cor_matrix <- cor(df_scaled)
corrplot(cor_matrix, method="color", type="upper", addCoef.col="black",
         number.cex=0.55, tl.cex=0.75, tl.col="black",
         col=colorRampPalette(c("#D73027","white","#1A9850"))(200),
         title="Heatmap Matriks Korelasi", mar=c(0,0,2,0))
Gambar 2. Heatmap Matriks Korelasi

Gambar 2. Heatmap Matriks Korelasi

Heatmap menunjukkan korelasi sangat kuat antar variabel termodinamika (T, Tpot, Tdew, VPmax, VPact, sh, H2OC), sementara wv dan max.wv membentuk kluster tersendiri. Pola ini mengindikasikan adanya struktur laten yang dapat diekstrak.


6. Uji Asumsi PCA

6.1 Uji Kaiser-Meyer-Olkin (KMO)

mat_corr <- cor(df_scaled)
kmo <- KMO(mat_corr)
cat("KMO Overall :", round(kmo$MSA, 3), "\n")
## KMO Overall : 0.746
cat("MSA per variabel:\n"); print(round(kmo$MSAi, 3))
## MSA per variabel:
##        p..mbar.        T..degC.        Tpot..K.     Tdew..degC.          rh.... 
##           0.080           0.745           0.761           0.831           0.760 
##    VPmax..mbar.    VPact..mbar.    VPdef..mbar.       sh..g.kg. H2OC..mmol.mol. 
##           0.771           0.764           0.679           0.822           0.843 
##    rho..g.m..3.        wv..m.s.   max..wv..m.s.        wd..deg. 
##           0.826           0.557           0.578           0.198

Interpretasi:

  1. KMO = 0,746 (kategori middling/cukup baik)
  2. Variabel terbaik: H2OC (0,843), Tdew (0,831), rho (0,826), sh (0,822) -> sangat terintegrasi
  3. Perhatian: p (0,080) dan wd (0,198) sangat rendah -> kedua variabel ini hampir independen dari yang lain, yang sebenarnya sudah terbukti dari heatmap korelasi
  4. Meskipun demikian, KMO overall 0,746 memenuhi syarat (> 0,5)

6.2 Uji Bartlett’s Test of Sphericity

bartlett <- cortest.bartlett(mat_corr, n = nrow(df_scaled))
cat("Chi-Square :", round(bartlett$chisq, 3), "\n")
## Chi-Square : 740419.9
cat("df         :", bartlett$df, "\n")
## df         : 91
cat("p-value    :", format(bartlett$p.value, scientific = TRUE), "\n")
## p-value    : 0e+00

Bartlett: Chi-Square = 740.419,9, p-value = 0,000 Nilai Chi-Square yang sangat besar mencerminkan n yang besar (10.000), dengan n besar bahkan korelasi kecil pun signifikan. Maka data layak untuk dilakukan PCA.


7. Principal Component Analysis (PCA)

7.1 Eigenvalue dan Variance Explained

pca <- PCA(df_scaled, graph = FALSE)
eig <- pca$eig
tabel_varians <- as.data.frame(eig)

colnames(tabel_varians) <- c("Eigenvalue", "Variance", "Cumulative")
tabel_varians$Komponen <- paste0("PC", 1:nrow(tabel_varians))

n_pc <- sum(eig[, 1] > 1)
cat("Jumlah PC (eigenvalue > 1):", n_pc, "\n")
## Jumlah PC (eigenvalue > 1): 4
cat("Total variance explained  :", round(eig[n_pc, 3], 2), "%\n")
## Total variance explained  : 92.03 %

Heatmap menunjukkan tiga pola korelasi yang terbentuk secara alami. Variabel termodinamika dan uap air (T, Tpot, VPmax, VPact, sh, H2OC, Tdew) saling berkorelasi kuat (r > 0,80), sementara rho berkorelasi negatif kuat dengan suhu (r = -0,96). Variabel angin (wv dan max.wv) berkorelasi kuat satu sama lain (r = 0,96) namun lemah terhadap kelompok lainnya. Variabel p dan wd berdiri sendiri dengan korelasi rendah terhadap semua variabel, mengindikasikan sifatnya yang independen.

7.2 Scree Plot

# PCA
pca <- PCA(df_scaled, graph = FALSE)

# Ambil eigenvalue
eig <- pca$eig
tabel_varians <- as.data.frame(eig)

# Rename kolom supaya aman
colnames(tabel_varians) <- c("Eigenvalue", 
                             "Variance", 
                             "Cumulative")

tabel_varians$Komponen <- paste0("PC", 1:nrow(tabel_varians))

# Hitung jumlah PC (Kaiser)
n_pc <- sum(tabel_varians$Eigenvalue > 1)

cat("Jumlah PC (eigenvalue > 1):", n_pc, "\n")
## Jumlah PC (eigenvalue > 1): 4
cat("Total variance explained  :", 
    round(tabel_varians$Cumulative[n_pc], 2), "%\n")
## Total variance explained  : 92.03 %
# Scree Plot
ggplot(tabel_varians, aes(x = 1:nrow(tabel_varians), y = Eigenvalue)) +
  geom_line(color = "blue", linewidth = 1) +
  geom_point(color = "red", size = 3) +
  geom_hline(yintercept = 1,
             linetype = "dashed",
             color = "darkgreen",
             linewidth = 1) +
  scale_x_continuous(breaks = 1:nrow(tabel_varians),
                     labels = tabel_varians$Komponen) +
  labs(title = "Scree Plot: Eigenvalue vs Komponen Utama",
       x = "Komponen Utama (Principal Component)",
       y = "Eigenvalue") +
  theme_minimal()
Gambar 3. Scree Plot PCA

Gambar 3. Scree Plot PCA

Scree plot memperlihatkan penurunan tajam dari PC1 ke PC2, kemudian menurun lebih landai hingga PC4. Setelah PC4, kurva sudah mendatar dan seluruh eigenvalue berada di bawah nilai 1. Patahan (elbow) yang jelas setelah PC4 mempertegas bahwa 4 komponen utama cukup untuk merepresentasikan struktur data.

7.3 Loadings

print(round(pca$var$coord[, 1:n_pc], 3))
##                  Dim.1  Dim.2  Dim.3  Dim.4
## p..mbar.        -0.114 -0.194 -0.656  0.246
## T..degC.         0.987  0.040 -0.094 -0.023
## Tpot..K.         0.989  0.055 -0.042 -0.042
## Tdew..degC.      0.920 -0.287  0.181  0.053
## rh....          -0.496 -0.625  0.517  0.161
## VPmax..mbar.     0.961  0.097 -0.194  0.004
## VPact..mbar.     0.920 -0.307  0.164  0.092
## VPdef..mbar.     0.734  0.418 -0.449 -0.072
## sh..g.kg.        0.921 -0.304  0.174  0.088
## H2OC..mmol.mol.  0.921 -0.304  0.174  0.088
## rho..g.m..3.    -0.968 -0.065 -0.104  0.084
## wv..m.s.         0.110  0.856  0.374  0.169
## max..wv..m.s.    0.143  0.873  0.337  0.108
## wd..deg.         0.028 -0.047  0.112 -0.929

Interpretasi:

  • PC1 didominasi oleh variabel suhu dan kandungan uap air dengan loading positif tinggi, serta rho dengan loading negatif, mencerminkan faktor termodinamika atmosfer.
  • PC2 didominasi oleh wv dan max.wv dengan loading positif, serta rh negatif, mencerminkan faktor dinamika angin.
  • PC3 didominasi oleh p negatif dan rh positif, mencerminkan faktor tekanan atmosfer.
  • PC4 secara eksklusif didominasi oleh wd, mencerminkan arah angin yang independen dari komponen lainnya.

8. Factor Analysis (FA)

8.1 Parallel Analysis

parallel  <- fa.parallel(df_scaled, fm = "ml", fa = "fa",
                         main = "Parallel Analysis Scree Plot")
Gambar 6. Parallel Analysis Scree Plot

Gambar 6. Parallel Analysis Scree Plot

## Parallel analysis suggests that the number of factors =  5  and the number of components =  NA
n_factors <- parallel$nfact
cat("Jumlah faktor optimal:", n_factors, "\n")
## Jumlah faktor optimal: 5

Parallel analysis menunjukkan bahwa eigenvalue data nyata berada di atas eigenvalue data acak hingga faktor ke-5, dan mulai faktor ke-6 sudah berada di bawahnya. Berdasarkan hal ini, jumlah faktor optimal yang direkomendasikan adalah 5 faktor.

8.2 Factor Analysis – Rotasi Varimax

fa_result <- fa(df_scaled, nfactors = n_factors,
                rotate = "varimax", fm = "ml")

Hasil FA dengan rotasi varimax menghasilkan 5 faktor yang secara kumulatif menjelaskan 91,3% variansi total. Rata-rata communality sebesar 0,913 menunjukkan bahwa model mampu merepresentasikan hampir seluruh variansi tiap variabel dengan baik, kecuali wd (0,035) yang bersifat sirkular dan independen secara alami.

8.3 Factor Loadings

print(round(fa_result$loadings[, 1:n_factors], 3))
##                    ML1    ML3    ML4    ML2    ML5
## p..mbar.        -0.061  0.027 -0.147  0.969  0.173
## T..degC.         0.843  0.508  0.076  0.029 -0.152
## Tpot..K.         0.842  0.502  0.087 -0.048 -0.164
## Tdew..degC.      0.970  0.107 -0.023  0.013 -0.169
## rh....          -0.097 -0.891 -0.242 -0.053  0.081
## VPmax..mbar.     0.781  0.609  0.040 -0.019  0.126
## VPact..mbar.     0.994  0.079 -0.052 -0.015  0.036
## VPdef..mbar.     0.385  0.898  0.108 -0.017  0.170
## sh..g.kg.        0.994  0.078 -0.050 -0.030  0.036
## H2OC..mmol.mol.  0.994  0.079 -0.049 -0.030  0.034
## rho..g.m..3.    -0.832 -0.446 -0.108  0.221  0.217
## wv..m.s.        -0.019  0.123  0.962 -0.086  0.074
## max..wv..m.s.   -0.009  0.176  0.961 -0.075  0.053
## wd..deg.         0.020 -0.006 -0.023 -0.033 -0.182

Interpretasi faktor:

  • ML1 mendapat loading dominan dari VPact, sh, H2OC, Tdew, T, dan Tpot, sehingga diidentifikasi sebagai faktor kandungan uap air dan suhu.
  • ML2 secara eksklusif didominasi oleh p, merepresentasikan faktor tekanan atmosfer.
  • ML3 didominasi oleh VPdef positif dan rh negatif, merepresentasikan faktor defisit uap air dan kekeringan.
  • ML4 hanya didominasi wv dan max.wv, merepresentasikan faktor dinamika angin secara murni.
  • ML5 tidak memiliki loading dominan pada variabel manapun sehingga dikategorikan sebagai faktor residual.

8.4 Communalities

# 10d. Communalities (Ringkas)
communalities <- round(fa_result$communality, 3)
summary(communalities)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##  0.0350  0.9677  0.9970  0.9131  0.9980  0.9980
cat("Rata-rata communality:", round(mean(communalities), 3), "\n")
## Rata-rata communality: 0.913
cat("Communality minimum :", round(min(communalities), 3), "\n")
## Communality minimum : 0.035
cat("Communality maksimum:", round(max(communalities), 3), "\n")
## Communality maksimum: 0.998

Interpretasi:

  1. Rata-rata = 0,913 artinya model sangat baik
  2. Maksimum = 0,998 (VPact, sh, H2OC, dll)
  3. Minimum = 0,035 (wd), artinya arah angin bersifat sirkular (0°–360°) dan acak, dan tidak memiliki hubungan linier dengan variabel atmosfer lain.

8.5 Variance Explained per Faktor

print(round(fa_result$Vaccounted, 3))
##                         ML1   ML3   ML4   ML2   ML5
## SS loadings           6.788 2.759 1.977 1.011 0.252
## Proportion Var        0.485 0.197 0.141 0.072 0.018
## Cumulative Var        0.485 0.682 0.823 0.895 0.913
## Proportion Explained  0.531 0.216 0.155 0.079 0.020
## Cumulative Proportion 0.531 0.747 0.901 0.980 1.000

Variance Explained kumulatif 91,3% ini artinya model FA sangat komprehensif


Kesimpulan

PCA berhasil mereduksi 14 variabel meteorologi menjadi 4 komponen utama yang menjelaskan 92,03% total variansi, terdiri dari faktor termodinamika dan kandungan uap air (57,37%), dinamika angin (17,71%), tekanan atmosfer (9,60%), dan arah angin (7,36%). Hasil Factor Analysis dengan rotasi varimax mengidentifikasi 5 faktor laten yang menjelaskan 91,3% variansi total, yaitu faktor kandungan uap air dan suhu, defisit uap air dan kekeringan, dinamika angin, tekanan atmosfer, dan faktor residual. Rata-rata communality sebesar 0,913 menunjukkan bahwa model mampu merepresentasikan hampir seluruh variansi tiap variabel, kecuali arah angin (wd) yang bersifat independen dengan communality hanya 0,035. Secara keseluruhan, kedua metode terbukti efektif dalam menyederhanakan struktur data atmosfer yang kompleks tanpa kehilangan informasi utama.


Referensi

Jolliffe, I. T., & Cadima, J. (2024). Principal component analysis: a review and recent developments. Philosophical transactions. Series A, Mathematical, physical, and engineering sciences, 374(2065), 20150202. https://doi.org/10.1098/rsta.2015.0202

Bashir, R. N., Mzoughi, O., Shahid, M. A., Alturki, N., & Saidani, O. (2024). Principal Component Analysis (PCA) and feature importance‑based dimension reduction for Reference Evapotranspiration (ET0) predictions of Taif, Saudi Arabia. Computers and Electronics in Agriculture, 222, 109036. https://doi.org/10.1016/j.compag.2024.109036

Mannan, Abd., Suparto, Suparto & Kusaeri, Kusaeri. (2025). Practices and Challenges of the Validity of Exploratory Factor Analysis (EFA)-Based Assessment Instruments: A Systematic Literature Review 2020–2025. EDUKASIA Jurnal Pendidikan dan Pembelajaran. 10.62775/edukasia.v6i1.1463

Tavakol, M., & Wetzel, A. (2020). Factor Analysis: a means for theory and instrument development in support of construct validity. International journal of medical education, 11, 245–247. https://doi.org/10.5116/ijme.5f96.0f4a

Wickham, H., & Grolemund, G. (2022). R for data science: Import, tidy, transform, visualize, and model data (Online version). Retrieved from https://r4ds.hadley.nz/missing-values.html

Zhang, Q., Zhou, T., & Li, F. (2021). Climate variability and extreme weather events under global warming: A review of recent advances. Earth-Science Reviews, 221, 103787. https://doi.org/10.1016/j.earscirev.2021.103787

Dataset: Agarwal, R. (n.d.). Max Planck Weather Dataset. Kaggle. https://www.kaggle.com/datasets/arashnic/max-planck-weather-dataset