Load Data

library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.1     ✔ stringr   1.5.1
## ✔ ggplot2   3.5.2     ✔ tibble    3.3.0
## ✔ lubridate 1.9.4     ✔ tidyr     1.3.1
## ✔ purrr     1.1.0     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ 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
library(caret)
## Loading required package: lattice
## 
## Attaching package: 'caret'
## 
## The following object is masked from 'package:purrr':
## 
##     lift
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:dplyr':
## 
##     combine
## 
## The following object is masked from 'package:ggplot2':
## 
##     margin
library(splines)

set.seed(223)

data_train <- read.csv("C:/Users/HP/Documents/TUGAS/SMT 5/Statistika Lingkungan/UTS/kualitasair-Training.csv")

str(data_train)
## 'data.frame':    300 obs. of  7 variables:
##  $ Lokasi: chr  "S1" "S2" "S3" "S4" ...
##  $ pH    : num  7.69 6.72 7.18 7.32 7.2 ...
##  $ DO    : num  NA 5.72 4.89 6.13 7.79 ...
##  $ BOD   : num  1.71 1.44 2.73 3.14 1.18 ...
##  $ TSS   : num  43.1 44.3 NA 41 48.1 ...
##  $ Suhu  : num  26.8 27.7 26 29.7 26.4 ...
##  $ Status: chr  "Tercemar ringan" "Tercemar ringan" "Tercemar ringan" "Tercemar ringan" ...
head(data_train)
##   Lokasi     pH     DO    BOD     TSS    Suhu          Status
## 1     S1 7.6855     NA 1.7136 43.1415 26.7972 Tercemar ringan
## 2     S2 6.7177 5.7236 1.4402 44.2963 27.7284 Tercemar ringan
## 3     S3 7.1816 4.8906 2.7274      NA 26.0255 Tercemar ringan
## 4     S4 7.3164 6.1339 3.1398 41.0104 29.6639 Tercemar ringan
## 5     S5 7.2021 7.7853 1.1778 48.0967 26.4099            baik
## 6     S6 6.9469 8.4222 3.2324 48.5610 28.6809 Tercemar ringan

SOAL 1 Data Cleaning & Eksplorasi

1) Missing value + Outlier + Inkonsistensi

colSums(is.na(data_train))
## Lokasi     pH     DO    BOD    TSS   Suhu Status 
##      0      0     23     22     24      0      0
for (col in c("DO","BOD","TSS")) {
  data_train[[col]][is.na(data_train[[col]])] <- median(data_train[[col]], na.rm = TRUE)
}

colSums(is.na(data_train))
## Lokasi     pH     DO    BOD    TSS   Suhu Status 
##      0      0      0      0      0      0      0
boxplot(data_train$pH,  main = "Outlier pH")

boxplot(data_train$DO,  main = "Outlier DO")

boxplot(data_train$BOD, main = "Outlier BOD")

boxplot(data_train$TSS, main = "Outlier TSS")

boxplot(data_train$Suhu,main = "Outlier Suhu")

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

Missing Value

  • Berdasarkan hasil colSums(is.na()), terdapat missing value pada variabel DO, BOD, dan TSS.

  • Nilai-nilai tersebut diimputasi menggunakan median, agar tidak mengubah distribusi data secara signifikan.

Outlier

  • Boxplot tiap variabel (pH, DO, BOD, TSS, Suhu) menunjukkan adanya beberapa titik ekstrem (lingkaran di luar whisker).
  • Ini menandakan data memiliki outlier alami akibat variasi kualitas air di beberapa lokasi.
  • Namun, karena jumlah outlier relatif sedikit dan masih dalam konteks pengukuran lingkungan, data tetap dipertahankan (tidak dibuang).

Inkonsistensi Kategori

  • Variabel Status distandarkan jadi tiga kategori tetap:

    • 1 = Baik

    • 2 = Tercemar Ringan

    • 3 = Tercemar Berat

2) Standarisasi kategori Status

