options(repos = c(CRAN = "https://cloud.r-project.org"))
library(readxl)
## Warning: package 'readxl' was built under R version 4.4.3
library(readxl)
data <- read_excel("C:/Users/Cahya Alam/OneDrive/Semester 5/Statistika Lingkungan/kualitasair.xlsx")
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
colSums(is.na(data))
## Lokasi     pH     DO    BOD    TSS   Suhu Status 
##      0      0     23     22     24      0      0
# Imputasi missing value dengan median
num_vars <- c("pH", "DO", "BOD", "TSS", "Suhu")

for (v in num_vars) {
  med <- median(data[[v]], na.rm = TRUE)
  data[[v]][is.na(data[[v]])] <- med
}

# Cek ulang
colSums(is.na(data))
## Lokasi     pH     DO    BOD    TSS   Suhu Status 
##      0      0      0      0      0      0      0
install.packages(c("readxl", "dplyr", "ggplot2", "caret", 
                   "e1071", "rpart", "rpart.plot", "randomForest", 
                   "splines", "writexl")) 
## Warning: package 'readxl' is in use and will not be installed
## Installing packages into 'C:/Users/Cahya Alam/AppData/Local/R/win-library/4.4'
## (as 'lib' is unspecified)
## Warning: package 'splines' is a base package, and should not be updated
## package 'dplyr' successfully unpacked and MD5 sums checked
## package 'ggplot2' successfully unpacked and MD5 sums checked
## package 'caret' successfully unpacked and MD5 sums checked
## package 'e1071' successfully unpacked and MD5 sums checked
## package 'rpart' successfully unpacked and MD5 sums checked
## Warning: cannot remove prior installation of package 'rpart'
## Warning in file.copy(savedcopy, lib, recursive = TRUE): problem copying
## C:\Users\Cahya
## Alam\AppData\Local\R\win-library\4.4\00LOCK\rpart\libs\x64\rpart.dll to
## C:\Users\Cahya Alam\AppData\Local\R\win-library\4.4\rpart\libs\x64\rpart.dll:
## Permission denied
## Warning: restored 'rpart'
## package 'rpart.plot' successfully unpacked and MD5 sums checked
## package 'randomForest' successfully unpacked and MD5 sums checked
## package 'writexl' successfully unpacked and MD5 sums checked
## 
## The downloaded binary packages are in
##  C:\Users\Cahya Alam\AppData\Local\Temp\RtmpOK90Fu\downloaded_packages
library(readxl)
library(dplyr)
## Warning: package 'dplyr' was built under R version 4.4.3
## 
## 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
library(ggplot2)
## Warning: package 'ggplot2' was built under R version 4.4.3
library(caret)
## Warning: package 'caret' was built under R version 4.4.3
## Loading required package: lattice
library(e1071)
## Warning: package 'e1071' was built under R version 4.4.3
## 
## Attaching package: 'e1071'
## The following object is masked from 'package:ggplot2':
## 
##     element
library(rpart)
## Warning: package 'rpart' was built under R version 4.4.3
library(rpart.plot)
## Warning: package 'rpart.plot' was built under R version 4.4.3
library(randomForest)
## Warning: package 'randomForest' was built under R version 4.4.3
## 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
library(splines)
library(writexl)
## Warning: package 'writexl' was built under R version 4.4.3
data <- read_excel("C:/Users/Cahya Alam/OneDrive/Semester 5/Statistika Lingkungan/kualitasair.xlsx")
num_vars <- c("pH","DO","BOD","TSS","Suhu")
for (v in num_vars) {
  med <- median(data[[v]], na.rm = TRUE)
  data[[v]][is.na(data[[v]])] <- med
}
set.seed(123)
index <- createDataPartition(data$DO, p = 0.7, list = FALSE)
train_reg <- data[index, ]
test_reg <- data[-index, ]
nrow(train_reg)
## [1] 212
nrow(test_reg)
## [1] 88

SOAL 1 — Data Cleaning & Eksplorasi (30%)

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

Menstandarkan Kategori “Status”

data$Status <- as.character(data$Status)
data$Status <- trimws(data$Status)

data$Status <- case_when(
data$Status %in% c("1", "Baik", "baik", "BAIK") ~ "Baik",
data$Status %in% c("2", "Tercemar ringan", "tercemar ringan") ~ "Tercemar_ringan",
data$Status %in% c("3", "Tercemar berat", "tercemar berat") ~ "Tercemar_berat",
TRUE ~ data$Status
)

