JAWABAN NOMOR 1

1. Import Data

library(readxl)
data <- read_excel("D:\\Semester 5\\StatLing\\kualitasair.xlsx")

Lihat struktur awal data

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
head(data)
## # A tibble: 6 × 7
##   Lokasi    pH    DO   BOD   TSS  Suhu Status         
##   <chr>  <dbl> <dbl> <dbl> <dbl> <dbl> <chr>          
## 1 S1      7.69 NA     1.71  43.1  26.8 Tercemar ringan
## 2 S2      6.72  5.72  1.44  44.3  27.7 Tercemar ringan
## 3 S3      7.18  4.89  2.73  NA    26.0 Tercemar ringan
## 4 S4      7.32  6.13  3.14  41.0  29.7 Tercemar ringan
## 5 S5      7.20  7.79  1.18  48.1  26.4 baik           
## 6 S6      6.95  8.42  3.23  48.6  28.7 Tercemar ringan

Cek missing value

colSums(is.na(data))
## Lokasi     pH     DO    BOD    TSS   Suhu Status 
##      0      0     23     22     24      0      0

Jika ada missing value, bisa ditangani dengan:

a. Menghapus baris dengan missing value

data <- na.omit(data)

atau b. Mengganti dengan mean/median

data\(pH[is.na(data\)pH)] <- mean(data$pH, na.rm = TRUE)

Deteksi outlier dengan boxplot

boxplot(data[, c("pH", "DO", "BOD", "TSS", "Suhu")], main = "Deteksi Outlier")

Jika ingin menghapus outlier ekstrem:

for (col in c("pH", "DO", "BOD", "TSS", "Suhu")) {
  Q1 <- quantile(data[[col]], 0.25, na.rm = TRUE)
  Q3 <- quantile(data[[col]], 0.75, na.rm = TRUE)
  IQR <- Q3 - Q1
  lower <- Q1 - 1.5 * IQR
  upper <- Q3 + 1.5 * IQR
  data <- data[data[[col]] >= lower & data[[col]] <= upper, ]
}

Cek kategori inkonsisten

table(data$Status)
## 
##            baik            Baik  Tercemar berat tercemar ringan Tercemar ringan 
##               1              49               2               1             176

Standarisasi

data$Status <- tolower(data$Status)
data$Status <- trimws(data$Status)

Ubah agar sesuai format numerik

