Project ini bertujuan untuk mengimplementasikan metode klasifikasi statistika pada data meteorologi sintetis. Dataset ini mencakup berbagai parameter cuaca yang digunakan untuk memprediksi empat kategori utama: Rainy, Sunny, Cloudy, dan Snowy.
Variabel yang digunakan meliputi:
- Atmosfer: Temperature, Humidity, Pressure.
- Kondisi Lingkungan: Wind Speed, UV Index, Visibility.
Analisis ini dilakukan pada data yang telah melalui tahap preprocessing untuk memastikan model LDA dan Multinomial bekerja secara optimal.
options(repos = c(CRAN = "[https://cloud.r-project.org](https://cloud.r-project.org)"))
library(nnet)
library(MASS)
library(caret)
library(ggplot2)
library(biotools)
Tahap awal pada penelitian dimulai dengan memuat paket yang diperlukan. Setiap paket memiliki fungsi spesifik sebagai berikut: - MASS → membangun model Linear Discriminant Analysis (LDA) - nnet → membangun model Multinomial Logistic Regression - caret → evaluasi performa model (confusion matrix, accuracy, Kappa) - ggplot2 → visualisasi data - biotools → uji asumsi LDA (Box’s M test) Tujuan tahap ini dilakukan adalah untuk menyiapkan lingkungan analisis agar seluruh metode dapat dijalankan dengan optimal.
weather_df <- read.csv("weather_classification_data.csv")
Dataset yang digunakan berisi informasi kondisi cuaca berdasarkan beberapa variabel meteorologi seperti suhu, kelembapan, tekanan udara, dan lain-lain. Variabel targetnya adalah Weather_Type yang menunjukkan jenis cuaca.
# Struktur data
str(weather_df)
## 'data.frame': 13200 obs. of 11 variables:
## $ Temperature : num 14 39 30 38 27 32 -2 3 3 28 ...
## $ Humidity : int 73 96 64 83 74 55 97 85 83 74 ...
## $ Wind.Speed : num 9.5 8.5 7 1.5 17 3.5 8 6 6 8.5 ...
## $ Precipitation.... : num 82 71 16 82 66 26 86 96 66 107 ...
## $ Cloud.Cover : chr "partly cloudy" "partly cloudy" "clear" "clear" ...
## $ Atmospheric.Pressure: num 1011 1011 1019 1026 991 ...
## $ UV.Index : int 2 7 5 7 1 2 1 1 0 8 ...
## $ Season : chr "Winter" "Spring" "Spring" "Spring" ...
## $ Visibility..km. : num 3.5 10 5.5 1 2.5 5 4 3.5 1 7.5 ...
## $ Location : chr "inland" "inland" "mountain" "coastal" ...
## $ Weather.Type : chr "Rainy" "Cloudy" "Sunny" "Sunny" ...
# Cek missing value
colSums(is.na(weather_df))
## Temperature Humidity Wind.Speed
## 0 0 0
## Precipitation.... Cloud.Cover Atmospheric.Pressure
## 0 0 0
## UV.Index Season Visibility..km.
## 0 0 0
## Location Weather.Type
## 0 0
Melakukan pemeriksaan nilai kosong untuk memastikan kualitas data. Hasil yang di peroleh menunjukkan tidak terdapat missing value, sehingga data siap digunakan tanpa imputasi.
# 1. Membersihkan Nama Kolom
colnames(weather_df) <- c("Temperature", "Humidity", "Wind_Speed", "Precipitation",
"Cloud_Cover", "Pressure", "UV_Index", "Season",
"Visibility", "Location", "Weather_Type")
# 2. Mengambil Sampel Acak 500 Data
set.seed(123) # Agar hasil random selalu sama setiap kali di-run
weather_df <- weather_df[sample(nrow(weather_df), 500), ]
Pada tahap ini dilakukan persiapan data sebelum analisis. Pertama, nama kolom diperbaiki agar lebih jelas dan mudah dipahami. Selanjutnya diambil sampel acak sebanyak 500 data menggunakan set.seed(123) supaya hasil sampling konsisten setiap kali dijalankan serta untuk mempercepat proses komputasi.
weather_df$Season <- as.factor(weather_df$Season)
weather_df$Cloud_Cover <- as.factor(weather_df$Cloud_Cover)
weather_df$Location <- as.factor(weather_df$Location)
weather_df$Weather_Type <- as.factor(weather_df$Weather_Type)
Variabel kategorik yaitu Season, Cloud_Cover, Location, dan Weather_Type diubah menjadi tipe faktor agar dapat digunakan dengan benar pada metode klasifikasi seperti LDA dan regresi logistik multinomial.
# Struktur data setelah sampling
str(weather_df)
## 'data.frame': 500 obs. of 11 variables:
## $ Temperature : num 41 27 -7 4 22 42 -7 31 44 1 ...
## $ Humidity : int 76 74 82 91 38 33 77 33 35 94 ...
## $ Wind_Speed : num 10.5 0.5 11.5 6.5 2.5 5.5 1.5 8 7 14.5 ...
## $ Precipitation: num 76 19 95 68 11 19 66 14 2 95 ...
## $ Cloud_Cover : Factor w/ 4 levels "clear","cloudy",..: 3 4 3 4 1 4 3 1 4 3 ...
## $ Pressure : num 1134 1018 998 989 1025 ...
## $ UV_Index : int 7 3 1 1 11 8 0 10 6 1 ...
## $ Season : Factor w/ 4 levels "Autumn","Spring",..: 2 1 4 4 2 2 4 2 2 4 ...
## $ Visibility : num 3.5 8.5 3.5 4.5 7.5 6.5 4 5.5 6.5 2 ...
## $ Location : Factor w/ 3 levels "coastal","inland",..: 2 1 2 3 3 2 2 2 2 2 ...
## $ Weather_Type : Factor w/ 4 levels "Cloudy","Rainy",..: 1 1 3 3 4 4 3 4 4 3 ...
# Distribusi kelas setelah sampling
table(weather_df$Weather_Type)
##
## Cloudy Rainy Snowy Sunny
## 124 127 115 134
# Visualisasi Distribusi
ggplot(weather_df, aes(Weather_Type, fill = Weather_Type)) +
geom_bar() +
theme_minimal() +
labs(title="Distribusi Kelas Cuaca (Sampel 500 Data)")
Tahap ini bertujuan untuk memahami kondisi data setelah proses sampling.
Fungsi str() digunakan untuk melihat struktur dataset seperti tipe
variabel dan jumlah observasi, sehingga dapat dipastikan data sudah
sesuai untuk analisis. Selanjutnya, table() digunakan untuk melihat
jumlah masing-masing kelas dan Weather_Type guna untuk mengetahui apakah
distribusi kelas seimbang atau tidak. Terakhir, grafik bar dibuat
menggunakan ggplot untuk memvisualisasikan distribusi kelas secara lebih
jelas sehingga memudahkan melihat kelas cuaca mana yang paling dominan
pada sampel 500 data.
summary(weather_df[, c("Temperature", "Humidity", "Wind_Speed", "Precipitation", "Pressure")])
## Temperature Humidity Wind_Speed Precipitation
## Min. :-24.0 Min. : 20.00 Min. : 0.000 Min. : 0.0
## 1st Qu.: 11.0 1st Qu.: 56.00 1st Qu.: 4.500 1st Qu.: 18.0
## Median : 22.0 Median : 70.00 Median : 8.000 Median : 56.0
## Mean : 20.2 Mean : 68.55 Mean : 9.021 Mean : 52.1
## 3rd Qu.: 31.0 3rd Qu.: 84.00 3rd Qu.:12.625 3rd Qu.: 82.0
## Max. :109.0 Max. :109.00 Max. :41.000 Max. :109.0
## Pressure
## Min. : 812.0
## 1st Qu.: 996.1
## Median :1009.5
## Mean :1007.6
## 3rd Qu.:1016.0
## Max. :1187.7
cor_matrix <- cor(weather_df[, sapply(weather_df, is.numeric)])
print(cor_matrix)
## Temperature Humidity Wind_Speed Precipitation Pressure
## Temperature 1.000000000 -0.2746240 0.005518159 -0.3407581 0.18948408
## Humidity -0.274623992 1.0000000 0.326115333 0.6260091 -0.11775474
## Wind_Speed 0.005518159 0.3261153 1.000000000 0.4194789 -0.05203059
## Precipitation -0.340758081 0.6260091 0.419478933 1.0000000 -0.20211785
## Pressure 0.189484084 -0.1177547 -0.052030589 -0.2021178 1.00000000
## UV_Index 0.443556835 -0.4668041 -0.112364365 -0.3477374 0.12971614
## Visibility 0.274792463 -0.4864713 -0.260099057 -0.5016860 0.20680900
## UV_Index Visibility
## Temperature 0.4435568 0.2747925
## Humidity -0.4668041 -0.4864713
## Wind_Speed -0.1123644 -0.2600991
## Precipitation -0.3477374 -0.5016860
## Pressure 0.1297161 0.2068090
## UV_Index 1.0000000 0.4053526
## Visibility 0.4053526 1.0000000
Langkah ini digunakan untuk memahami karakteristik variabel numerik sebelum pemodelan. Fungsi summary() digunakan untuk melihat statistik deskriptif seperti nilai minimum, maksimum, mean, dan median pada variabel Temperature, Humidity, Wind_Speed, Precipitation, dan Pressure. Tujuannya untuk mengetahui gambaran umum data serta mendeteksi kemungkinan adanya nilai ekstrem atau outlier.
Selanjutnya dibuat matriks korelasi menggunakan cor() untuk melihat hubungan antar variabel numerik. Dari hasil korelasi ini dapat diketahui apakah terdapat hubungan yang sangat kuat antar variabel (multikolinearitas). Informasi ini penting karena korelasi yang terlalu tinggi bisa mempengaruhi performa model klasifikasi yang akan dibangun.
ggplot(weather_df, aes(x = Weather_Type, y = Humidity, fill = Weather_Type)) +
geom_boxplot() +
theme_minimal() +
labs(title = "Variasi Kelembapan pada Setiap Tipe Cuaca",
x = "Weather Type", y = "Humidity (Standardized)")
Visualisasi boxplot ini digunakan untuk melihat perbedaan distribusi
kelembapan (Humidity) pada setiap kategori Weather_Type. Melalui grafik
ini, kita bisa membandingkan nilai median, sebaran data, serta
mendeteksi outlier pada masing-masing tipe cuaca. Jika terlihat
perbedaan pola antar kelas (misalnya ada tipe cuaca yang memiliki
kelembapan lebih tinggi atau lebih rendah), maka variabel Humidity
berpotensi menjadi variabel yang penting dalam proses klasifikasi cuaca
menggunakan model LDA maupun regresi multinomial.
ggplot(weather_df, aes(x = Temperature, y = Humidity, color = Weather_Type)) +
geom_point(alpha = 0.7, size = 2) +
theme_minimal() +
labs(title = "Scatter Plot: Temperature vs Humidity (Sampel 500)",
subtitle = "Pola sebaran antar kelas lebih mudah dibedakan")
Scatter plot digunakan untuk melihat hubungan antara Temperature dan
Humidity pada tiap kategori Weather_Type. Melalui grafik ini kita bisa
mengamati apakah terdapat pola pemisahan antar kelas cuaca berdasarkan
kombinasi suhu dan kelembapan. Jika titik-titik dari tiap tipe cuaca
membentuk kelompok (cluster) yang cukup berbeda, maka kedua variabel ini
memiliki kemampuan yang baik untuk membedakan jenis cuaca dan cocok
digunakan sebagai variabel prediktor pada model klasifikasi.
ggplot(weather_df, aes(x = Temperature, fill = Weather_Type)) +
geom_density(alpha = 0.5) +
theme_minimal() +
labs(title = "Distribusi Suhu berdasarkan Tipe Cuaca",
x = "Temperature (Standardized)", y = "Density")
Plot density digunakan untuk melihat sebaran nilai Temperature pada
setiap kategori Weather_Type. Dari grafik ini kita bisa membandingkan
apakah distribusi suhu tiap tipe cuaca saling tumpang tindih atau
memiliki pola yang berbeda. Jika kurva density antar kelas terlihat
berbeda atau bergeser, artinya suhu merupakan variabel yang cukup
informatif untuk membedakan tipe cuaca. Sebaliknya, jika kurvanya sangat
bertumpuk, maka kemampuan suhu dalam membedakan kelas cuaca relatif
rendah.
cor_matrix <- cor(weather_df[, sapply(weather_df, is.numeric)])
print(cor_matrix)
## Temperature Humidity Wind_Speed Precipitation Pressure
## Temperature 1.000000000 -0.2746240 0.005518159 -0.3407581 0.18948408
## Humidity -0.274623992 1.0000000 0.326115333 0.6260091 -0.11775474
## Wind_Speed 0.005518159 0.3261153 1.000000000 0.4194789 -0.05203059
## Precipitation -0.340758081 0.6260091 0.419478933 1.0000000 -0.20211785
## Pressure 0.189484084 -0.1177547 -0.052030589 -0.2021178 1.00000000
## UV_Index 0.443556835 -0.4668041 -0.112364365 -0.3477374 0.12971614
## Visibility 0.274792463 -0.4864713 -0.260099057 -0.5016860 0.20680900
## UV_Index Visibility
## Temperature 0.4435568 0.2747925
## Humidity -0.4668041 -0.4864713
## Wind_Speed -0.1123644 -0.2600991
## Precipitation -0.3477374 -0.5016860
## Pressure 0.1297161 0.2068090
## UV_Index 1.0000000 0.4053526
## Visibility 0.4053526 1.0000000
Langkah ini berfungsi untuk menghitung dan melihat korelasi antar variabel numerik pada dataset. Matriks korelasi menunjukkan seberapa kuat hubungan antar variabel dalam rentang -1 sampai 1. - Nilai mendekati 1 → hubungan positif kuat (jika satu naik, yang lain ikut naik). - Nilai mendekati -1 → hubungan negatif kuat (jika satu naik, yang lain turun). - Nilai mendekati 0 → hubungan lemah/tidak ada hubungan linear.
Tujuan utama pengecekan ini adalah untuk mendeteksi multikolinearitas. Jika ada variabel yang memiliki korelasi sangat tinggi (biasanya > 0.8), maka variabel tersebut bisa memberikan informasi yang mirip dan dapat mempengaruhi performa model klasifikasi seperti LDA dan regresi multinomial.
set.seed(123)
train_index <- createDataPartition(weather_df$Weather_Type,
p = 0.8,
list = FALSE)
train_data <- weather_df[train_index, ]
test_data <- weather_df[-train_index, ]
# Cek Jumlah Data
dim(train_data)
## [1] 402 11
dim(test_data)
## [1] 98 11
Langkah ini merupakan proses membagi dataset menjadi data training dan data testing. Pertama, set.seed(123) digunakan agar proses pembagian data bersifat reproducible, sehingga hasil pembagian akan selalu sama setiap kali kode dijalankan. Fungsi createDataPartition() digunakan untuk membagi data secara stratified, artinya proporsi tiap kelas pada variabel target Weather_Type tetap seimbang pada data training dan testing. Dataset dibagi dengan komposisi 80% data training dan 20% data testing. train_data digunakan untuk melatih model (LDA dan Multinomial) dan test_data digunakan untuk menguji performa model pada data yang belum pernah dilihat sebelumnya. Terakhir, fungsi dim() digunakan untuk memastikan jumlah baris dan kolom pada masing-masing dataset setelah proses pembagian.
num_cols <- c("Temperature","Humidity","Wind_Speed",
"Precipitation","Pressure","UV_Index","Visibility")
preproc <- preProcess(train_data[,num_cols], method = c("center","scale"))
train_data[,num_cols] <- predict(preproc, train_data[,num_cols])
test_data[,num_cols] <- predict(preproc, test_data[,num_cols])
Langkah ini merupakan proses standarisasi (scaling) variabel numerik sebelum pemodelan dilakukan. Pertama, membuat daftar variabel numerik yang akan distandarisasi, yaitu suhu, kelembapan, kecepatan angin, curah hujan, tekanan udara, UV index, dan jarak pandang. Fungsi preProcess() dengan metode center dan scale digunakan untuk: - Center: mengubah rata-rata tiap variabel menjadi 0 - Scale: mengubah standar deviasi menjadi 1 Tujuan standarisasi ini dilakukan adalah agar semua variabel memiliki skala yang sama, sehingga tidak ada variabel yang mendominasi model hanya karena memiliki nilai yang lebih besar. Langkah ini penting karena Model LDA dan regresi logistik sensitif terhadap perbedaan skala. Standarisasi dihitung dari data training, lalu diterapkan ke data testing menggunakan predict(). Hal ini dilakukan untuk mencegah data leakage (kebocoran informasi dari data test ke training).
# Uji Asumsi LDA
boxM(train_data[,num_cols], train_data$Weather_Type)
##
## Box's M-test for Homogeneity of Covariance Matrices
##
## data: train_data[, num_cols]
## Chi-Sq (approx.) = 456.09, df = 84, p-value < 2.2e-16
Langkah ini digunakan untuk menguji asumsi utama pada metode LDA, yaitu asumsi homogenitas matriks kovarians antar kelompok kelas cuaca. Fungsi boxM() melakukan Box’s M Test, yaitu uji statistik untuk mengecek apakah varians–kovarians variabel numerik pada setiap kelas Weather_Type memiliki pola yang sama. Tujuan uji ini adalah menguji apakah LDA mengasumsikan bahwa setiap kelas memiliki matriks kovarians yang sama (homogen). Jika asumsi ini terpenuhi, maka hasil klasifikasi LDA akan lebih valid dan optimal. Cara interpretasi hasil yang dilakukan adalah Jika p-value > 0.05 → asumsi homogenitas terpenuhi → LDA layak digunakan dan Jika p-value < 0.05 → asumsi tidak terpenuhi → performa LDA bisa kurang optimal, namun model masih bisa digunakan dengan catatan interpretasi lebih hati-hati.
# Membangun model LDA
model_lda <- lda(Weather_Type ~ Temperature + Humidity + Wind_Speed +
Precipitation + Pressure + UV_Index + Visibility,
data = train_data)
model_lda
## Call:
## lda(Weather_Type ~ Temperature + Humidity + Wind_Speed + Precipitation +
## Pressure + UV_Index + Visibility, data = train_data)
##
## Prior probabilities of groups:
## Cloudy Rainy Snowy Sunny
## 0.2487562 0.2537313 0.2288557 0.2686567
##
## Group means:
## Temperature Humidity Wind_Speed Precipitation Pressure
## Cloudy 0.2392317 -0.07499572 -0.113874808 -0.4349387 0.03771018
## Rainy 0.2061653 0.58687386 0.667264814 0.7076855 -0.09683412
## Snowy -1.2788286 0.54128950 -0.008733432 0.7456646 -0.38257904
## Sunny 0.6731500 -0.94592773 -0.517315320 -0.9008443 0.38243828
## UV_Index Visibility
## Cloudy -0.1512825 0.3734005
## Rainy -0.4800781 -0.5171669
## Snowy -0.5591187 -0.5146147
## Sunny 1.0697697 0.5810697
##
## Coefficients of linear discriminants:
## LD1 LD2 LD3
## Temperature -0.72854647 -1.19449844 0.1588008
## Humidity 0.32763868 -0.13564661 -0.4873462
## Wind_Speed 0.15459724 -0.42731629 0.0455756
## Precipitation 0.85770506 -0.10185709 0.7679367
## Pressure -0.05591093 -0.08510031 0.1636586
## UV_Index -0.61353965 0.80365705 0.7123481
## Visibility 0.04834540 -0.08402491 -0.7068022
##
## Proportion of trace:
## LD1 LD2 LD3
## 0.7933 0.1647 0.0420
# Menampilkan hasil (Prior probabilities & Coefficients)
print(model_lda)
## Call:
## lda(Weather_Type ~ Temperature + Humidity + Wind_Speed + Precipitation +
## Pressure + UV_Index + Visibility, data = train_data)
##
## Prior probabilities of groups:
## Cloudy Rainy Snowy Sunny
## 0.2487562 0.2537313 0.2288557 0.2686567
##
## Group means:
## Temperature Humidity Wind_Speed Precipitation Pressure
## Cloudy 0.2392317 -0.07499572 -0.113874808 -0.4349387 0.03771018
## Rainy 0.2061653 0.58687386 0.667264814 0.7076855 -0.09683412
## Snowy -1.2788286 0.54128950 -0.008733432 0.7456646 -0.38257904
## Sunny 0.6731500 -0.94592773 -0.517315320 -0.9008443 0.38243828
## UV_Index Visibility
## Cloudy -0.1512825 0.3734005
## Rainy -0.4800781 -0.5171669
## Snowy -0.5591187 -0.5146147
## Sunny 1.0697697 0.5810697
##
## Coefficients of linear discriminants:
## LD1 LD2 LD3
## Temperature -0.72854647 -1.19449844 0.1588008
## Humidity 0.32763868 -0.13564661 -0.4873462
## Wind_Speed 0.15459724 -0.42731629 0.0455756
## Precipitation 0.85770506 -0.10185709 0.7679367
## Pressure -0.05591093 -0.08510031 0.1636586
## UV_Index -0.61353965 0.80365705 0.7123481
## Visibility 0.04834540 -0.08402491 -0.7068022
##
## Proportion of trace:
## LD1 LD2 LD3
## 0.7933 0.1647 0.0420
# Kontribusi variabel ke fungsi diskriminan
model_lda$scaling
## LD1 LD2 LD3
## Temperature -0.72854647 -1.19449844 0.1588008
## Humidity 0.32763868 -0.13564661 -0.4873462
## Wind_Speed 0.15459724 -0.42731629 0.0455756
## Precipitation 0.85770506 -0.10185709 0.7679367
## Pressure -0.05591093 -0.08510031 0.1636586
## UV_Index -0.61353965 0.80365705 0.7123481
## Visibility 0.04834540 -0.08402491 -0.7068022
# Prediksi ke Data Test
pred_lda <- predict(model_lda, newdata = test_data)
pred_class_lda <- pred_lda$class
cm_lda <- confusionMatrix(pred_class_lda, test_data$Weather_Type)
# Confusion Matrix
confusionMatrix(pred_class_lda, test_data$Weather_Type)
## Confusion Matrix and Statistics
##
## Reference
## Prediction Cloudy Rainy Snowy Sunny
## Cloudy 18 1 0 0
## Rainy 4 19 0 3
## Snowy 2 4 21 2
## Sunny 0 1 2 21
##
## Overall Statistics
##
## Accuracy : 0.8061
## 95% CI : (0.7139, 0.879)
## No Information Rate : 0.2653
## P-Value [Acc > NIR] : < 2.2e-16
##
## Kappa : 0.7416
##
## Mcnemar's Test P-Value : NA
##
## Statistics by Class:
##
## Class: Cloudy Class: Rainy Class: Snowy Class: Sunny
## Sensitivity 0.7500 0.7600 0.9130 0.8077
## Specificity 0.9865 0.9041 0.8933 0.9583
## Pos Pred Value 0.9474 0.7308 0.7241 0.8750
## Neg Pred Value 0.9241 0.9167 0.9710 0.9324
## Prevalence 0.2449 0.2551 0.2347 0.2653
## Detection Rate 0.1837 0.1939 0.2143 0.2143
## Detection Prevalence 0.1939 0.2653 0.2959 0.2449
## Balanced Accuracy 0.8682 0.8321 0.9032 0.8830
# Detail performa per kelas LDA
confusionMatrix(pred_class_lda, test_data$Weather_Type)$byClass
## Sensitivity Specificity Pos Pred Value Neg Pred Value Precision
## Class: Cloudy 0.7500000 0.9864865 0.9473684 0.9240506 0.9473684
## Class: Rainy 0.7600000 0.9041096 0.7307692 0.9166667 0.7307692
## Class: Snowy 0.9130435 0.8933333 0.7241379 0.9710145 0.7241379
## Class: Sunny 0.8076923 0.9583333 0.8750000 0.9324324 0.8750000
## Recall F1 Prevalence Detection Rate
## Class: Cloudy 0.7500000 0.8372093 0.2448980 0.1836735
## Class: Rainy 0.7600000 0.7450980 0.2551020 0.1938776
## Class: Snowy 0.9130435 0.8076923 0.2346939 0.2142857
## Class: Sunny 0.8076923 0.8400000 0.2653061 0.2142857
## Detection Prevalence Balanced Accuracy
## Class: Cloudy 0.1938776 0.8682432
## Class: Rainy 0.2653061 0.8320548
## Class: Snowy 0.2959184 0.9031884
## Class: Sunny 0.2448980 0.8830128
# Hitung Akurasi LDA
acc_lda <- mean(pred_class_lda == test_data$Weather_Type)
acc_lda
## [1] 0.8061224
# Visualisasi LDA
lda_df <- data.frame(
LD1 = pred_lda$x[,1],
LD2 = pred_lda$x[,2],
Weather_Type = test_data$Weather_Type
)
ggplot(lda_df, aes(LD1, LD2, color = Weather_Type)) +
geom_point(size = 2, alpha = 0.7) +
theme_minimal() +
labs(title = "Visualisasi Hasil Klasifikasi LDA")
# Uji Signifikasi Model LDA
lda_pred_train <- predict(model_lda)$class
lda_table <- table(lda_pred_train, train_data$Weather_Type)
lda_table
##
## lda_pred_train Cloudy Rainy Snowy Sunny
## Cloudy 84 7 2 3
## Rainy 9 91 1 9
## Snowy 2 4 84 5
## Sunny 5 0 5 91
# Menghitung akurasi training
train_acc_lda <- mean(lda_pred_train == train_data$Weather_Type)
train_acc_lda
## [1] 0.8706468
Model LDA dibuat untuk mengklasifikasikan tipe cuaca berdasarkan variabel numerik. Output model menunjukkan kontribusi tiap variabel dalam membedakan kelas cuaca. Model kemudian digunakan untuk memprediksi data test dan dievaluasi menggunakan confusion matrix serta akurasi. Visualisasi LD1–LD2 digunakan untuk melihat pemisahan antar kelas. Terakhir, akurasi pada data training dihitung untuk membandingkan performa training vs testing dan mengecek kemungkinan overfitting.
cm_lda <- confusionMatrix(pred_class_lda, test_data$Weather_Type)
cm_lda_df <- as.data.frame(cm_lda$table)
ggplot(cm_lda_df, aes(Reference, Prediction, fill = Freq)) +
geom_tile() +
geom_text(aes(label = Freq), color = "white") +
scale_fill_gradient(low = "lightblue", high = "darkblue") +
theme_minimal() +
labs(title = "Heatmap Confusion Matrix - LDA",
x = "Data Aktual (Reference)",
y = "Data Prediksi (Prediction)")
Langkah ini mengubah confusion matrix LDA menjadi bentuk data frame lalu
divisualisasikan dalam bentuk heatmap. Grafik ini membantu melihat
seberapa banyak prediksi yang benar dan salah pada tiap kelas cuaca.
Warna yang semakin gelap menunjukkan jumlah prediksi yang semakin
banyak. Jika kotak diagonal lebih gelap dibandingkan kotak lainnya,
berarti model LDA mampu mengklasifikasikan tipe cuaca dengan baik.
# Menentukan kategori referensi
train_data$Weather_Type <- relevel(train_data$Weather_Type, ref = "Sunny")
test_data$Weather_Type <- relevel(test_data$Weather_Type, ref = "Sunny")
# Model Multinomial (TRAIN DATA)
model_mnl <- multinom(Weather_Type ~ Temperature + Humidity + Wind_Speed +
Precipitation + Pressure + UV_Index + Visibility,
data = train_data)
## # weights: 36 (24 variable)
## initial value 557.290333
## iter 10 value 260.784474
## iter 20 value 238.525385
## iter 30 value 231.091207
## final value 231.084163
## converged
summary(model_mnl)
## Call:
## multinom(formula = Weather_Type ~ Temperature + Humidity + Wind_Speed +
## Precipitation + Pressure + UV_Index + Visibility, data = train_data)
##
## Coefficients:
## (Intercept) Temperature Humidity Wind_Speed Precipitation Pressure
## Cloudy 1.5422624 -0.5192758 0.8267203 0.5154053 0.455825 -0.07468248
## Rainy 0.5470788 -0.5900514 1.1875098 1.0917122 2.143685 -0.08177496
## Snowy -1.0097882 -4.0458478 0.9361421 0.7118054 2.323739 -0.44382368
## UV_Index Visibility
## Cloudy -1.733200 0.5576647
## Rainy -2.957430 0.3394850
## Snowy -1.991782 0.5474324
##
## Std. Errors:
## (Intercept) Temperature Humidity Wind_Speed Precipitation Pressure
## Cloudy 0.3250641 0.3011106 0.2888792 0.2996359 0.2904540 0.1674409
## Rainy 0.3795414 0.3625016 0.3764416 0.3337850 0.3937612 0.2657195
## Snowy 0.5180382 0.4666539 0.4209313 0.3678436 0.4721609 0.2539332
## UV_Index Visibility
## Cloudy 0.2727911 0.2297527
## Rainy 0.3766919 0.3030597
## Snowy 0.3495436 0.2903211
##
## Residual Deviance: 462.1683
## AIC: 510.1683
# Menghitung p-value koefisien multinomial
z <- summary(model_mnl)$coefficients / summary(model_mnl)$standard.errors
p_value <- (1 - pnorm(abs(z), 0, 1)) * 2
p_value
## (Intercept) Temperature Humidity Wind_Speed Precipitation Pressure
## Cloudy 2.090350e-06 0.08461126 0.004212155 0.08541330 1.165655e-01 0.65558077
## Rainy 1.494659e-01 0.10358409 0.001607370 0.00107280 5.206064e-08 0.75827319
## Snowy 5.126504e-02 0.00000000 0.026149900 0.05298099 8.588364e-07 0.08049916
## UV_Index Visibility
## Cloudy 2.103604e-10 0.01521422
## Rainy 4.218847e-15 0.26263199
## Snowy 1.210540e-08 0.05934751
# Prediksi ke TEST DATA
pred_mnl <- predict(model_mnl, newdata = test_data)
cm_mnl <- confusionMatrix(pred_mnl, test_data$Weather_Type)
# Confusion Matrix
confusionMatrix(pred_mnl, test_data$Weather_Type)
## Confusion Matrix and Statistics
##
## Reference
## Prediction Sunny Cloudy Rainy Snowy
## Sunny 22 1 1 2
## Cloudy 0 19 2 0
## Rainy 3 2 21 0
## Snowy 1 2 1 21
##
## Overall Statistics
##
## Accuracy : 0.8469
## 95% CI : (0.7601, 0.9117)
## No Information Rate : 0.2653
## P-Value [Acc > NIR] : <2e-16
##
## Kappa : 0.7958
##
## Mcnemar's Test P-Value : 0.5018
##
## Statistics by Class:
##
## Class: Sunny Class: Cloudy Class: Rainy Class: Snowy
## Sensitivity 0.8462 0.7917 0.8400 0.9130
## Specificity 0.9444 0.9730 0.9315 0.9467
## Pos Pred Value 0.8462 0.9048 0.8077 0.8400
## Neg Pred Value 0.9444 0.9351 0.9444 0.9726
## Prevalence 0.2653 0.2449 0.2551 0.2347
## Detection Rate 0.2245 0.1939 0.2143 0.2143
## Detection Prevalence 0.2653 0.2143 0.2653 0.2551
## Balanced Accuracy 0.8953 0.8823 0.8858 0.9299
# Detail performa per kelas Multinomial
confusionMatrix(pred_mnl, test_data$Weather_Type)$byClass
## Sensitivity Specificity Pos Pred Value Neg Pred Value Precision
## Class: Sunny 0.8461538 0.9444444 0.8461538 0.9444444 0.8461538
## Class: Cloudy 0.7916667 0.9729730 0.9047619 0.9350649 0.9047619
## Class: Rainy 0.8400000 0.9315068 0.8076923 0.9444444 0.8076923
## Class: Snowy 0.9130435 0.9466667 0.8400000 0.9726027 0.8400000
## Recall F1 Prevalence Detection Rate
## Class: Sunny 0.8461538 0.8461538 0.2653061 0.2244898
## Class: Cloudy 0.7916667 0.8444444 0.2448980 0.1938776
## Class: Rainy 0.8400000 0.8235294 0.2551020 0.2142857
## Class: Snowy 0.9130435 0.8750000 0.2346939 0.2142857
## Detection Prevalence Balanced Accuracy
## Class: Sunny 0.2653061 0.8952991
## Class: Cloudy 0.2142857 0.8823198
## Class: Rainy 0.2653061 0.8857534
## Class: Snowy 0.2551020 0.9298551
# Akurasi Multinomial
acc_mnl <- mean(pred_mnl == test_data$Weather_Type)
acc_mnl
## [1] 0.8469388
Pada tahap ini, kategori Summary ditetapkan sebagai kelas referensi sehingga seluruh jenis cuaca lainnya dibandingkan terhadap kondisi cuaca cerah. Selanjutnya dibangun model regresi logistik multinomial menggunakan variabel meteorologi seperti suhu, kelembapan, kecepatan angin, presipitasi, tekanan, UV index, dan visibilitas untuk memprediksi jenis cuaca. Hasil ringkasan model digunakan untuk melihat nilai koefisien serta p-value guna mengetahui seberapa besar dan signifikan pengaruh setiap variabel terhadap peluang munculnya masing-masing tipe cuaca. Setelah model terbentuk, dilakukan prediksi pada data uji untuk menilai kemampuan generalisasi model. Kinerja model kemudian dievaluasi menggunakan confusion matrix dan metrik performa per kelas, sehingga dapat diketahui seberapa baik model mengklasifikasikan tiap jenis cuaca. Terakhir, nilai akurasi dihitung untuk menunjukkan persentase keseluruhan prediksi yang berhasil dilakukan dengan benar oleh model.
# Memastikan objek cm_mnl sudah tersedia
cm_mnl <- confusionMatrix(pred_mnl, test_data$Weather_Type)
# Visualisasi 7: Heatmap Confusion Matrix Multinomial
cm_mnl_df <- as.data.frame(cm_mnl$table)
ggplot(cm_mnl_df, aes(Reference, Prediction, fill = Freq)) +
geom_tile() +
geom_text(aes(label = Freq), color = "white") +
scale_fill_gradient(low = "lightgreen", high = "darkgreen") +
theme_minimal() +
labs(title = "Heatmap Confusion Matrix - Multinomial",
x = "Data Aktual (Reference)",
y = "Data Prediksi (Prediction)")
Heatmap menampilkan confusion matrix model multinomial dalam bentuk
visual. Warna hijau yang semakin gelap menunjukkan jumlah prediksi yang
lebih banyak. Kotak diagonal menandakan prediksi yang benar, sedangkan
kotak di luar diagonal menunjukkan kesalahan klasifikasi. Semakin
dominan warna pada diagonal, semakin baik performa model.
# Visualisasi 8: Kontribusi Variabel LDA
lda_scaling <- as.data.frame(model_lda$scaling)
lda_scaling$Variable <- rownames(lda_scaling)
ggplot(lda_scaling, aes(x = reorder(Variable, LD1), y = LD1)) +
geom_bar(stat = "identity", fill = "steelblue") +
coord_flip() +
theme_minimal() +
labs(title = "Kontribusi Variabel terhadap LD1",
x = "Variabel", y = "Koefisien LD1")
Visualisasi ini menunjukkan kontribusi setiap variabel terhadap fungsi
diskriminan pertama (LD1) pada model LDA. Semakin besar nilai koefisien
suatu variabel, semakin besar perannya dalam membedakan tipe cuaca.
Variabel dengan batang paling panjang berarti paling berpengaruh dalam
proses klasifikasi, sedangkan variabel dengan nilai kecil memiliki
pengaruh yang lebih rendah terhadap pemisahan kelas.
| Metode Analisis | Akurasi (%) | Akurasi (Proporsi) | Indeks Kappa |
|---|---|---|---|
| Analisis Diskriminan (LDA) | 80.61 % | 0.8061 | 0.7416 |
| Regresi Logistik Multinomial | 84.69 % | 0.8469 | 0.7958 |
Ringkasan Hasil Analisis
Berdasarkan seluruh tahapan analisis yang telah dilakukan, mulai dari eksplorasi data, pengujian asumsi, hingga evaluasi model, berikut adalah poin-poin kesimpulannya:
- Metode Regresi Logistik Multinomial menunjukkan performa yang lebih unggul dibandingkan Analisis Diskriminan Linier (LDA). Hal ini dibuktikan dengan nilai Akurasi sebesar 84.69% dan Indeks Kappa sebesar 0.7958.
- Model mampu membedakan tipe cuaca ekstrem (seperti Snowy) dengan sangat baik karena adanya perbedaan variabel suhu dan kelembapan yang signifikan.
- Untuk dataset cuaca dengan karakteristik non-linear atau yang tidak sepenuhnya memenuhi asumsi normalitas multivariat, penggunaan Regresi Logistik Multinomial lebih disarankan karena sifatnya yang lebih fleksibel (robust).
Laporan ini disusun sebagai bagian dari pemenuhan tugas praktikum mata kuliah Analisis Multivariat - Sains Data Universitas Negeri Surabaya.