data$Status <- factor(data$Status, levels = c("Baik","Tercemar_ringan","Tercemar_berat"))
table(data$Status)
## 
##            Baik Tercemar_ringan  Tercemar_berat 
##              72             220               7

Kategori pada kolom Status diseragamkan menjadi tiga kelompok utama.

Deteksi Outlier

par(mfrow = c(2,3))
for(v in num_vars){
boxplot(data[[v]], main = v, col = "skyblue4")
}
par(mfrow = c(1,1))

Boxplot menunjukkan distribusi data dan kemungkinan adanya nilai ekstrem pada variabel seperti BOD atau TSS.

Statistik Deskriptif

summary(data[num_vars])
##        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

Ringkasan statistik membantu memahami sebaran nilai tiap variabel setelah proses pembersihan data.

Soal 2 — Klasifikasi Status Kualitas Air (35%)

2.1 Split Data (70% Training, 30% Testing)

set.seed(123)
train_index <- createDataPartition(data$Status, p = 0.7, list = FALSE)
train <- data[train_index, ]
test <- data[-train_index, ]

Dataset dibagi agar model dapat dilatih pada data berbeda dari data yang digunakan untuk evaluasi.

2.2 Model Support Vector Machine (SVM)

svm_model <- svm(Status ~ pH + DO + BOD + TSS + Suhu, data = train, kernel = "radial")
svm_pred <- predict(svm_model, test)
confusionMatrix(svm_pred, test$Status)
## Confusion Matrix and Statistics
## 
##                  Reference
## Prediction        Baik Tercemar_ringan Tercemar_berat
##   Baik              11               0              0
##   Tercemar_ringan   10              66              2
##   Tercemar_berat     0               0              0
## 
## Overall Statistics
##                                           
##                Accuracy : 0.8652          
##                  95% CI : (0.7763, 0.9283)
##     No Information Rate : 0.7416          
##     P-Value [Acc > NIR] : 0.003614        
##                                           
##                   Kappa : 0.5799          
##                                           
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: Baik Class: Tercemar_ringan Class: Tercemar_berat
## Sensitivity               0.5238                 1.0000               0.00000
## Specificity               1.0000                 0.4783               1.00000
## Pos Pred Value            1.0000                 0.8462                   NaN
## Neg Pred Value            0.8718                 1.0000               0.97753
## Prevalence                0.2360                 0.7416               0.02247
## Detection Rate            0.1236                 0.7416               0.00000
## Detection Prevalence      0.1236                 0.8764               0.00000
## Balanced Accuracy         0.7619                 0.7391               0.50000

Hasil confusion matrix menunjukkan akurasi model SVM dalam mengklasifikasikan status air.

2.3 Model Decision Tree

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

tree_pred <- predict(tree_model, test, type = "class")
confusionMatrix(tree_pred, test$Status)
## Confusion Matrix and Statistics
## 
##                  Reference
## Prediction        Baik Tercemar_ringan Tercemar_berat
##   Baik              18               2              0
##   Tercemar_ringan    3              64              2
##   Tercemar_berat     0               0              0
## 
## Overall Statistics
##                                           
##                Accuracy : 0.9213          
##                  95% CI : (0.8446, 0.9678)
##     No Information Rate : 0.7416          
##     P-Value [Acc > NIR] : 1.554e-05       
##                                           
##                   Kappa : 0.7886          
##                                           
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: Baik Class: Tercemar_ringan Class: Tercemar_berat
## Sensitivity               0.8571                 0.9697               0.00000
## Specificity               0.9706                 0.7826               1.00000
## Pos Pred Value            0.9000                 0.9275                   NaN
## Neg Pred Value            0.9565                 0.9000               0.97753
## Prevalence                0.2360                 0.7416               0.02247
## Detection Rate            0.2022                 0.7191               0.00000
## Detection Prevalence      0.2247                 0.7753               0.00000
## Balanced Accuracy         0.9139                 0.8762               0.50000

Decision Tree mempermudah interpretasi karena menampilkan struktur aturan keputusan yang sederhana.

2.4 Model Random Forest

