# Install & load package (kalau belum terpasang)
if (!require(readxl)) install.packages("readxl"); library(readxl)
## Loading required package: readxl
## Warning: package 'readxl' was built under R version 4.5.1
if (!require(dplyr)) install.packages("dplyr"); library(dplyr)
## Loading required package: dplyr
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
if (!require(psych)) install.packages("psych"); library(psych)
## Loading required package: psych
## Warning: package 'psych' was built under R version 4.5.1
# Import file Excel
data <- read_excel("C:/SEMESTER 5/STATISTIKA LINGKUNGAN/kualitasair.xlsx")
Langkah pertama adalah memuat paket yang dibutuhkan dan membaca dataset kualitasair.xlsx.Dataset ini berisi parameter kualitas air seperti pH, DO, BOD, TSS, dan Suhu beserta kategori status air.
# Melihat struktur data dan ringkasan awal
str(data)
## tibble [300 × 7] (S3: tbl_df/tbl/data.frame)
## $ Lokasi: chr [1:300] "S1" "S2" "S3" "S4" ...
## $ pH : num [1:300] 7.69 6.72 7.18 7.32 7.2 ...
## $ DO : num [1:300] NA 5.72 4.89 6.13 7.79 ...
## $ BOD : num [1:300] 1.71 1.44 2.73 3.14 1.18 ...
## $ TSS : num [1:300] 43.1 44.3 NA 41 48.1 ...
## $ Suhu : num [1:300] 26.8 27.7 26 29.7 26.4 ...
## $ Status: chr [1:300] "Tercemar ringan" "Tercemar ringan" "Tercemar ringan" "Tercemar ringan" ...
summary(data)
## Lokasi pH DO BOD
## Length:300 Min. :5.503 Min. :2.982 Min. :0.3026
## Class :character 1st Qu.:6.670 1st Qu.:5.375 1st Qu.:2.3573
## Mode :character Median :6.988 Median :5.991 Median :3.0661
## Mean :6.989 Mean :5.976 Mean :3.0005
## 3rd Qu.:7.318 3rd Qu.:6.688 3rd Qu.:3.5781
## Max. :8.351 Max. :9.229 Max. :5.7962
## NA's :23 NA's :22
## TSS Suhu Status
## Min. :24.65 Min. :22.77 Length:300
## 1st Qu.:43.73 1st Qu.:26.62 Class :character
## Median :49.52 Median :28.01 Mode :character
## Mean :49.70 Mean :28.31
## 3rd Qu.:56.44 3rd Qu.:29.46
## Max. :76.34 Max. :90.00
## NA's :24
Tahap ini digunakan untuk mengenali tipe data setiap kolom (numerik/kategorik) dan melihat ringkasan statistik awal, seperti nilai minimum, maksimum, dan jumlah data hilang.
# Mengecek jumlah nilai yang hilang di setiap kolom
colSums(is.na(data))
## Lokasi pH DO BOD TSS Suhu Status
## 0 0 23 22 24 0 0
Langkah ini memastikan apakah ada nilai NA yang perlu diimputasi sebelum analisis lebih lanjut.
# Imputasi nilai hilang pada variabel numerik dengan median
num_col <- c("pH", "DO", "BOD", "TSS", "Suhu")
for (col in num_col) {
data[[col]][is.na(data[[col]])] <- median(data[[col]], na.rm = TRUE)
}
Median dipilih karena lebih stabil terhadap outlier dibandingkan mean, sehingga hasil imputasi tidak bias.
# Deteksi dan tandai outlier menggunakan IQR
for (col in num_col) {
Q1 <- quantile(data[[col]], 0.25, na.rm = TRUE)
Q3 <- quantile(data[[col]], 0.75, na.rm = TRUE)
IQR <- Q3 - Q1
batas_bawah <- Q1 - 1.5 * IQR
batas_atas <- Q3 + 1.5 * IQR
# Ganti outlier dengan NA
data[[col]][data[[col]] < batas_bawah | data[[col]] > batas_atas] <- NA
}
Metode IQR digunakan untuk mendeteksi nilai ekstrem tanpa harus menghapus data, menjaga keutuhan dataset.
# Mengganti outlier yang jadi NA dengan median baru
for (col in num_col) {
data[[col]][is.na(data[[col]])] <- median(data[[col]], na.rm = TRUE)
}
Nilai ekstrem yang dianggap tidak wajar diisi ulang dengan median agar tidak memengaruhi analisis statistik berikutnya.
# Standarisasi tulisan kategori status
data$Status <- tolower(data$Status)
data$Status <- gsub("baik|1", "Baik", data$Status)
data$Status <- gsub("tercemar ringan|2", "Tercemar ringan", data$Status)
data$Status <- gsub("tercemar berat|3", "Tercemar berat", data$Status)
# Ubah menjadi faktor
data$Status <- factor(data$Status,
levels = c("Baik", "Tercemar ringan", "Tercemar berat"))
Langkah ini menyamakan variasi penulisan agar kategori status air terbaca seragam oleh model klasifikasi.
# Cek hasil akhir setelah pembersihan
summary(data)
## Lokasi pH DO BOD
## Length:300 Min. :5.780 Min. :3.811 Min. :0.8993
## Class :character 1st Qu.:6.690 1st Qu.:5.425 1st Qu.:2.4712
## Mode :character Median :6.992 Median :5.991 Median :3.0661
## Mean :6.998 Mean :5.977 Mean :2.9981
## 3rd Qu.:7.317 3rd Qu.:6.598 3rd Qu.:3.5093
## Max. :8.230 Max. :8.242 Max. :5.0988
## TSS Suhu Status
## Min. :27.73 Min. :22.77 Baik : 72
## 1st Qu.:44.51 1st Qu.:26.62 Tercemar ringan:221
## Median :49.52 Median :28.00 Tercemar berat : 7
## Mean :49.75 Mean :28.08
## 3rd Qu.:55.13 3rd Qu.:29.43
## Max. :72.41 Max. :33.40
describe(data[num_col])
## vars n mean sd median trimmed mad min max range skew kurtosis
## pH 1 300 7.00 0.47 6.99 7.00 0.47 5.78 8.23 2.45 0.04 -0.29
## DO 2 300 5.98 0.90 5.99 5.99 0.87 3.81 8.24 4.43 -0.13 -0.20
## BOD 3 300 3.00 0.75 3.07 3.00 0.76 0.90 5.10 4.20 -0.12 -0.04
## TSS 4 300 49.75 8.65 49.52 49.79 7.80 27.73 72.41 44.69 -0.01 -0.10
## Suhu 5 300 28.08 2.01 28.00 28.07 2.10 22.77 33.40 10.62 0.06 -0.24
## se
## pH 0.03
## DO 0.05
## BOD 0.04
## TSS 0.50
## Suhu 0.12
Setelah pembersihan, dataset kini bersih tanpa missing value dan outlier ekstrem.
Hasil Akhir Setelah pembersihan data, seluruh nilai hilang dan outlier berhasil ditangani dengan imputasi median. Nilai pH berkisar 5,78–8,23 (umumnya netral), DO rata-rata 5,98 mg/L menunjukkan oksigen terlarut masih cukup, dan BOD rata-rata 3,0 mg/L menandakan kadar bahan organik masih aman. Sebagian besar sampel berstatus “Tercemar ringan”, sedangkan sisanya “Baik” dan sedikit “Tercemar berat.” Secara umum, kondisi kualitas air tergolong cukup baik.
# Install dan load library yang dibutuhkan
if (!require(caret)) install.packages("caret"); library(caret)
## Loading required package: caret
## Warning: package 'caret' was built under R version 4.5.1
## Loading required package: ggplot2
##
## Attaching package: 'ggplot2'
## The following objects are masked from 'package:psych':
##
## %+%, alpha
## Loading required package: lattice
if (!require(e1071)) install.packages("e1071"); library(e1071)
## Loading required package: e1071
## Warning: package 'e1071' was built under R version 4.5.1
if (!require(rpart)) install.packages("rpart"); library(rpart)
## Loading required package: rpart
if (!require(rpart.plot)) install.packages("rpart.plot"); library(rpart.plot)
## Loading required package: rpart.plot
## Warning: package 'rpart.plot' was built under R version 4.5.1
if (!require(randomForest)) install.packages("randomForest"); library(randomForest)
## Loading required package: randomForest
## Warning: package 'randomForest' was built under R version 4.5.1
## randomForest 4.7-1.2
## Type rfNews() to see new features/changes/bug fixes.
##
## Attaching package: 'randomForest'
## The following object is masked from 'package:ggplot2':
##
## margin
## The following object is masked from 'package:psych':
##
## outlier
## The following object is masked from 'package:dplyr':
##
## combine
set.seed(123) # agar hasil konsisten
# Bagi data menjadi training (80%) dan testing (20%)
trainIndex <- createDataPartition(data$Status, p = 0.8, list = FALSE)
trainData <- data[trainIndex, ]
testData <- data[-trainIndex, ]
dim(trainData); dim(testData)
## [1] 241 7
## [1] 59 7
Data dibagi menjadi 80% untuk melatih model dan 20% untuk menguji performanya, agar hasil evaluasi lebih objektif.
# Model SVM dengan kernel radial
svm_model <- svm(Status ~ pH + DO + BOD + TSS + Suhu,
data = trainData, kernel = "radial")
# Prediksi dan evaluasi
svm_pred <- predict(svm_model, testData)
svm_conf <- confusionMatrix(svm_pred, testData$Status)
svm_conf
## Confusion Matrix and Statistics
##
## Reference
## Prediction Baik Tercemar ringan Tercemar berat
## Baik 9 1 0
## Tercemar ringan 5 43 1
## Tercemar berat 0 0 0
##
## Overall Statistics
##
## Accuracy : 0.8814
## 95% CI : (0.7707, 0.9509)
## No Information Rate : 0.7458
## P-Value [Acc > NIR] : 0.008645
##
## Kappa : 0.6515
##
## Mcnemar's Test P-Value : NA
##
## Statistics by Class:
##
## Class: Baik Class: Tercemar ringan Class: Tercemar berat
## Sensitivity 0.6429 0.9773 0.00000
## Specificity 0.9778 0.6000 1.00000
## Pos Pred Value 0.9000 0.8776 NaN
## Neg Pred Value 0.8980 0.9000 0.98305
## Prevalence 0.2373 0.7458 0.01695
## Detection Rate 0.1525 0.7288 0.00000
## Detection Prevalence 0.1695 0.8305 0.00000
## Balanced Accuracy 0.8103 0.7886 0.50000
SVM digunakan karena mampu menangkap hubungan non-linear antar variabel.
# Bangun model pohon keputusan
tree_model <- rpart(Status ~ pH + DO + BOD + TSS + Suhu,
data = trainData, method = "class")
# Visualisasi pohon
rpart.plot(tree_model, type = 2, extra = 104, cex = 0.8, main = "Pohon Keputusan")
# Prediksi dan evaluasi
tree_pred <- predict(tree_model, testData, type = "class")
tree_conf <- confusionMatrix(tree_pred, testData$Status)
tree_conf
## Confusion Matrix and Statistics
##
## Reference
## Prediction Baik Tercemar ringan Tercemar berat
## Baik 13 0 1
## Tercemar ringan 1 44 0
## Tercemar berat 0 0 0
##
## Overall Statistics
##
## Accuracy : 0.9661
## 95% CI : (0.8829, 0.9959)
## No Information Rate : 0.7458
## P-Value [Acc > NIR] : 6.696e-06
##
## Kappa : 0.9096
##
## Mcnemar's Test P-Value : NA
##
## Statistics by Class:
##
## Class: Baik Class: Tercemar ringan Class: Tercemar berat
## Sensitivity 0.9286 1.0000 0.00000
## Specificity 0.9778 0.9333 1.00000
## Pos Pred Value 0.9286 0.9778 NaN
## Neg Pred Value 0.9778 1.0000 0.98305
## Prevalence 0.2373 0.7458 0.01695
## Detection Rate 0.2203 0.7458 0.00000
## Detection Prevalence 0.2373 0.7627 0.00000
## Balanced Accuracy 0.9532 0.9667 0.50000
Decision Tree mudah diinterpretasi karena menghasilkan aturan klasifikasi berupa cabang logis berdasarkan nilai parameter air. Model pohon keputusan ini efektif dan mudah diinterpretasi, dengan hasil menunjukkan bahwa kadar DO dan BOD merupakan penentu utama status kualitas air.
# Bangun model Random Forest
set.seed(123)
rf_model <- randomForest(Status ~ pH + DO + BOD + TSS + Suhu,
data = trainData, ntree = 500, mtry = 3, importance = TRUE)
# Prediksi dan evaluasi
rf_pred <- predict(rf_model, testData)
rf_conf <- confusionMatrix(rf_pred, testData$Status)
rf_conf
## Confusion Matrix and Statistics
##
## Reference
## Prediction Baik Tercemar ringan Tercemar berat
## Baik 13 0 1
## Tercemar ringan 1 44 0
## Tercemar berat 0 0 0
##
## Overall Statistics
##
## Accuracy : 0.9661
## 95% CI : (0.8829, 0.9959)
## No Information Rate : 0.7458
## P-Value [Acc > NIR] : 6.696e-06
##
## Kappa : 0.9096
##
## Mcnemar's Test P-Value : NA
##
## Statistics by Class:
##
## Class: Baik Class: Tercemar ringan Class: Tercemar berat
## Sensitivity 0.9286 1.0000 0.00000
## Specificity 0.9778 0.9333 1.00000
## Pos Pred Value 0.9286 0.9778 NaN
## Neg Pred Value 0.9778 1.0000 0.98305
## Prevalence 0.2373 0.7458 0.01695
## Detection Rate 0.2203 0.7458 0.00000
## Detection Prevalence 0.2373 0.7627 0.00000
## Balanced Accuracy 0.9532 0.9667 0.50000
# Cek variabel paling penting
importance(rf_model)
## Baik Tercemar ringan Tercemar berat MeanDecreaseAccuracy
## pH -1.870894 -1.947077 0.7192570 -2.638631
## DO 71.781677 69.656547 6.5540615 86.735854
## BOD 74.429637 65.673882 2.7609224 85.104875
## TSS -1.570659 1.718986 0.6040976 0.552901
## Suhu -2.768718 -2.415967 -2.6730971 -3.901362
## MeanDecreaseGini
## pH 3.528891
## DO 42.704410
## BOD 38.982770
## TSS 5.710166
## Suhu 5.097049
varImpPlot(rf_model, main = "Pentingnya Variabel pada Random Forest")
Random Forest menggabungkan banyak pohon keputusan untuk meningkatkan
akurasi dan mengurangi risiko overfitting. Model klasifikasi menunjukkan
akurasi tinggi (96,6%) dengan DO dan BOD sebagai faktor paling
berpengaruh. Air dengan DO ≥ 6 dan BOD < 3,1 tergolong Baik,
sedangkan DO < 6 menunjukkan Tercemar ringan. Secara keseluruhan,
model sangat akurat dan mudah diinterpretasi.
svm_acc <- svm_conf$overall["Accuracy"]
tree_acc <- tree_conf$overall["Accuracy"]
rf_acc <- rf_conf$overall["Accuracy"]
accuracy_table <- data.frame(
Model = c("SVM", "Decision Tree", "Random Forest"),
Akurasi = c(svm_acc, tree_acc, rf_acc)
)
accuracy_table
## Model Akurasi
## 1 SVM 0.8813559
## 2 Decision Tree 0.9661017
## 3 Random Forest 0.9661017
Tabel ini menunjukkan perbandingan tingkat akurasi dari ketiga model klasifikasi yang digunakan.
library(ggplot2)
ggplot(accuracy_table, aes(x = Model, y = Akurasi, fill = Model)) +
geom_col() +
geom_text(aes(label = round(Akurasi, 3)), vjust = -0.5) +
labs(title = "Perbandingan Akurasi Model Klasifikasi",
x = "Model", y = "Akurasi") +
theme_minimal()
Grafik ini membantu membandingkan performa model secara visual dan
menegaskan model mana yang paling akurat.Grafik menunjukkan bahwa
Decision Tree dan Random Forest memiliki akurasi tertinggi sebesar
0,966, sedangkan SVM sedikit lebih rendah yaitu 0,881. Ini menegaskan
bahwa model berbasis pohon keputusan lebih stabil dan akurat dalam
mengklasifikasikan kualitas air dibandingkan SVM.
Hasil Akhir Model Decision Tree dan Random Forest menunjukkan akurasi tertinggi, masing-masing sekitar 96,6%, sedangkan SVM memperoleh akurasi sekitar 88,1%. Ini berarti model berbasis pohon lebih mampu mengenali pola data kualitas air dibandingkan SVM. Parameter yang paling berpengaruh dalam menentukan status air adalah DO dan BOD, karena keduanya berkaitan langsung dengan tingkat pencemaran organik.
# Model regresi linier untuk memprediksi DO
model_DO <- lm(DO ~ pH + BOD + TSS + Suhu, data = data)
# Lihat ringkasan model
summary(model_DO)
##
## Call:
## lm(formula = DO ~ pH + BOD + TSS + Suhu, data = data)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.18608 -0.54471 0.00143 0.64989 2.36707
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 5.974540 1.177524 5.074 6.91e-07 ***
## pH 0.023785 0.112810 0.211 0.833
## BOD 0.009364 0.070576 0.133 0.895
## TSS 0.005725 0.006073 0.943 0.347
## Suhu -0.016992 0.026184 -0.649 0.517
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.908 on 295 degrees of freedom
## Multiple R-squared: 0.004674, Adjusted R-squared: -0.008821
## F-statistic: 0.3464 on 4 and 295 DF, p-value: 0.8465
Model ini digunakan untuk melihat pengaruh variabel pH, BOD, TSS, dan Suhu terhadap kadar DO (oksigen terlarut) dalam air. Output summary() memberikan informasi koefisien, nilai R², dan signifikansi tiap variabel.
# Uji normalitas residual
res <- residuals(model_DO)
shapiro.test(res)
##
## Shapiro-Wilk normality test
##
## data: res
## W = 0.98999, p-value = 0.03775
# Uji multikolinearitas
if (!require(car)) install.packages("car"); library(car)
## Loading required package: car
## Warning: package 'car' was built under R version 4.5.1
## Loading required package: carData
## Warning: package 'carData' was built under R version 4.5.1
##
## Attaching package: 'car'
## The following object is masked from 'package:psych':
##
## logit
## The following object is masked from 'package:dplyr':
##
## recode
vif(model_DO)
## pH BOD TSS Suhu
## 1.007026 1.005883 1.000579 1.007686
Uji Shapiro-Wilk digunakan untuk memeriksa apakah residual berdistribusi normal.Nilai VIF (< 10) menunjukkan tidak terjadi multikolinearitas antar variabel bebas.Uji Shapiro–Wilk (p = 0.02676) menunjukkan residual tidak sepenuhnya normal, namun masih dapat diterima karena jumlah data besar. Nilai VIF ≈ 1 menandakan tidak ada multikolinearitas, sehingga model layak digunakan.
par(mfrow = c(2,2))
plot(model_DO)
Plot diagnostik digunakan untuk mengecek pola residual, mendeteksi
outlier, dan memverifikasi kesesuaian model linier.Secara keseluruhan,
model regresi masih layak digunakan meskipun asumsi normalitas sedikit
menyimpang.
data$Prediksi_DO <- predict(model_DO)
library(ggplot2)
ggplot(data, aes(x = DO, y = Prediksi_DO)) +
geom_point(color = "black", size = 2) +
geom_abline(intercept = 0, slope = 1, color = "red", linetype = "dashed") +
labs(title = "Perbandingan DO Aktual vs Prediksi",
x = "DO Aktual", y = "DO Prediksi") +
theme_minimal()
Plot ini membandingkan nilai aktual DO dengan hasil prediksi model.
Semakin mendekati garis merah (45°), semakin baik kemampuan model dalam
memperkirakan nilai DO.
if (!require(Metrics)) install.packages("Metrics"); library(Metrics)
## Loading required package: Metrics
## Warning: package 'Metrics' was built under R version 4.5.1
##
## Attaching package: 'Metrics'
## The following objects are masked from 'package:caret':
##
## precision, recall
rmse(data$DO, data$Prediksi_DO)
## [1] 0.9004047
Nilai RMSE (Root Mean Square Error) menunjukkan tingkat kesalahan prediksi model. Semakin kecil nilainya, semakin baik model regresi.
Hasil Akhir Model regresi menunjukkan bahwa variabel pH, BOD, TSS, dan Suhu tidak berpengaruh signifikan terhadap DO (p-value > 0,05) dengan nilai R² yang rendah. Artinya, perubahan kadar oksigen terlarut lebih dipengaruhi oleh faktor lain di luar empat variabel tersebut. Meskipun demikian, model masih memberikan gambaran umum hubungan arah pengaruh antarparameter kualitas air.
# Ambil 75 baris terakhir dari dataset
test75 <- tail(data, 75)
Langkah ini mengambil sebagian data paling akhir untuk dijadikan sampel prediksi, agar model diuji pada data yang belum dievaluasi sebelumnya.
# Prediksi kadar DO menggunakan model regresi
test75$Pred_DO <- predict(model_DO, test75)
# Prediksi status kualitas air menggunakan model Random Forest dari nomor 2
test75$Pred_Status <- predict(rf_model, test75)
Kolom Pred_DO berisi hasil prediksi kadar oksigen terlarut (DO) dari model regresi linier, sedangkan Pred_Status berisi hasil klasifikasi kualitas air dari model Random Forest.
if (!require(knitr)) install.packages("knitr"); library(knitr)
## Loading required package: knitr
kable(
test75[, c("pH", "BOD", "TSS", "Suhu", "DO", "Pred_DO", "Status", "Pred_Status")],
caption = "Tabel Prediksi Kadar DO dan Status Kualitas Air (75 Data Terakhir)"
)
| pH | BOD | TSS | Suhu | DO | Pred_DO | Status | Pred_Status |
|---|---|---|---|---|---|---|---|
| 6.91300 | 3.4263 | 45.95360 | 26.4897 | 5.7515 | 5.984035 | Tercemar ringan | Tercemar ringan |
| 7.25780 | 3.5757 | 48.54230 | 27.0170 | 6.4223 | 5.999496 | Tercemar ringan | Tercemar ringan |
| 6.88280 | 3.4481 | 57.19470 | 28.2945 | 5.9909 | 6.017212 | Tercemar ringan | Tercemar ringan |
| 6.67070 | 2.9855 | 45.08910 | 32.7130 | 6.8356 | 5.863449 | Baik | Baik |
| 7.62510 | 3.0661 | 54.75960 | 26.1587 | 5.3395 | 6.053640 | Tercemar ringan | Tercemar ringan |
| 6.86410 | 3.6086 | 55.73150 | 23.6863 | 7.5641 | 6.088195 | Tercemar ringan | Tercemar ringan |
| 7.47400 | 2.6870 | 39.81140 | 27.7592 | 4.3770 | 5.933718 | Tercemar ringan | Tercemar ringan |
| 6.39920 | 3.8079 | 49.38130 | 26.3215 | 6.8639 | 5.997870 | Tercemar ringan | Tercemar ringan |
| 6.76690 | 2.4984 | 44.61690 | 23.6551 | 5.4884 | 6.012383 | Tercemar ringan | Tercemar ringan |
| 6.86530 | 1.6923 | 49.52205 | 26.2514 | 5.9909 | 5.991143 | Tercemar ringan | Tercemar ringan |
| 6.80450 | 3.9962 | 34.91720 | 27.2528 | 4.1342 | 5.910637 | Tercemar ringan | Tercemar ringan |
| 7.67440 | 3.1451 | 65.39170 | 25.7956 | 6.2452 | 6.122594 | Tercemar ringan | Tercemar ringan |
| 6.98860 | 3.0661 | 63.46020 | 29.4313 | 8.2235 | 6.032707 | Tercemar berat | Baik |
| 7.12210 | 3.7325 | 41.57140 | 29.8153 | 6.2734 | 5.910278 | Tercemar ringan | Tercemar ringan |
| 6.52880 | 3.8388 | 43.30130 | 27.3504 | 7.1308 | 5.948949 | Tercemar ringan | Tercemar ringan |
| 6.63540 | 3.6111 | 40.91510 | 25.0368 | 6.8387 | 5.975003 | Tercemar ringan | Tercemar ringan |
| 7.49900 | 2.5173 | 48.63460 | 29.1883 | 5.3454 | 5.958956 | Tercemar ringan | Tercemar ringan |
| 7.62920 | 2.7037 | 44.98960 | 26.2903 | 6.9540 | 5.992172 | Baik | Baik |
| 7.62440 | 3.0661 | 51.12640 | 26.3402 | 5.9909 | 6.029738 | Tercemar ringan | Tercemar ringan |
| 6.30970 | 3.8441 | 31.24780 | 28.2982 | 6.2066 | 5.858673 | Tercemar ringan | Tercemar ringan |
| 8.02500 | 3.4664 | 51.58550 | 26.0477 | 7.0011 | 6.050613 | Tercemar ringan | Tercemar ringan |
| 7.50840 | 2.2107 | 50.15560 | 27.4106 | 6.7475 | 5.995223 | Baik | Baik |
| 6.98660 | 4.3477 | 33.99400 | 26.4581 | 5.3734 | 5.926478 | Tercemar ringan | Tercemar ringan |
| 7.35180 | 1.9065 | 52.75970 | 28.7846 | 6.3952 | 5.980212 | Baik | Baik |
| 6.51430 | 2.6534 | 49.52205 | 26.3074 | 5.1078 | 5.990842 | Tercemar ringan | Tercemar ringan |
| 6.45190 | 4.8600 | 47.69430 | 26.3125 | 6.6308 | 5.999470 | Tercemar ringan | Tercemar ringan |
| 7.02450 | 3.4193 | 49.86780 | 26.0762 | 5.5673 | 6.016057 | Tercemar ringan | Tercemar ringan |
| 6.40080 | 3.7766 | 53.84950 | 28.0221 | 6.4521 | 5.994300 | Tercemar ringan | Tercemar ringan |
| 7.09500 | 3.3016 | 53.46720 | 30.4299 | 6.3680 | 5.963262 | Tercemar ringan | Tercemar ringan |
| 7.64890 | 2.2033 | 45.68390 | 26.2222 | 5.7296 | 5.993087 | Tercemar ringan | Tercemar ringan |
| 6.48310 | 2.5220 | 61.50180 | 28.4362 | 6.4655 | 6.021285 | Baik | Baik |
| 6.63080 | 3.1322 | 49.63470 | 26.6878 | 6.5744 | 5.992278 | Tercemar ringan | Tercemar ringan |
| 7.02330 | 3.0661 | 48.64200 | 25.8230 | 5.9909 | 6.010006 | Tercemar ringan | Tercemar ringan |
| 6.49120 | 2.3217 | 59.44620 | 30.1823 | 5.9909 | 5.978164 | Baik | Baik |
| 6.80840 | 3.6389 | 59.92040 | 26.8615 | 7.3927 | 6.057184 | Tercemar ringan | Tercemar ringan |
| 7.43640 | 2.7612 | 42.99330 | 31.2416 | 5.3380 | 5.892563 | Tercemar ringan | Tercemar ringan |
| 7.48480 | 2.7731 | 40.08940 | 26.6260 | 5.2226 | 5.955628 | Tercemar ringan | Tercemar ringan |
| 7.19190 | 3.6956 | 42.94380 | 29.3140 | 6.5135 | 5.927968 | Tercemar ringan | Tercemar ringan |
| 6.07420 | 2.5645 | 38.24220 | 30.2214 | 5.0867 | 5.848456 | Tercemar ringan | Tercemar ringan |
| 6.97300 | 3.5030 | 32.18800 | 32.2814 | 5.5506 | 5.808956 | Tercemar ringan | Tercemar ringan |
| 7.53240 | 1.8621 | 49.52205 | 26.3381 | 6.8029 | 6.007126 | Baik | Baik |
| 7.40660 | 2.0180 | 48.54890 | 28.1528 | 5.4265 | 5.969187 | Tercemar ringan | Tercemar ringan |
| 6.90460 | 1.6607 | 56.42550 | 29.8716 | 4.0719 | 5.969792 | Tercemar ringan | Tercemar ringan |
| 6.99235 | 3.0675 | 49.98340 | 26.9967 | 6.6644 | 5.997019 | Tercemar ringan | Tercemar ringan |
| 7.03050 | 2.8351 | 54.09160 | 29.1897 | 4.3975 | 5.982008 | Tercemar ringan | Tercemar ringan |
| 7.28690 | 4.1535 | 45.03940 | 27.1387 | 4.6454 | 5.983475 | Tercemar ringan | Tercemar ringan |
| 7.02290 | 3.0661 | 40.39890 | 25.7333 | 5.9909 | 5.964326 | Tercemar berat | Tercemar berat |
| 7.07870 | 4.0830 | 57.78130 | 23.5257 | 6.8312 | 6.112206 | Tercemar ringan | Tercemar ringan |
| 7.21580 | 4.5562 | 57.61120 | 29.0293 | 6.2511 | 6.025408 | Tercemar ringan | Tercemar ringan |
| 6.80170 | 2.6072 | 32.66290 | 27.3162 | 6.4623 | 5.883580 | Baik | Baik |
| 7.65500 | 3.3108 | 58.77290 | 31.4358 | 6.8448 | 5.989952 | Tercemar ringan | Tercemar ringan |
| 7.23520 | 2.3241 | 32.26630 | 25.7672 | 5.9909 | 5.915290 | Tercemar ringan | Tercemar ringan |
| 6.37870 | 3.5904 | 49.54310 | 27.0230 | 4.8944 | 5.984352 | Tercemar ringan | Tercemar ringan |
| 7.69080 | 2.1362 | 46.05130 | 29.6147 | 6.5638 | 5.937914 | Baik | Baik |
| 7.60220 | 2.1788 | 48.71940 | 27.4780 | 5.9909 | 5.987787 | Baik | Tercemar ringan |
| 7.41200 | 3.2310 | 60.96240 | 28.9761 | 4.4998 | 6.037756 | Tercemar ringan | Tercemar ringan |
| 6.16870 | 3.0726 | 37.44780 | 30.7056 | 5.3930 | 5.842685 | Tercemar ringan | Tercemar ringan |
| 6.71530 | 3.2101 | 47.34520 | 32.3536 | 5.7078 | 5.885637 | Tercemar ringan | Tercemar ringan |
| 7.31780 | 3.0555 | 49.52205 | 28.1028 | 4.7103 | 5.983211 | Tercemar ringan | Tercemar ringan |
| 7.02190 | 2.5771 | 49.52205 | 26.3238 | 6.6941 | 6.001922 | Baik | Baik |
| 7.17400 | 2.8958 | 43.73410 | 25.8308 | 5.4008 | 5.983764 | Tercemar ringan | Tercemar ringan |
| 8.22980 | 4.2961 | 49.58950 | 26.9069 | 7.2569 | 6.037227 | Tercemar ringan | Tercemar ringan |
| 6.59080 | 3.0661 | 51.99950 | 27.1470 | 6.0535 | 5.996444 | Baik | Baik |
| 5.94340 | 1.9452 | 49.52205 | 25.5780 | 6.7281 | 5.983026 | Baik | Baik |
| 7.13680 | 2.3244 | 47.33970 | 29.1956 | 7.5611 | 5.940997 | Baik | Baik |
| 6.65620 | 2.1185 | 60.84150 | 30.8478 | 6.2656 | 5.976866 | Baik | Baik |
| 7.22300 | 2.2799 | 48.19250 | 27.1134 | 7.0767 | 5.982894 | Baik | Baik |
| 6.59380 | 1.9911 | 52.51560 | 25.9193 | 6.2107 | 6.010265 | Baik | Baik |
| 8.10600 | 0.8993 | 53.69540 | 25.4522 | 4.4883 | 6.050700 | Tercemar ringan | Tercemar ringan |
| 6.93810 | 3.5353 | 54.07030 | 29.5403 | 6.0224 | 5.980287 | Tercemar ringan | Tercemar ringan |
| 6.76130 | 3.5280 | 54.92510 | 28.0630 | 6.7181 | 6.006010 | Tercemar ringan | Tercemar ringan |
| 6.91690 | 2.7995 | 49.52205 | 24.1903 | 6.4895 | 6.037760 | Baik | Baik |
| 7.43130 | 2.4210 | 42.91330 | 27.7525 | 5.8261 | 5.948085 | Tercemar ringan | Tercemar ringan |
| 7.04870 | 2.3503 | 49.41730 | 28.0007 | 4.7823 | 5.971343 | Tercemar ringan | Tercemar ringan |
| 6.18720 | 3.3190 | 40.36580 | 26.3124 | 6.6464 | 5.936788 | Tercemar ringan | Tercemar ringan |
Tabel ini menampilkan perbandingan antara nilai aktual dan hasil prediksi untuk kadar DO dan status air.Jika nilai prediksi mendekati nilai aktual, berarti model bekerja dengan baik dalam memperkirakan kondisi kualitas air.
library(ggplot2)
ggplot(test75, aes(x = DO, y = Pred_DO)) +
geom_point(color = "skyblue", size = 2) +
geom_abline(intercept = 0, slope = 1, color = "red", linetype = "dashed") +
labs(
title = "Perbandingan DO Aktual dan Hasil Prediksi (75 Data Terakhir)",
x = "DO Aktual",
y = "DO Prediksi"
) +
theme_minimal()
Sebagian besar titik berada di sekitar garis diagonal, menandakan hasil
prediksi cukup mendekati nilai aktual. Hal ini menunjukkan bahwa model
regresi masih dapat digunakan untuk estimasi kadar DO, meskipun tidak
sepenuhnya presisi.
Prediksi
# Ambil 75 data terakhir dari dataset asli
test75 <- tail(data, 75)
# Prediksi SVM
svm_pred75 <- predict(svm_model, test75)
# Prediksi Decision Tree
tree_pred75 <- predict(tree_model, test75, type = "class")
# Prediksi Random Forest
rf_pred75 <- predict(rf_model, test75)
# Gabungkan hasil prediksi ke masing-masing data frame
svm_result75 <- data.frame(
pH = test75$pH,
BOD = test75$BOD,
TSS = test75$TSS,
Suhu = test75$Suhu,
DO = test75$DO,
Status_Aktual = test75$Status,
Prediksi_SVM = svm_pred75
)
tree_result75 <- data.frame(
pH = test75$pH,
BOD = test75$BOD,
TSS = test75$TSS,
Suhu = test75$Suhu,
DO = test75$DO,
Status_Aktual = test75$Status,
Prediksi_Tree = tree_pred75
)
rf_result75 <- data.frame(
pH = test75$pH,
BOD = test75$BOD,
TSS = test75$TSS,
Suhu = test75$Suhu,
DO = test75$DO,
Status_Aktual = test75$Status,
Prediksi_RF = rf_pred75
)
if (!require(openxlsx)) install.packages("openxlsx"); library(openxlsx)
## Loading required package: openxlsx
## Warning: package 'openxlsx' was built under R version 4.5.1
write.xlsx(svm_result75, "Prediksi75_SVM.xlsx")
write.xlsx(tree_result75, "Prediksi75_DecisionTree.xlsx")
write.xlsx(rf_result75, "Prediksi75_RandomForest.xlsx")
Hasil Akhir Berdasarkan 75 data terakhir, hasil prediksi menunjukkan bahwa nilai DO hasil model regresi cenderung mendekati nilai aktual, dengan rata-rata selisih sekitar 0.9. Sementara hasil klasifikasi model Random Forest mampu mengidentifikasi status air dengan tingkat kecocokan tinggi, di mana sebagian besar prediksi sesuai dengan status sebenarnya. Hal ini menegaskan bahwa kombinasi model regresi linier untuk DO dan Random Forest untuk status kualitas air dapat digunakan sebagai dasar pemantauan kondisi perairan secara cukup akurat.