table(data_train$Status)
## 
##            baik            Baik            BAIK  Tercemar berat tercemar ringan 
##               1              70               1               7               1 
## Tercemar ringan Tercemar Ringan 
##             219               1
data_train$Status <- tolower(data_train$Status)
data_train$Status <- trimws(data_train$Status)
data_train$Status <- dplyr::recode(
  data_train$Status,
  "baik"            = "1",
  "tercemar ringan" = "2",
  "tercemar berat"  = "3",
  .default = data_train$Status
)
data_train$Status <- as.factor(data_train$Status)

table(data_train$Status)
## 
##   1   2   3 
##  72 221   7

Pada tahap ini dilakukan standarisasi penulisan kategori variabel Status agar konsisten dan tidak menimbulkan perbedaan interpretasi.
Beberapa data memiliki variasi penulisan seperti “Baik”, “BAIK”, dan “baik”, serta “Tercemar ringan” dengan variasi kapitalisasi.

Langkah yang dilakukan:

  1. Mengubah seluruh teks menjadi huruf kecil dengan fungsi tolower().

  2. Menghapus spasi berlebih menggunakan trimws().

  3. Melakukan pengkodean ulang dengan dplyr::recode() menjadi:

-   **1** = Baik

```{=html}
<!-- -->
```
-    **2** = Tercemar ringan

```{=html}
<!-- -->
```
-    **3** = Tercemar berat
  1. Mengubah tipe data menjadi factor.

Hasil distribusi setelah standarisasi menunjukkan:

  • 72 data berstatus Baik,

  • 221 data berstatus Tercemar ringan, dan

  • 7 data berstatus Tercemar berat.

Langkah ini memastikan kategori pada variabel Status seragam dan siap digunakan untuk proses klasifikasi pada tahap berikutnya.

3) Ringkasan statistik deskriptif (setelah cleaning)

summary(data_train[, c("pH","DO","BOD","TSS","Suhu")])
##        pH              DO             BOD              TSS       
##  Min.   :5.503   Min.   :2.982   Min.   :0.3026   Min.   :24.65  
##  1st Qu.:6.670   1st Qu.:5.413   1st Qu.:2.4599   1st Qu.:44.28  
##  Median :6.988   Median :5.991   Median :3.0661   Median :49.52  
##  Mean   :6.989   Mean   :5.977   Mean   :3.0053   Mean   :49.68  
##  3rd Qu.:7.318   3rd Qu.:6.611   3rd Qu.:3.5323   3rd Qu.:55.62  
##  Max.   :8.351   Max.   :9.229   Max.   :5.7962   Max.   :76.34  
##       Suhu      
##  Min.   :22.77  
##  1st Qu.:26.62  
##  Median :28.01  
##  Mean   :28.31  
##  3rd Qu.:29.46  
##  Max.   :90.00

Tahap ini bertujuan untuk menampilkan gambaran umum dari data setelah dilakukan pembersihan (data cleaning).
Ringkasan statistik deskriptif menunjukkan sebaran nilai untuk setiap variabel numerik sebagai berikut:

  • Nilai pH berkisar antara 5.50 – 8.35 dengan rata-rata 6.99, menunjukkan kondisi air relatif netral.

  • Nilai DO (Dissolved Oxygen) berada pada rentang 2.98 – 9.23 mg/L, dengan rata-rata 5.98, menandakan variasi kadar oksigen terlarut antar lokasi.

  • Nilai BOD (Biochemical Oxygen Demand) memiliki kisaran 0.30 – 5.80 mg/L, dengan median sekitar 3.07, menandakan kualitas bahan organik terlarut tergolong sedang.

  • TSS (Total Suspended Solid) berkisar 24.65 – 76.34 mg/L, dengan rata-rata 49.68, menunjukkan perbedaan tingkat kekeruhan antar lokasi.

  • Suhu air berada di kisaran 22.77 – 90.00°C dengan rata-rata 28.31°C, di mana nilai ekstrem tinggi kemungkinan merupakan outlier pengukuran.