train <- train %>% filter(complete.cases(.))
test <- test %>% filter(complete.cases(.))
set.seed(123)
rf_model <- randomForest(Status ~ pH + DO + BOD + TSS + Suhu, data = train, ntree = 500, importance = TRUE)
rf_pred <- predict(rf_model, test)
confusionMatrix(rf_pred, test$Status)
## Confusion Matrix and Statistics
## 
##                  Reference
## Prediction        Baik Tercemar_ringan Tercemar_berat
##   Baik              18               2              0
##   Tercemar_ringan    3              64              2
##   Tercemar_berat     0               0              0
## 
## Overall Statistics
##                                           
##                Accuracy : 0.9213          
##                  95% CI : (0.8446, 0.9678)
##     No Information Rate : 0.7416          
##     P-Value [Acc > NIR] : 1.554e-05       
##                                           
##                   Kappa : 0.7886          
##                                           
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: Baik Class: Tercemar_ringan Class: Tercemar_berat
## Sensitivity               0.8571                 0.9697               0.00000
## Specificity               0.9706                 0.7826               1.00000
## Pos Pred Value            0.9000                 0.9275                   NaN
## Neg Pred Value            0.9565                 0.9000               0.97753
## Prevalence                0.2360                 0.7416               0.02247
## Detection Rate            0.2022                 0.7191               0.00000
## Detection Prevalence      0.2247                 0.7753               0.00000
## Balanced Accuracy         0.9139                 0.8762               0.50000
varImpPlot(rf_model)

Random Forest umumnya memiliki akurasi tertinggi karena menggabungkan banyak pohon keputusan dan mengurangi overfitting.

Soal 3 — Prediksi Variabel DO (35%)

3.1 Split Data untuk Regresi

set.seed(123)
index <- createDataPartition(data$DO, p = 0.7, list = FALSE)
train_reg <- data[index, ]
test_reg <- data[-index, ]

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.01836 -0.52678  0.01004  0.67867  2.98760 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  5.601603   1.123864   4.984 1.31e-06 ***
## pH           0.030197   0.134200   0.225    0.822    
## BOD          0.113544   0.080293   1.414    0.159    
## TSS         -0.002318   0.007107  -0.326    0.745    
## Suhu        -0.002632   0.014032  -0.188    0.851    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.9672 on 207 degrees of freedom
## Multiple R-squared:  0.01056,    Adjusted R-squared:  -0.008559 
## F-statistic: 0.5524 on 4 and 207 DF,  p-value: 0.6975
lm_pred <- predict(lm_model, test_reg)

lm_R2 <- cor(test_reg$DO, lm_pred)^2
lm_MSE <- mean((test_reg$DO - lm_pred)^2)
lm_RMSE <- sqrt(lm_MSE)
data.frame(R2 = lm_R2, MSE = lm_MSE, RMSE = lm_RMSE)
##             R2       MSE      RMSE
## 1 4.109829e-05 0.9184745 0.9583707

Regresi linear digunakan untuk melihat hubungan langsung antara DO dan variabel prediktor lain.

Regresi Spline

spline_model <- lm(DO ~ bs(pH, df=4) + bs(BOD, df=4) + bs(TSS, df=4) + bs(Suhu, df=4),
data = train_reg)
summary(spline_model)
## 
## Call:
## lm(formula = DO ~ bs(pH, df = 4) + bs(BOD, df = 4) + bs(TSS, 
##     df = 4) + bs(Suhu, df = 4), data = train_reg)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -2.93317 -0.53864  0.05054  0.57224  2.49048 
## 
## Coefficients:
##                    Estimate Std. Error t value Pr(>|t|)    
## (Intercept)        6.122428   1.178196   5.196  5.1e-07 ***
## bs(pH, df = 4)1    0.365184   1.041616   0.351 0.726272    
## bs(pH, df = 4)2   -0.210406   0.724565  -0.290 0.771827    
## bs(pH, df = 4)3    0.226620   0.940485   0.241 0.809838    
## bs(pH, df = 4)4    0.557867   0.898888   0.621 0.535575    
## bs(BOD, df = 4)1   0.998118   1.004977   0.993 0.321856    
## bs(BOD, df = 4)2   0.708918   0.710980   0.997 0.319952    
## bs(BOD, df = 4)3   0.457214   0.983944   0.465 0.642683    
## bs(BOD, df = 4)4   3.218174   0.945943   3.402 0.000811 ***
## bs(TSS, df = 4)1  -0.908867   0.871441  -1.043 0.298264    
## bs(TSS, df = 4)2  -0.334627   0.604428  -0.554 0.580469    
## bs(TSS, df = 4)3  -0.634775   0.815674  -0.778 0.437381    
## bs(TSS, df = 4)4  -1.290065   0.791708  -1.629 0.104828    
## bs(Suhu, df = 4)1 -0.277965   0.610200  -0.456 0.649234    
## bs(Suhu, df = 4)2 -2.231997   2.714172  -0.822 0.411883    
## bs(Suhu, df = 4)3 11.308761  22.296081   0.507 0.612582    
## bs(Suhu, df = 4)4 -0.008051   1.048338  -0.008 0.993880    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.9556 on 195 degrees of freedom
## Multiple R-squared:  0.09006,    Adjusted R-squared:  0.01539 
## F-statistic: 1.206 on 16 and 195 DF,  p-value: 0.2659
spline_pred <- predict(spline_model, test_reg)
## Warning in bs(BOD, degree = 3L, knots = 3.0661, Boundary.knots = c(0.6572, :
## some 'x' values beyond boundary knots may cause ill-conditioned bases
## Warning in bs(Suhu, degree = 3L, knots = 28.00415, Boundary.knots = c(23.2896,
## : some 'x' values beyond boundary knots may cause ill-conditioned bases
sp_R2 <- cor(test_reg$DO, spline_pred)^2
sp_MSE <- mean((test_reg$DO - spline_pred)^2)
sp_RMSE <- sqrt(sp_MSE)
data.frame(R2 = sp_R2, MSE = sp_MSE, RMSE = sp_RMSE)
##             R2       MSE      RMSE
## 1 1.223294e-05 0.9537181 0.9765849

