# Load library yang diperlukan
library(dplyr)
## Warning: package 'dplyr' was built under R version 4.3.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.3.3

DATA PREPROCESSING

Import Data

# Baca data dari file CSV
file_path <- "D:/3SD2/SEMESTER 6/Datmin/P2/bank latih.csv"
databank <- read.csv(file_path, stringsAsFactors = FALSE)
View(databank)
head(databank)

Eksplorasi Awal

Eksplorasi data adalah tahap awal dalam analisis data yang bertujuan untuk memahami karakteristik dataset sebelum melakukan preprocessing atau modeling. Tujuan utama dari eksplorasi data meliputi: - Mengetahui jumlah observasi dan variabel dalam dataset. - Memahami tipe data dari setiap variabel. - Mengidentifikasi data yang hilang atau tidak sesuai. - Menilai distribusi data menggunakan statistik deskriptif.

#Mengecek jumlah observasi (baris) dan atribut/variabel (kolom)
dim(databank) # Menampilkan jumlah baris dan kolom
## [1] 4521   17
# Mengecek tipe data dari tiap variabel 
str(databank)  # Cek struktur data
## 'data.frame':    4521 obs. of  17 variables:
##  $ Age      : int  30 33 35 30 59 35 36 39 41 43 ...
##  $ job      : chr  "unemployed" "services" "management" "management" ...
##  $ marital  : chr  "married" "married" "single" "married" ...
##  $ education: chr  "primary" "secondary" "tertiary" "tertier" ...
##  $ default  : chr  "no" "no" "no" "no" ...
##  $ balance  : int  1787 4789 1350 1476 0 747 307 147 221 -88 ...
##  $ housing  : chr  "no" "yes" "yes" "yes" ...
##  $ loan     : chr  "no" "yes" "no" "yes" ...
##  $ contact  : chr  "cellular" "cellular" "cellular" "unknown" ...
##  $ day      : int  19 11 16 3 5 23 14 6 14 17 ...
##  $ month    : chr  "10" "may" "apr" "jun" ...
##  $ duration : int  79 220 185 199 226 141 341 151 57 313 ...
##  $ campaign : int  1 1 1 4 1 2 1 2 2 1 ...
##  $ pdays    : int  -1 339 330 -1 -1 176 330 -1 -1 147 ...
##  $ previous : int  0 4 1 0 0 3 2 0 0 2 ...
##  $ poutcome : chr  "unknown" "failure" "failure" "unknown" ...
##  $ y        : chr  "no" "no" "no" "no" ...
# Menampilkan ringkasan statistik dari data
summary(databank)
##       Age            job              marital           education        
##  Min.   :19.00   Length:4521        Length:4521        Length:4521       
##  1st Qu.:33.00   Class :character   Class :character   Class :character  
##  Median :39.00   Mode  :character   Mode  :character   Mode  :character  
##  Mean   :41.17                                                           
##  3rd Qu.:49.00                                                           
##  Max.   :87.00                                                           
##    default             balance        housing              loan          
##  Length:4521        Min.   :-3313   Length:4521        Length:4521       
##  Class :character   1st Qu.:   69   Class :character   Class :character  
##  Mode  :character   Median :  444   Mode  :character   Mode  :character  
##                     Mean   : 1423                                        
##                     3rd Qu.: 1480                                        
##                     Max.   :71188                                        
##    contact               day           month              duration   
##  Length:4521        Min.   : 1.00   Length:4521        Min.   :   4  
##  Class :character   1st Qu.: 9.00   Class :character   1st Qu.: 104  
##  Mode  :character   Median :16.00   Mode  :character   Median : 185  
##                     Mean   :15.92                      Mean   : 264  
##                     3rd Qu.:21.00                      3rd Qu.: 329  
##                     Max.   :31.00                      Max.   :3025  
##     campaign          pdays           previous         poutcome        
##  Min.   : 1.000   Min.   : -1.00   Min.   : 0.0000   Length:4521       
##  1st Qu.: 1.000   1st Qu.: -1.00   1st Qu.: 0.0000   Class :character  
##  Median : 2.000   Median : -1.00   Median : 0.0000   Mode  :character  
##  Mean   : 2.794   Mean   : 39.77   Mean   : 0.5426                     
##  3rd Qu.: 3.000   3rd Qu.: -1.00   3rd Qu.: 0.0000                     
##  Max.   :50.000   Max.   :871.00   Max.   :25.0000                     
##       y            
##  Length:4521       
##  Class :character  
##  Mode  :character  
##                    
##                    
## 