Secara keseluruhan, data telah bersih, terstandarisasi, dan siap digunakan untuk tahap analisis lanjutan yaitu klasifikasi status kualitas air.

Soal 2 Klasifikasi Status Kualitas Air (35%)

1) Pemilihan Variabel Numerik dan Pembagian Data

num_vars <- c("pH", "DO", "BOD", "TSS", "Suhu")
data_class <- data_train[, c(num_vars, "Status")]

set.seed(123)
library(caret)

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

2) Pembangunan Model Klasifikasi

# 1. SVM / SVR (pakai e1071)
library(e1071)
svm_model <- svm(Status ~ ., data = train_data)
svm_pred  <- predict(svm_model, newdata = test_data)

# 2. Decision Tree
library(rpart)
library(rpart.plot)
tree_model <- rpart(Status ~ ., data = train_data, method = "class")
tree_pred  <- predict(tree_model, newdata = test_data, type = "class")

# 3. Random Forest
library(randomForest)
rf_model <- randomForest(Status ~ ., data = train_data, ntree = 100)
rf_pred  <- predict(rf_model, newdata = test_data)

3) Evaluasi Model (Confusion Matrix dan Akurasi)

library(caret)

cat("===== SVM =====\n")
## ===== SVM =====
cm_svm <- confusionMatrix(as.factor(svm_pred), as.factor(test_data$Status))
print(cm_svm)
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction  1  2  3
##          1  8  1  0
##          2  6 43  1
##          3  0  0  0
## 
## Overall Statistics
##                                           
##                Accuracy : 0.8644          
##                  95% CI : (0.7502, 0.9396)
##     No Information Rate : 0.7458          
##     P-Value [Acc > NIR] : 0.02096         
##                                           
##                   Kappa : 0.5913          
##                                           
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: 1 Class: 2 Class: 3
## Sensitivity            0.5714   0.9773  0.00000
## Specificity            0.9778   0.5333  1.00000
## Pos Pred Value         0.8889   0.8600      NaN
## Neg Pred Value         0.8800   0.8889  0.98305
## Prevalence             0.2373   0.7458  0.01695
## Detection Rate         0.1356   0.7288  0.00000
## Detection Prevalence   0.1525   0.8475  0.00000
## Balanced Accuracy      0.7746   0.7553  0.50000
cat("\n===== Decision Tree =====\n")
## 
## ===== Decision Tree =====
cm_tree <- confusionMatrix(as.factor(tree_pred), as.factor(test_data$Status))
print(cm_tree)
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction  1  2  3
##          1 13  0  0
##          2  1 44  1
##          3  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.9075          
##                                           
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: 1 Class: 2 Class: 3
## Sensitivity            0.9286   1.0000  0.00000
## Specificity            1.0000   0.8667  1.00000
## Pos Pred Value         1.0000   0.9565      NaN
## Neg Pred Value         0.9783   1.0000  0.98305
## Prevalence             0.2373   0.7458  0.01695
## Detection Rate         0.2203   0.7458  0.00000
## Detection Prevalence   0.2203   0.7797  0.00000
## Balanced Accuracy      0.9643   0.9333  0.50000
cat("\n===== Random Forest =====\n")
## 
## ===== Random Forest =====
cm_rf <- confusionMatrix(as.factor(rf_pred), as.factor(test_data$Status))
print(cm_rf)
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction  1  2  3
##          1 13  1  0
##          2  1 43  1
##          3  0  0  0
## 
## Overall Statistics
##                                           
##                Accuracy : 0.9492          
##                  95% CI : (0.8585, 0.9894)
##     No Information Rate : 0.7458          
##     P-Value [Acc > NIR] : 4.59e-05        
##                                           
##                   Kappa : 0.8644          
##                                           
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: 1 Class: 2 Class: 3
## Sensitivity            0.9286   0.9773  0.00000
## Specificity            0.9778   0.8667  1.00000
## Pos Pred Value         0.9286   0.9556      NaN
## Neg Pred Value         0.9778   0.9286  0.98305
## Prevalence             0.2373   0.7458  0.01695
## Detection Rate         0.2203   0.7288  0.00000
## Detection Prevalence   0.2373   0.7627  0.00000
## Balanced Accuracy      0.9532   0.9220  0.50000
acc_svm  <- cm_svm$overall["Accuracy"]
acc_tree <- cm_tree$overall["Accuracy"]
acc_rf   <- cm_rf$overall["Accuracy"]