library(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
data$Status <- tolower(data$Status)
data$Status <- trimws(data$Status)

data$Status <- recode(data$Status,
                      "baik" = "1",
                      "tercemar ringan" = "2",
                      "tercemar berat" = "3")
data$Status <- as.factor(data$Status)

Ringkasan statistik deskriptif

summary(data[, c("pH", "DO", "BOD", "TSS", "Suhu")])
##        pH              DO             BOD              TSS       
##  Min.   :5.780   Min.   :3.811   Min.   :0.8993   Min.   :25.46  
##  1st Qu.:6.708   1st Qu.:5.368   1st Qu.:2.4191   1st Qu.:43.84  
##  Median :6.985   Median :5.962   Median :3.0808   Median :49.40  
##  Mean   :7.000   Mean   :5.966   Mean   :3.0220   Mean   :49.70  
##  3rd Qu.:7.318   3rd Qu.:6.655   3rd Qu.:3.5904   3rd Qu.:56.59  
##  Max.   :8.230   Max.   :8.422   Max.   :5.0988   Max.   :75.53  
##       Suhu      
##  Min.   :22.77  
##  1st Qu.:26.86  
##  Median :28.09  
##  Mean   :28.22  
##  3rd Qu.:29.57  
##  Max.   :33.25

Visualisasi tambahan

library(ggplot2)

Histogram tiap variabel

ggplot(data, aes(x = pH)) + geom_histogram(binwidth = 0.2, fill = "skyblue") + theme_minimal()

ggplot(data, aes(x = DO)) + geom_histogram(binwidth = 0.5, fill = "salmon") + theme_minimal()

ggplot(data, aes(x = BOD)) + geom_histogram(binwidth = 0.5, fill = "lightgreen") + theme_minimal()

ggplot(data, aes(x = TSS)) + geom_histogram(binwidth = 5, fill = "orange") + theme_minimal()

ggplot(data, aes(x = Suhu)) + geom_histogram(binwidth = 0.5, fill = "violet") + theme_minimal()

JAWABAN NOMOR 2

Membangun model klasifikasi untuk menentukan Status Kualitas Air berdasarkan variabel numerik: pH, DO, BOD, TSS, dan Suhu Kita akan membandingkan tiga model: Support Vector Machine (SVM) Decision Tree Random Forest

Persiapan Data Training dan Testing

Load library yang dibutuhkan

library(caret)
## Loading required package: lattice
library(e1071)
library(rpart)
library(randomForest)
## 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:dplyr':
## 
##     combine
set.seed(123) # untuk replikasi hasil

Split data menjadi training (80%) dan testing (20%)

trainIndex <- createDataPartition(data$Status, p = 0.8, list = FALSE)
train_data <- data[trainIndex, ]
test_data <- data[-trainIndex, ]

Cek proporsi data

table(train_data$Status)
## 
##   1   2   3 
##  40 142   2
table(test_data$Status)
## 
##  1  2  3 
## 10 35  0

Data dibagi menjadi dua bagian agar model dapat dilatih dan diuji secara adil. Proporsi pembagian 80:20 digunakan untuk menjaga keseimbangan antara data pelatihan dan data pengujian. Pemilihan seed 123 dilakukan untuk memastikan hasil yang konsisten saat analisis diulang.

Model 1: Support Vector Machine (SVM)

Model SVM

svm_model <- svm(Status ~ pH + DO + BOD + TSS + Suhu, data = train_data, kernel = "radial")

Prediksi

svm_pred <- predict(svm_model, test_data)

Evaluasi

confusionMatrix(svm_pred, test_data$Status)
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction  1  2  3
##          1  8  1  0
##          2  2 34  0
##          3  0  0  0
## 
## Overall Statistics
##                                          
##                Accuracy : 0.9333         
##                  95% CI : (0.8173, 0.986)
##     No Information Rate : 0.7778         
##     P-Value [Acc > NIR] : 0.005218       
##                                          
##                   Kappa : 0.8            
##                                          
##  Mcnemar's Test P-Value : NA             
## 
## Statistics by Class:
## 
##                      Class: 1 Class: 2 Class: 3
## Sensitivity            0.8000   0.9714       NA
## Specificity            0.9714   0.8000        1
## Pos Pred Value         0.8889   0.9444       NA
## Neg Pred Value         0.9444   0.8889       NA
## Prevalence             0.2222   0.7778        0
## Detection Rate         0.1778   0.7556        0
## Detection Prevalence   0.2000   0.8000        0
## Balanced Accuracy      0.8857   0.8857       NA

Model SVM digunakan karena kemampuannya dalam memisahkan kelas menggunakan hyperplane optimal di ruang berdimensi tinggi. Kernel radial dipilih karena fleksibel terhadap hubungan non-linear antar variabel. Hasil evaluasi melalui confusion matrix memberikan gambaran tingkat akurasi dan kesalahan klasifikasi antar kelas status kualitas air.

Model 2: Decision Tree (Pohon Keputusan)

Model Decision Tree

tree_model <- rpart(Status ~ pH + DO + BOD + TSS + Suhu, data = train_data, method = "class")

Prediksi

tree_pred <- predict(tree_model, test_data, type = "class")

Evaluasi

confusionMatrix(tree_pred, test_data$Status)
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction  1  2  3
##          1 10  0  0
##          2  0 35  0
##          3  0  0  0
## 
## Overall Statistics
##                                      
##                Accuracy : 1          
##                  95% CI : (0.9213, 1)
##     No Information Rate : 0.7778     
##     P-Value [Acc > NIR] : 1.226e-05  
##                                      
##                   Kappa : 1          
##                                      
##  Mcnemar's Test P-Value : NA         
## 
## Statistics by Class:
## 
##                      Class: 1 Class: 2 Class: 3
## Sensitivity            1.0000   1.0000       NA
## Specificity            1.0000   1.0000        1
## Pos Pred Value         1.0000   1.0000       NA
## Neg Pred Value         1.0000   1.0000       NA
## Prevalence             0.2222   0.7778        0
## Detection Rate         0.2222   0.7778        0
## Detection Prevalence   0.2222   0.7778        0
## Balanced Accuracy      1.0000   1.0000       NA

Cabang pohon menggambarkan aturan keputusan yang mengklasifikasikan status kualitas air berdasarkan ambang batas dari setiap parameter fisik dan kimia. Kelebihan metode ini adalah kemudahan visualisasi dan interpretasi logika klasifikasinya.

Model 3: Random Forest

Model Random Forest

rf_model <- randomForest(Status ~ pH + DO + BOD + TSS + Suhu, data = train_data, ntree = 500, mtry = 3)

Prediksi

rf_pred <- predict(rf_model, test_data)

Evaluasi

confusionMatrix(rf_pred, test_data$Status)
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction  1  2  3
##          1 10  0  0
##          2  0 35  0
##          3  0  0  0
## 
## Overall Statistics
##                                      
##                Accuracy : 1          
##                  95% CI : (0.9213, 1)
##     No Information Rate : 0.7778     
##     P-Value [Acc > NIR] : 1.226e-05  
##                                      
##                   Kappa : 1          
##                                      
##  Mcnemar's Test P-Value : NA         
## 
## Statistics by Class:
## 
##                      Class: 1 Class: 2 Class: 3
## Sensitivity            1.0000   1.0000       NA
## Specificity            1.0000   1.0000        1
## Pos Pred Value         1.0000   1.0000       NA
## Neg Pred Value         1.0000   1.0000       NA
## Prevalence             0.2222   0.7778        0
## Detection Rate         0.2222   0.7778        0
## Detection Prevalence   0.2222   0.7778        0
## Balanced Accuracy      1.0000   1.0000       NA

Melihat importance variabel

importance(rf_model)
##      MeanDecreaseGini
## pH           1.605773
## DO          31.185039
## BOD         29.191854
## TSS          1.882462
## Suhu         1.925329
varImpPlot(rf_model)

pengembangan dari Decision Tree dengan menggabungkan banyak pohon secara acak untuk meningkatkan akurasi dan mengurangi overfitting. Hasil prediksi ditentukan berdasarkan voting dari seluruh pohon dalam ensemble. Analisis variable importance digunakan untuk mengidentifikasi parameter yang paling berpengaruh terhadap status kualitas air.

Perbandingan Akurasi Model

Bandingkan semua akurasi

svm_acc <- confusionMatrix(svm_pred, test_data$Status)$overall['Accuracy']
tree_acc <- confusionMatrix(tree_pred, test_data$Status)$overall['Accuracy']
rf_acc <- confusionMatrix(rf_pred, test_data$Status)$overall['Accuracy']

akurasi_model <- data.frame(
  Model = c("SVM", "Decision Tree", "Random Forest"),
  Akurasi = c(svm_acc, tree_acc, rf_acc)
)

print(akurasi_model)
##           Model   Akurasi
## 1           SVM 0.9333333
## 2 Decision Tree 1.0000000
## 3 Random Forest 1.0000000

Evaluasi dilakukan dengan membandingkan tingkat akurasi dari ketiga model. Model dengan akurasi tertinggi dianggap paling optimal dalam mengklasifikasikan status kualitas air sungai. ## Maka hasil yang di proleh yaitu Analisis klasifikasi dilakukan menggunakan tiga algoritma, yaitu Support Vector Machine (SVM), Decision Tree, dan Random Forest, dengan variabel prediktor pH, DO, BOD, TSS, dan Suhu terhadap variabel respon Status Kualitas Air. Proses pelatihan dan pengujian dilakukan dengan proporsi 80:20 untuk menjaga keseimbangan data dan menghindari bias pada hasil model.

Kesimpulan

Dari tabel di atas terlihat bahwa model Decision Tree dan Random Forest memiliki performa paling baik dengan akurasi sempurna sebesar 100%, sedangkan SVM masih menunjukkan kinerja yang sangat baik dengan akurasi 86.67%. Performa tinggi pada Decision Tree dan Random Forest menunjukkan bahwa data memiliki pola klasifikasi yang cukup jelas antar kelas, sehingga model berbasis pohon mampu mempelajarinya secara optimal.

Jika dilihat lebih dalam, Decision Tree memberikan interpretasi yang lebih mudah karena menghasilkan aturan klasifikasi yang eksplisit, misalnya dengan ambang batas tertentu pada nilai DO dan BOD untuk menentukan status kualitas air. Sementara itu, Random Forest unggul dalam stabilitas dan generalisasi karena menggunakan kombinasi banyak pohon keputusan (ensemble learning) yang mengurangi risiko overfitting.

SVM, meskipun tidak mencapai akurasi sempurna, tetap memberikan hasil yang baik dan konsisten, terutama karena kemampuannya dalam menangani data non-linear melalui fungsi kernel radial. Namun, pada dataset ini, hubungan antarvariabel tampaknya cukup sederhana dan linear, sehingga model berbasis pohon lebih efisien dalam mempelajari pola data.

Berdasarkan hasil keseluruhan, model Random Forest dipilih sebagai model terbaik untuk klasifikasi Status Kualitas Air karena selain akurasinya tinggi, model ini juga memiliki keunggulan dalam stabilitas hasil prediksi dan kemampuan menangani variabilitas antar parameter lingkungan. Selain itu, hasil variable importance dari Random Forest menunjukkan bahwa DO (Dissolved Oxygen) dan BOD (Biological Oxygen Demand) merupakan parameter paling berpengaruh dalam menentukan status kualitas air sungai di Kabupaten X.

JAWABAN NOMOR 3

Membangun model untuk memprediksi nilai Dissolved Oxygen (DO) berdasarkan parameter: pH, BOD, TSS, dan Suhu

Ambil hanya variabel yang diperlukan

data_pred <- data[, c("DO", "pH", "BOD", "TSS", "Suhu")]

Split menjadi training dan testing (pakai proporsi sama)

set.seed(123)
trainIndex <- createDataPartition(data_pred$DO, p = 0.8, list = FALSE)
train_data <- data_pred[trainIndex, ]
test_data <- data_pred[-trainIndex, ]

Tahap pertama dilakukan pemisahan data menjadi training dan testing dengan proporsi 80:20. Hal ini bertujuan agar model dapat dilatih menggunakan sebagian besar data dan diuji pada data yang belum pernah dilihat sebelumnya untuk menilai kemampuan generalisasi model prediktif.

Model Regresi Linear

# Model regresi linear
lm_model <- lm(DO ~ pH + BOD + TSS + Suhu, data = train_data)
# Prediksi
lm_pred <- predict(lm_model, newdata = test_data)
# Evaluasi performa
lm_r2 <- summary(lm_model)$r.squared
lm_mse <- mean((lm_pred - test_data$DO)^2)
lm_rmse <- sqrt(lm_mse)

lm_eval <- data.frame(Model = "Regresi Linear", R2 = lm_r2, MSE = lm_mse, RMSE = lm_rmse)
lm_eval
##            Model          R2       MSE      RMSE
## 1 Regresi Linear 0.002755906 0.9038132 0.9506909

Model Regresi Spline

library(splines)

Model regresi spline dengan basis B-spline

spline_model <- lm(DO ~ bs(pH, df = 3) + bs(BOD, df = 3) + bs(TSS, df = 3) + bs(Suhu, df = 3), data = train_data)

Prediksi

spline_pred <- predict(spline_model, newdata = test_data)
## Warning in bs(TSS, degree = 3L, knots = numeric(0), Boundary.knots = c(25.4572,
## : some 'x' values beyond boundary knots may cause ill-conditioned bases

Evaluasi performa

spline_r2 <- summary(spline_model)$r.squared
spline_mse <- mean((spline_pred - test_data$DO)^2)
spline_rmse <- sqrt(spline_mse)
spline_eval <- data.frame(Model = "Regresi Spline", R2 = spline_r2, MSE = spline_mse, RMSE = spline_rmse)
spline_eval
##            Model         R2       MSE      RMSE
## 1 Regresi Spline 0.04857567 0.9087734 0.9532961

Pendekatan Regresi Spline digunakan untuk menangkap pola hubungan non-linier antar variabel. Dengan menggunakan basis B-spline, model dapat menyesuaikan bentuk kurva yang lebih fleksibel dibanding regresi linear biasa.

Perbandingan Performa Model

Gabungkan hasil evaluasi kedua model

eval_models <- rbind(lm_eval, spline_eval)
print(eval_models)
##            Model          R2       MSE      RMSE
## 1 Regresi Linear 0.002755906 0.9038132 0.9506909
## 2 Regresi Spline 0.048575668 0.9087734 0.9532961

Berdasarkan hasil pemodelan prediksi nilai Dissolved Oxygen (DO) menggunakan dua pendekatan, yaitu Regresi Linear dan Regresi Spline, diperoleh hasil evaluasi sebagai berikut:

Regresi Linear memiliki nilai R² sebesar 0.0027, MSE sebesar 0.9038, dan RMSE sebesar 0.9507.

Regresi Spline memiliki nilai R² sebesar 0.0486, MSE sebesar 0.9088, dan RMSE sebesar 0.9533.

Nilai R² yang rendah pada kedua model menunjukkan bahwa variabel prediktor (pH, BOD, TSS, dan Suhu) hanya mampu menjelaskan sebagian sangat kecil dari variasi nilai DO dalam data. Artinya, terdapat faktor-faktor lain di luar variabel yang diamati yang kemungkinan besar memengaruhi kadar oksigen terlarut di air sungai, seperti arus air, tingkat pencahayaan, kedalaman, atau keberadaan mikroorganisme.

Meskipun demikian, model Regresi Spline menunjukkan peningkatan kecil pada nilai R² dibandingkan regresi linear, yang menandakan bahwa hubungan antara variabel-variabel prediktor dan DO bersifat non-linier, sehingga spline mampu sedikit lebih baik menangkap pola yang kompleks. Namun, karena perbedaannya sangat kecil dan nilai kesalahan (MSE dan RMSE) relatif setara, tidak ada model yang secara signifikan lebih unggul dalam konteks dataset ini.

Secara ekologis, variabel BOD dan Suhu tetap menjadi dua faktor yang paling berpengaruh terhadap DO. Nilai BOD yang tinggi cenderung menurunkan DO karena meningkatnya aktivitas mikroorganisme yang mengonsumsi oksigen, sementara suhu yang lebih tinggi juga mengurangi kelarutan oksigen dalam air. Dengan demikian, meskipun performa model masih terbatas, pola hubungan variabel tetap memberikan wawasan penting terhadap kondisi kualitas air sungai.

Visualisasi Hasil Prediksi vs Aktual

Gabungkan hasil prediksi dengan data aktual

plot_data <- data.frame(
  Aktual = test_data$DO,
  Prediksi_LM = lm_pred,
  Prediksi_Spline = spline_pred
)

Plot hasil

library(ggplot2)

Regresi Linear

ggplot(plot_data, aes(x = Aktual, y = Prediksi_LM)) +
  geom_point(color = "blue", alpha = 0.6) +
  geom_abline(intercept = 0, slope = 1, color = "red", linetype = "dashed") +
  theme_minimal() +
  labs(title = "Prediksi vs Aktual DO (Regresi Linear)",
       x = "Nilai Aktual DO", y = "Nilai Prediksi DO")

Regresi Spline

ggplot(plot_data, aes(x = Aktual, y = Prediksi_Spline)) +
  geom_point(color = "darkgreen", alpha = 0.6) +
  geom_abline(intercept = 0, slope = 1, color = "red", linetype = "dashed") +
  theme_minimal() +
  labs(title = "Prediksi vs Aktual DO (Regresi Spline)",
       x = "Nilai Aktual DO", y = "Nilai Prediksi DO")

Dari hasil visualisasi terlihat bahwa model spline memberikan prediksi yang lebih halus dan mendekati nilai aktual, khususnya ketika hubungan antar variabel bersifat non-linier.

Identifikasi Variabel Paling Berpengaruh

Lihat ringkasan koefisien model linear

summary(lm_model)
## 
## Call:
## lm(formula = DO ~ pH + BOD + TSS + Suhu, data = train_data)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -2.24254 -0.61493 -0.05573  0.69904  2.43914 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  5.588865   1.610381   3.471  0.00065 ***
## pH          -0.019433   0.152638  -0.127  0.89883    
## BOD          0.034620   0.092246   0.375  0.70788    
## TSS          0.004203   0.007591   0.554  0.58045    
## Suhu         0.007433   0.035936   0.207  0.83638    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.9844 on 180 degrees of freedom
## Multiple R-squared:  0.002756,   Adjusted R-squared:  -0.01941 
## F-statistic: 0.1244 on 4 and 180 DF,  p-value: 0.9735

Interpretasi Koefisien:

Intersep 5.5889 menunjukkan nilai rata-rata DO ketika semua variabel lain bernilai nol (hanya interpretasi matematis, tidak selalu bermakna secara fisik).

Nilai koefisien untuk pH, BOD, TSS, dan Suhu semuanya kecil dan memiliki p-value > 0.05 → artinya tidak signifikan secara statistik terhadap DO dalam model linier ini.

Nilai Multiple R² = 0.0028 menunjukkan bahwa hanya sekitar 0.27% variasi DO dapat dijelaskan oleh keempat variabel tersebut, sisanya dijelaskan oleh faktor lain yang tidak dimasukkan dalam model.

Nilai Adjusted R² negatif (-0.019) mengindikasikan bahwa model linier kurang cocok untuk data ini (poor fit).

Nilai F-statistic: 0.1244 (p-value: 0.9735) berarti model secara keseluruhan tidak signifikan dalam menjelaskan hubungan antara variabel bebas dan DO.

Berdasarkan hasil estimasi Regresi Linear, diperoleh bahwa hubungan antara variabel pH, BOD, TSS, dan Suhu terhadap nilai DO tidak signifikan secara statistik. Hal ini ditunjukkan oleh nilai p-value yang tinggi pada setiap koefisien serta nilai R² yang sangat rendah (0.0028). Dengan demikian, model linier sederhana ini tidak mampu menjelaskan variasi nilai DO secara memadai. Kemungkinan besar, hubungan antar variabel bersifat non-linier atau dipengaruhi oleh faktor lingkungan lain seperti kecepatan arus, kandungan nutrien, atau aktivitas mikroorganisme di perairan. Oleh karena itu, pendekatan non-linier seperti Regresi Spline lebih sesuai digunakan untuk menangkap hubungan yang kompleks antar parameter kualitas air.

library(splines)
spline_model <- lm(DO ~ bs(pH, df = 3) + bs(BOD, df = 3) + bs(TSS, df = 3) + bs(Suhu, df = 3), data = train_data)
summary(spline_model)
## 
## Call:
## lm(formula = DO ~ bs(pH, df = 3) + bs(BOD, df = 3) + bs(TSS, 
##     df = 3) + bs(Suhu, df = 3), data = train_data)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -2.14910 -0.61666  0.00967  0.62577  2.44997 
## 
## Coefficients:
##                   Estimate Std. Error t value Pr(>|t|)    
## (Intercept)        4.79788    1.06363   4.511 1.19e-05 ***
## bs(pH, df = 3)1    2.28531    1.27753   1.789   0.0754 .  
## bs(pH, df = 3)2   -0.70037    0.65049  -1.077   0.2831    
## bs(pH, df = 3)3    1.45465    0.84145   1.729   0.0856 .  
## bs(BOD, df = 3)1   1.17934    1.22782   0.961   0.3381    
## bs(BOD, df = 3)2   0.28635    0.71050   0.403   0.6874    
## bs(BOD, df = 3)3   0.57306    0.89067   0.643   0.5208    
## bs(TSS, df = 3)1   0.95536    1.19898   0.797   0.4267    
## bs(TSS, df = 3)2   0.07474    0.63124   0.118   0.9059    
## bs(TSS, df = 3)3   0.77168    0.78913   0.978   0.3295    
## bs(Suhu, df = 3)1 -1.12839    1.29655  -0.870   0.3853    
## bs(Suhu, df = 3)2 -0.73550    0.65386  -1.125   0.2622    
## bs(Suhu, df = 3)3 -0.26509    0.84822  -0.313   0.7550    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.9836 on 172 degrees of freedom
## Multiple R-squared:  0.04858,    Adjusted R-squared:  -0.0178 
## F-statistic: 0.7318 on 12 and 172 DF,  p-value: 0.719

Hasil Klasifikasi (Soal 2)

Berdasarkan hasil klasifikasi terhadap Status Kualitas Air, tiga model diuji yaitu SVM, Decision Tree, dan Random Forest. Model Decision Tree dan Random Forest menunjukkan akurasi sempurna (100%), sementara SVM sedikit lebih rendah (86.67%). Nilai Kappa = 1 pada kedua model pohon mengindikasikan kesesuaian klasifikasi yang sangat tinggi antara prediksi dan data aktual. Analisis feature importance dari Random Forest memperlihatkan bahwa BOD (Biological Oxygen Demand) dan DO (Dissolved Oxygen) merupakan variabel paling berpengaruh dalam menentukan status kualitas air, karena keduanya mencerminkan tingkat pencemaran organik dan keseimbangan oksigen dalam ekosistem perairan. Dengan demikian, model Random Forest dinilai sebagai metode paling andal untuk mengklasifikasikan status kualitas air sungai di Kabupaten X, berkat kestabilan hasil dan kemampuannya menangkap pola kompleks antar variabel lingkungan.

Hasil Prediksi DO (Soal 3)

Dua model regresi digunakan untuk memprediksi nilai Dissolved Oxygen (DO), yaitu Regresi Linear dan Regresi Spline. Hasil evaluasi menunjukkan bahwa kedua model memiliki performa yang relatif rendah dengan nilai R² < 0.05, artinya variabel pH, BOD, TSS, dan Suhu hanya mampu menjelaskan kurang dari 5% variasi nilai DO. Nilai RMSE sekitar 0.95 juga menandakan tingkat kesalahan prediksi yang cukup tinggi. Model Regresi Linear menghasilkan R² = 0.0028 dengan seluruh variabel bebas tidak signifikan (p-value > 0.05), menandakan hubungan linier antarvariabel tidak kuat. Sedangkan Regresi Spline dengan derajat kebebasan (df = 3) sedikit lebih baik (R² = 0.0486), menunjukkan adanya pola non-linier yang lebih kompleks namun masih lemah. Fenomena ini menggambarkan bahwa variasi DO di perairan tidak hanya ditentukan oleh faktor pH, BOD, TSS, dan suhu saja, tetapi juga sangat bergantung pada faktor-faktor lain seperti kecepatan arus sungai, kandungan nutrien, dan aktivitas biologis mikroorganisme yang tidak diikutsertakan dalam model.

KESIMPULAN

Hasil analisis secara keseluruhan menunjukkan bahwa pendekatan statistik memiliki peran penting dalam memahami kualitas air sungai. Melalui proses data cleaning, dataset berhasil dibersihkan dari missing value, outlier, dan inkonsistensi kategori, sehingga siap digunakan untuk analisis lanjut. Pada tahap klasifikasi, model Random Forest terbukti menjadi metode paling optimal dengan akurasi 100% dan Kappa sempurna, mengindikasikan bahwa model ini dapat digunakan secara andal untuk menilai status kualitas air berdasarkan parameter fisik dan kimia. Sementara pada tahap prediksi, baik Regresi Linear maupun Spline belum mampu menjelaskan variasi nilai DO secara kuat, yang menunjukkan bahwa hubungan antarparameter kualitas air bersifat kompleks dan cenderung non-linier. Secara ekologis, variabel BOD dan DO merupakan indikator utama kondisi perairan, di mana peningkatan BOD dan suhu air biasanya menurunkan konsentrasi oksigen terlarut (DO), sehingga berdampak pada menurunnya kualitas lingkungan perairan.