Dataset memiliki 4.521 baris dan 17 variabel dengan kombinasi data numerik dan kategorikal.

Data Cleaning

# Cek missing values
missing_summary <- colSums(is.na(databank))

# Summary hasil missing values keseluruhan
print(missing_summary)
##       Age       job   marital education   default   balance   housing      loan 
##         0         0         0         0         0         0         0         0 
##   contact       day     month  duration  campaign     pdays  previous  poutcome 
##         0         0         0         0         0         0         0         0 
##         y 
##         0

Tidak ditemukan missing values di seluruh atribut(kolom)

# Mengubah semua teks menjadi huruf kecil (case folding)
databank <- databank %>%
  mutate(across(where(is.character), tolower))
# Load library yang diperlukan
library(stringr)

# Cek apakah ada tanda titik di seluruh kolom karakter
kolom_karakter <- select(databank, where(is.character))

ada_titik <- sapply(kolom_karakter, function(x) any(grepl("\\.", x)))

# Menampilkan kolom mana saja yang mengandung tanda titik
kolom_dengan_titik <- names(ada_titik[ada_titik == TRUE])
print(paste("Kolom yang mengandung tanda titik:", paste(kolom_dengan_titik, collapse = ", ")))
## [1] "Kolom yang mengandung tanda titik: job"
# Hitung jumlah tanda titik (.) di seluruh kolom job
jumlah_titik <- sum(str_count(databank$job, "\\."))
print(paste("Jumlah tanda titik di kolom job:", jumlah_titik))
## [1] "Jumlah tanda titik di kolom job: 478"
# Menghapus tanda titik dari kolom job
databank <- databank %>%
  mutate(job = gsub("\\.", "", job))

print("Tanda titik pada kolom job telah dihapus")
## [1] "Tanda titik pada kolom job telah dihapus"
# Hitung jumlah tanda titik (.) di seluruh kolom job
jumlah_titik <- sum(str_count(databank$job, "\\."))
print(paste("Jumlah tanda titik di kolom job:", jumlah_titik))
## [1] "Jumlah tanda titik di kolom job: 0"
# Mengecek dan menangani typo 
library(tidyr)
## Warning: package 'tidyr' was built under R version 4.3.3
# Melihat daftar unik dari setiap kolom non-numerik
categorical_cols <- sapply(databank, is.character) # Pilih kolom kategori
databank_categorical <- databank[, categorical_cols]

# Cek nilai unik di setiap kolom kategori
lapply(databank_categorical, unique)
## $job
##  [1] "unemployed"    "services"      "management"    "blue-collar"  
##  [5] "self-employed" "technician"    "entrepreneur"  "admin"        
##  [9] "student"       "housemaid"     "retired"       "unknown"      
## 
## $marital
## [1] "married"  "single"   "menikah"  "divorced"
## 
## $education
## [1] "primary"   "secondary" "tertiary"  "tertier"   "sekunder"  "unknown"  
## 
## $default
## [1] "no"  "yes"
## 
## $housing
## [1] "no"    "yes"   "tidak"
## 
## $loan
## [1] "no"    "yes"   "tidak"
## 
## $contact
## [1] "cellular"  "unknown"   "seluler"   "telephone"
## 
## $month
##  [1] "10"  "may" "apr" "jun" "feb" "aug" "jan" "7"   "nov" "jul" "oct" "sep"
## [13] "mar" "dec"
## 
## $poutcome
## [1] "unknown" "failure" "other"   "success"
## 
## $y
## [1] "no"  "iya" "yes"
# Pilih hanya kolom kategori
categorical_cols <- sapply(databank, is.character)
databank_categorical <- databank[, categorical_cols]