Regresi spline memberikan fleksibilitas lebih besar untuk menangkap hubungan non-linear antar variabel.

Visualisasi Prediksi vs Aktual

ggplot(data.frame(Aktual = test_reg$DO, Prediksi = lm_pred),
aes(x = Aktual, y = Prediksi)) +
geom_point(color = "steelblue") +
geom_abline(intercept = 0, slope = 1, color = "darkred", linetype = "dashed") +
labs(title = "Linear Regression: DO Aktual vs Prediksi", x = "Aktual", y = "Prediksi") +
theme_minimal()

ggplot(data.frame(Aktual = test_reg$DO, Prediksi = spline_pred),
aes(x = Aktual, y = Prediksi)) +
geom_point(color = "darkgreen") +
geom_abline(intercept = 0, slope = 1, color = "darkred", linetype = "dashed") +
labs(title = "Spline Regression: DO Aktual vs Prediksi", x = "Aktual", y = "Prediksi") +
theme_minimal()

Titik-titik yang dekat dengan garis diagonal menunjukkan hasil prediksi mendekati nilai aktual.

# Simpan hasil prediksi ke spreadsheet (Excel)

hasil_prediksi <- data.frame(
  Aktual_DO = test_reg$DO,
  Prediksi_Linear = lm_pred,
  Prediksi_Spline = spline_pred
)

write_xlsx(hasil_prediksi, "hasil_prediksi_DO_75baris.xlsx")
hasil_status <- data.frame(
  Lokasi = test$Lokasi,
  Status_Aktual = test$Status,
  Status_Prediksi = rf_pred
)

write_xlsx(hasil_status, "hasil_prediksi_status.xlsx")
View(hasil_prediksi)
library(writexl)

hasil_prediksi_status <- data.frame(Status_Prediksi = rf_pred)

write_xlsx(hasil_prediksi_status, "Status_Prediksi_75baris.xlsx")

View(hasil_prediksi_status)
write_xlsx(hasil_status, "Hasil_Prediksi_Status_Kualitas_Air.xlsx")
  library(writexl)
# Tampilkan hasil prediksi status langsung di RStudio
hasil_status <- data.frame(Status_Prediksi = rf_pred)

View(hasil_status)   # buka tabel di RStudio