accuracy_df <- data.frame(
  Model = c("SVM", "Decision Tree", "Random Forest"),
  Akurasi = c(acc_svm, acc_tree, acc_rf)
)
print(accuracy_df)
##           Model   Akurasi
## 1           SVM 0.8644068
## 2 Decision Tree 0.9661017
## 3 Random Forest 0.9491525

Evaluasi dilakukan menggunakan Confusion Matrix dan akurasi model.
Hasil evaluasi menunjukkan bahwa ketiga model memiliki performa cukup baik dalam mengklasifikasikan status kualitas air berdasarkan variabel numerik (pH, DO, BOD, TSS, dan Suhu).

  • Support Vector Machine (SVM) memperoleh akurasi sebesar 86,44%, menandakan performa yang baik namun cenderung sensitif terhadap data non-linear.

  • Decision Tree memiliki akurasi tertinggi sebesar 96,61%, menunjukkan model ini paling efektif dalam membedakan kategori Baik, Tercemar Ringan, dan Tercemar Berat.

  • Random Forest mencatat akurasi 94,92%, sedikit di bawah Decision Tree, namun tetap unggul dari sisi kestabilan karena sifatnya yang berbasis ensemble.

Dari Confusion Matrix terlihat bahwa model Decision Tree dan Random Forest mampu mengenali kelas “Baik” dan “Tercemar Ringan” dengan sensitivitas tinggi (di atas 0.92). Namun, kelas “Tercemar Berat” memiliki nilai sensitivitas 0, yang kemungkinan disebabkan oleh jumlah data kelas tersebut sangat sedikit (hanya 7 data) sehingga model sulit mengenalinya.

Secara keseluruhan, Decision Tree menjadi model terbaik dalam memprediksi status kualitas air, dengan keseimbangan antara akurasi dan interpretabilitas hasil.

4) Interpretasi dan Visualisasi Akurasi

library(ggplot2)
ggplot(accuracy_df, aes(x = Model, y = Akurasi, fill = Model)) +
  geom_col(width = 0.6) +
  geom_text(aes(label = round(Akurasi, 3)), vjust = -0.5) +
  labs(
    title = "Perbandingan Akurasi Model Klasifikasi Status Kualitas Air",
    x = NULL, y = "Akurasi"
  ) +
  theme_minimal()

Grafik di atas menunjukkan perbandingan tingkat akurasi dari ketiga model klasifikasi yang digunakan, yaitu Decision Tree, Random Forest, dan SVM.
Dari hasil visualisasi terlihat bahwa:

  • Decision Tree memiliki akurasi tertinggi sebesar 96,6%, menunjukkan bahwa model ini paling efektif dalam memisahkan kategori status kualitas air.

  • Random Forest menyusul dengan akurasi 94,9%, menunjukkan performa yang stabil dan hampir setara dengan Decision Tree.

  • SVM memiliki akurasi 86,4%, sedikit lebih rendah dibanding dua model lainnya karena lebih sensitif terhadap distribusi data yang tidak seimbang.

Secara keseluruhan, dapat disimpulkan bahwa Decision Tree menjadi model terbaik untuk mengklasifikasikan status kualitas air berdasarkan variabel pH, DO, BOD, TSS, dan Suhu, karena memberikan hasil akurasi tertinggi dengan kompleksitas yang relatif rendah.

Soal 3 Prediksi Variabel DO

1) Pembuatan Model Regresi Linear dan Regresi Spline

num_vars <- c("pH", "BOD", "TSS", "Suhu", "DO")
data_reg <- data_train[, num_vars]