# Loop untuk setiap kolom kategori
for (col in colnames(databank_categorical)) {
  
  # Hitung jumlah kemunculan setiap nilai unik
  count_data <- databank %>%
    count(!!sym(col)) %>%
    arrange(desc(n))  # Urutkan dari terbesar

  # Hitung total keseluruhan
  total_count <- sum(count_data$n)

  # Tentukan lebar maksimum untuk teks kategori
  max_width <- max(nchar(count_data[[col]]), na.rm = TRUE)

  # Cetak header kategori
  cat("\n", col, "\n", strrep("=", nchar(col)), "\n")
  cat(sprintf("%-*s %10s\n", max_width, "Kategori", "Jumlah"))  # Header tabel
  cat(strrep("-", max_width + 12), "\n")  # Garis pemisah

  # Cetak data kategori dengan format rapi
  for (i in 1:nrow(count_data)) {
    cat(sprintf("%-*s %10d\n", max_width, count_data[[col]][i], count_data$n[i]))
  }

  # Cetak total dengan format yang sejajar
  cat(strrep("-", max_width + 12), "\n")
  cat(sprintf("%-*s %10d\n\n", max_width, "Total", total_count))
}
## 
##  job 
##  === 
## Kategori          Jumlah
## ------------------------- 
## management           969
## blue-collar          946
## technician           768
## admin                478
## services             417
## retired              230
## self-employed        183
## entrepreneur         168
## unemployed           128
## housemaid            112
## student               84
## unknown               38
## ------------------------- 
## Total               4521
## 
## 
##  marital 
##  ======= 
## Kategori     Jumlah
## -------------------- 
## married        2796
## single         1196
## divorced        528
## menikah           1
## -------------------- 
## Total          4521
## 
## 
##  education 
##  ========= 
## Kategori      Jumlah
## --------------------- 
## secondary       2305
## tertiary        1349
## primary          678
## unknown          187
## sekunder           1
## tertier            1
## --------------------- 
## Total           4521
## 
## 
##  default 
##  ======= 
## Kategori     Jumlah
## --------------- 
## no        4445
## yes         76
## --------------- 
## Total       4521
## 
## 
##  housing 
##  ======= 
## Kategori     Jumlah
## ----------------- 
## yes         2559
## no          1961
## tidak          1
## ----------------- 
## Total       4521
## 
## 
##  loan 
##  ==== 
## Kategori     Jumlah
## ----------------- 
## no          3829
## yes          691
## tidak          1
## ----------------- 
## Total       4521
## 
## 
##  contact 
##  ======= 
## Kategori      Jumlah
## --------------------- 
## cellular        2895
## unknown         1324
## telephone        301
## seluler            1
## --------------------- 
## Total           4521
## 
## 
##  month 
##  ===== 
## Kategori     Jumlah
## --------------- 
## may       1398
## jul        705
## aug        633
## jun        531
## nov        389
## apr        293
## feb        222
## jan        148
## oct         79
## sep         52
## mar         49
## dec         20
## 10           1
## 7            1
## --------------- 
## Total       4521
## 
## 
##  poutcome 
##  ======== 
## Kategori     Jumlah
## ------------------- 
## unknown       3705
## failure        490
## other          197
## success        129
## ------------------- 
## Total         4521
## 
## 
##  y 
##  = 
## Kategori     Jumlah
## --------------- 
## no        4000
## yes        520
## iya          1
## --------------- 
## Total       4521
library(dplyr)
# Menangani ketidak-konsistenan isian
databank <- databank %>%
  mutate(across(c(marital, education, housing, loan, contact, y, month), as.character)) %>% # Pastikan kolom bertipe karakter
  mutate(across(marital, ~ gsub("menikah", "married", .))) %>%
  mutate(across(education, ~ gsub("sekunder", "secondary", .))) %>%
  mutate(across(education, ~ gsub("tertier", "tertiary", .))) %>%
  mutate(across(housing, ~ gsub("tidak", "no", .))) %>%
  mutate(across(loan, ~ gsub("tidak", "no", .))) %>%
  mutate(across(contact, ~ gsub("seluler", "cellular", .))) %>%
  mutate(across(month, ~ gsub("^10$", "oct", .))) %>%
  mutate(across(month, ~ gsub("^7$", "jul", .))) %>%
  mutate(across(y, ~ gsub("iya", "yes", .)))
# Cek Hasil perubahan
# Pilih hanya kolom kategori
categorical_cols <- sapply(databank, is.character)
databank_categorical <- databank[, categorical_cols]