# Print di console juga biar bisa copy dari sana
print(hasil_status)
##    Status_Prediksi
## 1  Tercemar_ringan
## 2  Tercemar_ringan
## 3             Baik
## 4  Tercemar_ringan
## 5  Tercemar_ringan
## 6  Tercemar_ringan
## 7  Tercemar_ringan
## 8  Tercemar_ringan
## 9             Baik
## 10 Tercemar_ringan
## 11 Tercemar_ringan
## 12 Tercemar_ringan
## 13 Tercemar_ringan
## 14 Tercemar_ringan
## 15 Tercemar_ringan
## 16            Baik
## 17 Tercemar_ringan
## 18            Baik
## 19            Baik
## 20 Tercemar_ringan
## 21 Tercemar_ringan
## 22 Tercemar_ringan
## 23            Baik
## 24 Tercemar_ringan
## 25 Tercemar_ringan
## 26 Tercemar_ringan
## 27 Tercemar_ringan
## 28            Baik
## 29 Tercemar_ringan
## 30            Baik
## 31 Tercemar_ringan
## 32 Tercemar_ringan
## 33            Baik
## 34 Tercemar_ringan
## 35 Tercemar_ringan
## 36 Tercemar_ringan
## 37 Tercemar_ringan
## 38 Tercemar_ringan
## 39 Tercemar_ringan
## 40 Tercemar_ringan
## 41 Tercemar_ringan
## 42 Tercemar_ringan
## 43            Baik
## 44 Tercemar_ringan
## 45 Tercemar_ringan
## 46 Tercemar_ringan
## 47            Baik
## 48 Tercemar_ringan
## 49            Baik
## 50 Tercemar_ringan
## 51            Baik
## 52 Tercemar_ringan
## 53 Tercemar_ringan
## 54            Baik
## 55            Baik
## 56 Tercemar_ringan
## 57 Tercemar_ringan
## 58            Baik
## 59 Tercemar_ringan
## 60 Tercemar_ringan
## 61 Tercemar_ringan
## 62 Tercemar_ringan
## 63 Tercemar_ringan
## 64 Tercemar_ringan
## 65 Tercemar_ringan
## 66            Baik
## 67 Tercemar_ringan
## 68 Tercemar_ringan
## 69 Tercemar_ringan
## 70 Tercemar_ringan
## 71 Tercemar_ringan
## 72            Baik
## 73 Tercemar_ringan
## 74 Tercemar_ringan
## 75 Tercemar_ringan
## 76 Tercemar_ringan
## 77 Tercemar_ringan
## 78            Baik
## 79 Tercemar_ringan
## 80 Tercemar_ringan
## 81 Tercemar_ringan
## 82 Tercemar_ringan
## 83 Tercemar_ringan
## 84 Tercemar_ringan
## 85 Tercemar_ringan
## 86 Tercemar_ringan
## 87            Baik
## 88 Tercemar_ringan
## 89 Tercemar_ringan
# ===============================
# 🔮 HASIL PREDIKSI STATUS (75 BARIS)
hasil_status <- data.frame(Status_Prediksi = rf_pred)
hasil_status <- head(hasil_status, 75)
View(hasil_status)
cat(paste(hasil_status$Status_Prediksi, collapse = "\n"))
## Tercemar_ringan
## Tercemar_ringan
## Baik
## Tercemar_ringan
## Tercemar_ringan
## Tercemar_ringan
## Tercemar_ringan
## Tercemar_ringan
## Baik
## Tercemar_ringan
## Tercemar_ringan
## Tercemar_ringan
## Tercemar_ringan
## Tercemar_ringan
## Tercemar_ringan
## Baik
## Tercemar_ringan
## Baik
## Baik
## Tercemar_ringan
## Tercemar_ringan
## Tercemar_ringan
## Baik
## Tercemar_ringan
## Tercemar_ringan
## Tercemar_ringan
## Tercemar_ringan
## Baik
## Tercemar_ringan
## Baik
## Tercemar_ringan
## Tercemar_ringan
## Baik
## Tercemar_ringan
## Tercemar_ringan
## Tercemar_ringan
## Tercemar_ringan
## Tercemar_ringan
## Tercemar_ringan
## Tercemar_ringan
## Tercemar_ringan
## Tercemar_ringan
## Baik
## Tercemar_ringan
## Tercemar_ringan
## Tercemar_ringan
## Baik
## Tercemar_ringan
## Baik
## Tercemar_ringan
## Baik
## Tercemar_ringan
## Tercemar_ringan
## Baik
## Baik
## Tercemar_ringan
## Tercemar_ringan
## Baik
## Tercemar_ringan
## Tercemar_ringan
## Tercemar_ringan
## Tercemar_ringan
## Tercemar_ringan
## Tercemar_ringan
## Tercemar_ringan
## Baik
## Tercemar_ringan
## Tercemar_ringan
## Tercemar_ringan
## Tercemar_ringan
## Tercemar_ringan
## Baik
## Tercemar_ringan
## Tercemar_ringan
## Tercemar_ringan
cat("\n\nJumlah baris yang ditampilkan:", nrow(hasil_status), "\n")
## 
## 
## Jumlah baris yang ditampilkan: 75

```