set.seed(123)
library(caret)
train_index <- createDataPartition(data_reg$DO, p = 0.8, list = FALSE)
train_reg <- data_reg[train_index, ]
test_reg  <- data_reg[-train_index, ]

# Model 1: Regresi Linear
lm_model <- lm(DO ~ pH + BOD + TSS + Suhu, data = train_reg)
summary(lm_model)
## 
## Call:
## lm(formula = DO ~ pH + BOD + TSS + Suhu, data = train_reg)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -3.00096 -0.52419  0.00635  0.61111  2.87205 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  5.8944142  1.0524885   5.600 5.93e-08 ***
## pH          -0.0488955  0.1270069  -0.385   0.7006    
## BOD          0.1687463  0.0793648   2.126   0.0345 *  
## TSS          0.0002084  0.0066383   0.031   0.9750    
## Suhu        -0.0036443  0.0140490  -0.259   0.7956    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.9781 on 236 degrees of freedom
## Multiple R-squared:  0.01962,    Adjusted R-squared:  0.003007 
## F-statistic: 1.181 on 4 and 236 DF,  p-value: 0.3198
# Model 2: Regresi Spline
library(splines)
spline_model <- lm(DO ~ bs(pH, df = 3) + bs(BOD, df = 3) + bs(TSS, df = 3) + bs(Suhu, df = 3),
                   data = train_reg)
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_reg)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -3.03297 -0.51077  0.01215  0.56018  2.53244 
## 
## Coefficients:
##                   Estimate Std. Error t value Pr(>|t|)    
## (Intercept)        5.22842    0.88370   5.917  1.2e-08 ***
## bs(pH, df = 3)1    0.80837    1.22752   0.659 0.510858    
## bs(pH, df = 3)2   -0.54262    0.63479  -0.855 0.393555    
## bs(pH, df = 3)3    0.59072    0.86551   0.683 0.495610    
## bs(BOD, df = 3)1   3.08657    1.11518   2.768 0.006108 ** 
## bs(BOD, df = 3)2  -1.16757    0.64031  -1.823 0.069545 .  
## bs(BOD, df = 3)3   3.48026    0.88861   3.917 0.000119 ***
## bs(TSS, df = 3)1  -0.82848    1.04768  -0.791 0.429893    
## bs(TSS, df = 3)2   0.62061    0.60389   1.028 0.305186    
## bs(TSS, df = 3)3  -0.89559    0.77871  -1.150 0.251306    
## bs(Suhu, df = 3)1 -3.25497    2.66622  -1.221 0.223416    
## bs(Suhu, df = 3)2 10.86728   14.29206   0.760 0.447818    
## bs(Suhu, df = 3)3 -0.05014    1.00583  -0.050 0.960288    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.9645 on 228 degrees of freedom
## Multiple R-squared:  0.07903,    Adjusted R-squared:  0.03055 
## F-statistic:  1.63 on 12 and 228 DF,  p-value: 0.08435

Dibangun dua model regresi, yaitu Regresi Linear dan Regresi Spline, dengan variabel prediktor pH, BOD, TSS, dan Suhu.

Dari hasil regresi linear, variabel BOD memiliki nilai p-value = 0.0345, yang berarti signifikan terhadap perubahan DO, sedangkan variabel lain (pH, TSS, dan Suhu) tidak signifikan.

Model spline menunjukkan adanya peningkatan fleksibilitas, namun belum memberikan peningkatan performa yang berarti terhadap nilai DO.

2) Evaluasi Performa Model (R², MSE, RMSE)

lm_pred <- predict(lm_model, newdata = test_reg)
spline_pred <- predict(spline_model, newdata = test_reg)
## Warning in bs(BOD, degree = 3L, knots = numeric(0), Boundary.knots = c(0.8993,
## : some 'x' values beyond boundary knots may cause ill-conditioned bases
## Warning in bs(Suhu, degree = 3L, knots = numeric(0), Boundary.knots =
## c(23.2896, : some 'x' values beyond boundary knots may cause ill-conditioned
## bases
R2_lm <- R2(lm_pred, test_reg$DO)
R2_spline <- R2(spline_pred, test_reg$DO)