# Loop untuk setiap kolom kategori
for (col in colnames(databank_categorical)) {
  
  # Hitung jumlah kemunculan setiap nilai unik
  count_data <- databank %>%
    count(!!sym(col)) %>%
    arrange(desc(n))  # Urutkan dari terbesar

  # Hitung total keseluruhan
  total_count <- sum(count_data$n)

  # Tentukan lebar maksimum untuk teks kategori
  max_width <- max(nchar(count_data[[col]]), na.rm = TRUE)

  # Cetak header kategori
  cat("\n", col, "\n", strrep("=", nchar(col)), "\n")
  cat(sprintf("%-*s %10s\n", max_width, "Kategori", "Jumlah"))  # Header tabel
  cat(strrep("-", max_width + 12), "\n")  # Garis pemisah

  # Cetak data kategori dengan format rapi
  for (i in 1:nrow(count_data)) {
    cat(sprintf("%-*s %10d\n", max_width, count_data[[col]][i], count_data$n[i]))
  }

  # Cetak total dengan format yang sejajar
  cat(strrep("-", max_width + 12), "\n")
  cat(sprintf("%-*s %10d\n\n", max_width, "Total", total_count))
}
## 
##  job 
##  === 
## Kategori          Jumlah
## ------------------------- 
## management           969
## blue-collar          946
## technician           768
## admin                478
## services             417
## retired              230
## self-employed        183
## entrepreneur         168
## unemployed           128
## housemaid            112
## student               84
## unknown               38
## ------------------------- 
## Total               4521
## 
## 
##  marital 
##  ======= 
## Kategori     Jumlah
## -------------------- 
## married        2797
## single         1196
## divorced        528
## -------------------- 
## Total          4521
## 
## 
##  education 
##  ========= 
## Kategori      Jumlah
## --------------------- 
## secondary       2306
## tertiary        1350
## primary          678
## unknown          187
## --------------------- 
## Total           4521
## 
## 
##  default 
##  ======= 
## Kategori     Jumlah
## --------------- 
## no        4445
## yes         76
## --------------- 
## Total       4521
## 
## 
##  housing 
##  ======= 
## Kategori     Jumlah
## --------------- 
## yes       2559
## no        1962
## --------------- 
## Total       4521
## 
## 
##  loan 
##  ==== 
## Kategori     Jumlah
## --------------- 
## no        3830
## yes        691
## --------------- 
## Total       4521
## 
## 
##  contact 
##  ======= 
## Kategori      Jumlah
## --------------------- 
## cellular        2896
## unknown         1324
## telephone        301
## --------------------- 
## Total           4521
## 
## 
##  month 
##  ===== 
## Kategori     Jumlah
## --------------- 
## may       1398
## jul        706
## aug        633
## jun        531
## nov        389
## apr        293
## feb        222
## jan        148
## oct         80
## sep         52
## mar         49
## dec         20
## --------------- 
## Total       4521
## 
## 
##  poutcome 
##  ======== 
## Kategori     Jumlah
## ------------------- 
## unknown       3705
## failure        490
## other          197
## success        129
## ------------------- 
## Total         4521
## 
## 
##  y 
##  = 
## Kategori     Jumlah
## --------------- 
## no        4000
## yes        521
## --------------- 
## Total       4521
# Mengecek rule validasi
# Cek nilai negatif di kolom Age
invalid_age <- databank %>% filter(Age < 0)
if (nrow(invalid_age) > 0) {
  print("Ditemukan nilai negatif di kolom Age:")
  print(invalid_age)
} else {
  print("Tidak ada nilai negatif di kolom Age.")
}
## [1] "Tidak ada nilai negatif di kolom Age."
# Cek nilai negatif di kolom duration
invalid_duration <- databank %>% filter(duration < 0)
if (nrow(invalid_duration) > 0) {
  print("Ditemukan nilai negatif di kolom duration:")
  print(invalid_duration)
} else {
  print("Tidak ada nilai negatif di kolom duration.")
}
## [1] "Tidak ada nilai negatif di kolom duration."
## Definisikan jumlah hari maksimum untuk setiap bulan
max_days <- c("jan" = 31, "feb" = 29, "mar" = 31, "apr" = 30, 
              "may" = 31, "jun" = 30, "jul" = 31, "aug" = 31, 
              "sep" = 30, "oct" = 31, "nov" = 30, "dec" = 31)

# Pastikan day bertipe numerik
databank <- databank %>%
  mutate(day = as.integer(day))

# Filter baris yang memiliki tanggal tidak valid tanpa menambahkan kolom baru
invalid_rows <- databank %>%
  filter(!(day >= 1 & day <= max_days[tolower(month)]))

# Cek hasil validasi
if(nrow(invalid_rows) > 0) {
  print("Ada data yang tidak valid:")
  print(invalid_rows)
} else {
  print("Semua data valid!")
}
## [1] "Semua data valid!"
# Cek duplikasi data
duplikasi <- sum(duplicated(databank))

print(paste("Jumlah baris duplikat:", duplikasi))
## [1] "Jumlah baris duplikat: 0"
# Cek Outlier 

# Visualisasi outlier dengan boxplot untuk semua variabel numerik
numeric_cols <- sapply(databank, is.numeric) # Pilih kolom numerik
databank_numeric <- databank[, numeric_cols]

# Plot boxplot untuk melihat outlier
boxplot(databank_numeric, main = "Deteksi Outlier", col = "skyblue", outline = TRUE)

# Fungsi untuk mendeteksi outlier dengan metode IQR
detect_outliers <- function(x) {
  Q1 <- quantile(x, 0.25, na.rm = TRUE)
  Q3 <- quantile(x, 0.75, na.rm = TRUE)
  IQR <- Q3 - Q1
  lower_bound <- Q1 - 1.5 * IQR
  upper_bound <- Q3 + 1.5 * IQR
  return(x < lower_bound | x > upper_bound)
}

# Menerapkan fungsi ke semua kolom numerik
outlier_matrix <- as.data.frame(sapply(databank_numeric, detect_outliers))

# Menampilkan jumlah outlier per kolom
colSums(outlier_matrix)
##      Age  balance      day duration campaign    pdays previous 
##       38      506        0      330      318      816      816

Outlier disini belum bisa ditangani karena diasumsikan memiliki makna penting untuk data bank seperti jika ingin menganalisis saldo rekening (balance) pelanggan bank, outlier bisa mewakili nasabah kaya (high-net-worth individuals). Menghapusnya bisa menghilangkan wawasan penting.

Data Reduction

Reduksi Data: Menghasilkan representasi data yang lebih kecil dengan meminimalkan kehilangan informasi. Metodenya meliputi: â—‹ Reduksi Dimensionalitas: Mengurangi jumlah atribut menggunakan metode seperti PCA, pemilihan subset atribut, dan transformasi wavelet. â—‹ Reduksi Numerositas: Menggunakan model parametrik (seperti regresi) dan nonparametrik (seperti histogram dan clustering). â—‹ Kompresi Data: Mengurangi ukuran data dengan metode lossless atau lossy.

Berikut ini dilakukan reduksi data (data reduction) dengan fokus pada pemilihan variabel (feature selection) menggunakan korelasi antar variabel numerik dan uji multikolinearitas dengan Variance Inflation Factor (VIF). Nantinya, hasil ini dapat berguna untuk melakukan metode reduksi dimensionalitas seperti PCA.

Reduksi Dimensionalitas

# Feature Selection (Pemilihan Variabel)
# 1. Cek Korelasi antar variabel numerik
library(corrplot)
## corrplot 0.92 loaded
cor_matrix <- cor(databank %>% select_if(is.numeric))
corrplot(cor_matrix, method = "color")

# Pilih hanya variabel numerik
num_vars <- databank %>% select_if(is.numeric)

# Hitung matriks korelasi
cor_matrix <- cor(num_vars, use = "pairwise.complete.obs")

# Tampilkan matriks korelasi dengan angka desimal 3 digit
print(round(cor_matrix, 3))
##             Age balance    day duration campaign  pdays previous
## Age       1.000   0.084 -0.018   -0.002   -0.005 -0.009   -0.004
## balance   0.084   1.000 -0.009   -0.016   -0.010  0.009    0.026
## day      -0.018  -0.009  1.000   -0.025    0.161 -0.094   -0.059
## duration -0.002  -0.016 -0.025    1.000   -0.068  0.010    0.018
## campaign -0.005  -0.010  0.161   -0.068    1.000 -0.093   -0.068
## pdays    -0.009   0.009 -0.094    0.010   -0.093  1.000    0.578
## previous -0.004   0.026 -0.059    0.018   -0.068  0.578    1.000
# Load library yang dibutuhkan
library(car)
## Warning: package 'car' was built under R version 4.3.3
## Loading required package: carData
## Warning: package 'carData' was built under R version 4.3.3
## 
## Attaching package: 'car'
## The following object is masked from 'package:dplyr':
## 
##     recode
# Pastikan y ada di databank dan bertipe numerik atau faktor biner (0/1)
databank$y <- ifelse(databank$y == "yes", 1, 0)