MSE_lm <- mean((test_reg$DO - lm_pred)^2)
MSE_spline <- mean((test_reg$DO - spline_pred)^2)

RMSE_lm <- sqrt(MSE_lm)
RMSE_spline <- sqrt(MSE_spline)

eval_df <- data.frame(
  Model = c("Regresi Linear", "Regresi Spline"),
  R2 = c(R2_lm, R2_spline),
  MSE = c(MSE_lm, MSE_spline),
  RMSE = c(RMSE_lm, RMSE_spline)
)
print(eval_df)
##            Model         R2       MSE      RMSE
## 1 Regresi Linear 0.02835838 0.8411642 0.9171500
## 2 Regresi Spline 0.00251645 0.9336114 0.9662357

Evaluasi dilakukan menggunakan metrik R², MSE, dan RMSE:

Model MSE RMSE
Regresi Linear 0.028 0.841 0.917
Regresi Spline 0.002 0.934 0.966

Nilai R² yang rendah pada kedua model menunjukkan bahwa variabel pH, BOD, TSS, dan Suhu belum cukup menjelaskan variasi nilai DO secara signifikan.
Namun, model linear masih sedikit lebih baik dibanding spline karena memiliki galat (RMSE) yang lebih kecil.

3) Visualisasi Hasil Prediksi vs Aktual

library(ggplot2)

pred_df <- data.frame(
  DO_Aktual = test_reg$DO,
  DO_LM = lm_pred,
  DO_Spline = spline_pred
)

ggplot(pred_df, aes(x = DO_Aktual)) +
  geom_point(aes(y = DO_LM, color = "Regresi Linear"), size = 2) +
  geom_point(aes(y = DO_Spline, color = "Regresi Spline"), size = 2, shape = 17) +
  geom_abline(slope = 1, intercept = 0, linetype = "dashed") +
  labs(
    title = "Perbandingan Nilai Aktual vs Prediksi DO",
    x = "DO Aktual",
    y = "DO Prediksi",
    color = "Model"
  ) +
  theme_minimal()

Plot perbandingan antara nilai aktual DO dan hasil prediksi memperlihatkan bahwa sebaran titik prediksi dari kedua model cenderung mendekati garis diagonal, meskipun tidak terlalu rapat.

Artinya, prediksi DO cenderung mendekati nilai aktual, tetapi masih terdapat penyimpangan yang cukup besar terutama di beberapa titik ekstrem.

Model linear menghasilkan distribusi prediksi yang lebih stabil dibandingkan model spline.

4) Analisis dan Interpretasi Variabel

summary(lm_model)$coefficients
##                  Estimate  Std. Error     t value     Pr(>|t|)
## (Intercept)  5.8944142390 1.052488498  5.60045478 5.926828e-08
## pH          -0.0488955018 0.127006888 -0.38498307 7.005967e-01
## BOD          0.1687462868 0.079364827  2.12620998 3.452423e-02
## TSS          0.0002083945 0.006638268  0.03139291 9.749827e-01
## Suhu        -0.0036443269 0.014049037 -0.25940048 7.955524e-01

Berdasarkan hasil regresi linear:

  • BOD berpengaruh positif signifikan terhadap DO (p = 0.0345), artinya semakin tinggi nilai BOD, nilai DO cenderung meningkat sedikit. Namun secara teori, hubungan ini bisa berbeda tergantung kondisi perairan (karena peningkatan BOD biasanya menurunkan DO akibat konsumsi oksigen oleh mikroorganisme).

  • pH, TSS, dan Suhu tidak menunjukkan pengaruh signifikan terhadap DO dalam model ini.

Secara umum, model menunjukkan bahwa variabel-variabel ini belum cukup kuat untuk memprediksi DO secara akurat, dan dibutuhkan penambahan variabel lain seperti kadar nitrat, amonia, atau kecepatan arus air untuk meningkatkan performa model.