# Pilih hanya variabel numerik dari databank
num_vars <- databank[, sapply(databank, is.numeric)]

# Hapus baris dengan NA agar panjang variabel sama
num_vars <- na.omit(num_vars)

# Cek apakah semua variabel memiliki jumlah baris yang sama
if (nrow(num_vars) > 0 && all(sapply(num_vars, length) == nrow(num_vars))) {
  # Model regresi untuk menghitung VIF
  model <- lm(y ~ ., data = num_vars)  # Pastikan y ada dalam num_vars
  
  # Hitung VIF
  vif_values <- vif(model)
  
  # Tampilkan hasil VIF
  print(vif_values)
} else {
  print("Error: Ada masalah dengan panjang variabel atau dataset kosong!")
}
##      Age  balance      day duration campaign    pdays previous 
## 1.007513 1.008210 1.033819 1.005384 1.037721 1.513716 1.502266

Hasil dari corrplot menunjukkan bahwa Mayoritas nilai korelasi rendah, yang artinya tidak ada hubungan linear yang kuat antara variabel-variabel ini. Lalu, Tidak ada indikasi kuat multikolinearitas karena semua VIF di bawah 5. Oleh karena nilai korelasi rendah dan tidak ada multikoleniaritas, maka tidak perlu dilakukan reduksi dimensionalitas.

Berikut ini dicoba untuk melakukan reduksi Numerositas dengan teknik clustering #### Reduksi Numerositas

# Load library yang diperlukan
library(tidyverse)  # Untuk manipulasi data
## Warning: package 'tidyverse' was built under R version 4.3.3
## Warning: package 'purrr' was built under R version 4.3.3
## Warning: package 'lubridate' was built under R version 4.3.3
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ forcats   1.0.0     ✔ readr     2.1.5
## ✔ lubridate 1.9.3     ✔ tibble    3.2.1
## ✔ purrr     1.0.2     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ✖ car::recode()   masks dplyr::recode()
## ✖ purrr::some()   masks car::some()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(cluster)     # Untuk analisis clustering
## Warning: package 'cluster' was built under R version 4.3.3
library(factoextra)  # Untuk visualisasi clustering
## Warning: package 'factoextra' was built under R version 4.3.3
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
# 📌 2. Preprocessing Data: Pilih hanya variabel numerik
num_vars <- databank %>% select_if(is.numeric)

# Normalisasi Data (agar skala variabel seragam)
num_vars_scaled <- scale(num_vars)

# 📌 3. Tentukan jumlah cluster optimal dengan metode Elbow
# Metode Elbow dengan garis penanda
fviz_nbclust(num_vars_scaled, kmeans, method = "wss") + 
  geom_vline(xintercept = 7, linetype = "dashed", color = "red") + # Garis merah di elbow
  labs(title = "Metode Elbow dengan Penanda Optimal Cluster")

# 📌 4. Jalankan K-Means Clustering
set.seed(123)  # Untuk hasil yang reproducible
kmeans_result <- kmeans(num_vars_scaled, centers = 7, nstart = 25)  # Sesuaikan jumlah cluster

# Tambahkan hasil cluster ke data asli
databank$Cluster <- as.factor(kmeans_result$cluster)

# 📌 5. Visualisasi hasil clustering
fviz_cluster(kmeans_result, data = num_vars_scaled,
             geom = "point", ellipse.type = "convex") +
  ggtitle("Hasil Clustering dengan K-Means")

# 📌 6. Lihat karakteristik tiap cluster
summary(databank %>% group_by(Cluster))
##       Age            job              marital           education        
##  Min.   :19.00   Length:4521        Length:4521        Length:4521       
##  1st Qu.:33.00   Class :character   Class :character   Class :character  
##  Median :39.00   Mode  :character   Mode  :character   Mode  :character  
##  Mean   :41.17                                                           
##  3rd Qu.:49.00                                                           
##  Max.   :87.00                                                           
##                                                                          
##    default             balance        housing              loan          
##  Length:4521        Min.   :-3313   Length:4521        Length:4521       
##  Class :character   1st Qu.:   69   Class :character   Class :character  
##  Mode  :character   Median :  444   Mode  :character   Mode  :character  
##                     Mean   : 1423                                        
##                     3rd Qu.: 1480                                        
##                     Max.   :71188                                        
##                                                                          
##    contact               day           month              duration   
##  Length:4521        Min.   : 1.00   Length:4521        Min.   :   4  
##  Class :character   1st Qu.: 9.00   Class :character   1st Qu.: 104  
##  Mode  :character   Median :16.00   Mode  :character   Median : 185  
##                     Mean   :15.92                      Mean   : 264  
##                     3rd Qu.:21.00                      3rd Qu.: 329  
##                     Max.   :31.00                      Max.   :3025  
##                                                                      
##     campaign          pdays           previous         poutcome        
##  Min.   : 1.000   Min.   : -1.00   Min.   : 0.0000   Length:4521       
##  1st Qu.: 1.000   1st Qu.: -1.00   1st Qu.: 0.0000   Class :character  
##  Median : 2.000   Median : -1.00   Median : 0.0000   Mode  :character  
##  Mean   : 2.794   Mean   : 39.77   Mean   : 0.5426                     
##  3rd Qu.: 3.000   3rd Qu.: -1.00   3rd Qu.: 0.0000                     
##  Max.   :50.000   Max.   :871.00   Max.   :25.0000                     
##                                                                        
##        y          Cluster 
##  Min.   :0.0000   1: 164  
##  1st Qu.:0.0000   2: 933  
##  Median :0.0000   3:1218  
##  Mean   :0.1152   4: 137  
##  3rd Qu.:0.0000   5: 499  
##  Max.   :1.0000   6: 484  
##                   7:1086
head(databank)

Data Transformation and Data Discretization

Transformasi data adalah mengubah data menjadi bentuk yang lebih sesuai untuk data mining. Salah satu strategi dari transformasi data adalah dengan Discretization: Mengonversi nilai numerik menjadi label interval (misalnya usia: 0–10, 11–20) atau label konseptual (muda, dewasa, lansia).

# Mendiskretisasi data usia (Age) 
databank <- databank %>%
  mutate(age_group = cut(Age, breaks = c(0, 25, 40, 60, Inf), labels = c("Young", "Adult", "Middle-aged", "Senior")))
head(databank)

Encoding variabel kategorik menjadi variabel numerik

# Encoding variabel job
databank$job <- factor(databank$job, 
                        levels = c("management", "blue-collar", "technician", "admin",
                                   "services", "retired", "self-employed", "entrepreneur",
                                   "unemployed", "housemaid", "student", "unknown"),
                        labels = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12))

# Encoding variabel marital
databank$marital <- factor(databank$marital, 
                            levels = c("married", "single", "divorced"), 
                            labels = c(1, 2, 3))

# Encoding variabel education
databank$education <- factor(databank$education, 
                              levels = c("secondary", "tertiary", "primary", "unknown"), 
                              labels = c(1, 2, 3, 4))

# Encoding variabel default
databank$default <- factor(databank$default, 
                            levels = c("no", "yes"), 
                            labels = c(0, 1))

# Encoding variabel housing
databank$housing <- factor(databank$housing, 
                            levels = c("no", "yes"), 
                            labels = c(0, 1))

# Encoding variabel loan
databank$loan <- factor(databank$loan, 
                         levels = c("no", "yes"), 
                         labels = c(0, 1))

# Encoding variabel contact
databank$contact <- factor(databank$contact, 
                            levels = c("cellular", "unknown", "telephone"), 
                            labels = c(1, 2, 3))

# Encoding variabel month
databank$month <- factor(databank$month, 
                          levels = c("jan", "feb", "mar", "apr", "may", "jun", "jul", 
                                     "aug", "sep", "oct", "nov", "dec"), 
                          labels = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12))

# Encoding variabel poutcome
databank$poutcome <- factor(databank$poutcome, 
                             levels = c("unknown", "failure", "other", "success"), 
                             labels = c(1, 2, 3, 4))

# Menampilkan heading data setelah encoding
head(databank)
# Simpan hasil preprocessing tanpa kolom Age
write.csv(databank %>% select(-Age), 
          "D:/3SD2/SEMESTER 6/Datmin/P2/prepro_databank.csv", 
          row.names = FALSE)

print("Preprocessing selesai! Data telah disimpan sebagai prepro_databank.csv tanpa kolom Age.")
## [1] "Preprocessing selesai! Data telah disimpan sebagai prepro_databank.csv tanpa kolom Age."