# ============================================================
# LANGKAH 1 — LOAD PACKAGE
# ============================================================
library(readxl)
## Warning: package 'readxl' was built under R version 4.4.3
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(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(caret)
## Warning: package 'caret' was built under R version 4.4.3
## Loading required package: ggplot2
## Warning: package 'ggplot2' was built under R version 4.4.3
## Loading required package: lattice
## Warning: package 'lattice' was built under R version 4.4.3
## New names:
## • `` -> `...2`
## • `` -> `...3`
## • `` -> `...4`
## • `` -> `...5`
## • `` -> `...6`
## • `` -> `...7`
## • `` -> `...8`
## • `` -> `...9`
## • `` -> `...10`
## • `` -> `...11`
## • `` -> `...12`
## • `` -> `...13`
## • `` -> `...14`
## • `` -> `...15`
## • `` -> `...16`
## • `` -> `...17`
## • `` -> `...18`
## Jumlah data awal : 897
# ============================================================
# LANGKAH 3 — CEK NAMA KOLOM
# ============================================================
names(data_awal)
## [1] "2023" "...2" "...3" "...4" "...5" "...6" "...7" "...8" "...9"
## [10] "...10" "...11" "...12" "...13" "...14" "...15" "...16" "...17" "...18"
# ============================================================
# LANGKAH 4 — CEK STRUKTUR DATA
# ============================================================
str(data_awal)
## tibble [897 × 18] (S3: tbl_df/tbl/data.frame)
## $ 2023 : chr [1:897] "JANUARI" "No" "1" "2" ...
## $ ...2 : chr [1:897] NA "Nama Sales" "DHEVY" "MUS MAULANA" ...
## $ ...3 : chr [1:897] NA "Nama Debitur" "RESTU BUDIONO" "ABDUL CHAFID" ...
## $ ...4 : chr [1:897] NA "Tanggal Masuk Berkas" "44921" "44922" ...
## $ ...5 : chr [1:897] NA "Tanggal di Analisis" "44921" "44922" ...
## $ ...6 : chr [1:897] NA "Segmen FIX/ Non Fix" "FIX INCOME" "FIX INCOME" ...
## $ ...7 : chr [1:897] NA "Produk" "BNI GRIYA" "BNI GRIYA" ...
## $ ...8 : chr [1:897] NA "Maximum Permohonan" "450000000" "1000000000" ...
## $ ...9 : chr [1:897] NA "Permohonan Jangka Waktu" "120" "180" ...
## $ ...10: chr [1:897] NA "Instansi Bekrja" "NES GLOBAL" "TOP UP" ...
## $ ...11: chr [1:897] NA "Analis" "ERIKA" "KIRMAN" ...
## $ ...12: chr [1:897] NA "TGL USUL/TGL KELUAR" "44928" "44929" ...
## $ ...13: chr [1:897] NA "Nominal Keputusan" "425000000" "1000000000" ...
## $ ...14: chr [1:897] NA "Jangka Waktu Keputusan" "140" "120" ...
## $ ...15: chr [1:897] NA "Hasil Keputusan" "USUL" "BACK TO SALES" ...
## $ ...16: chr [1:897] NA "Keterangan/ Alasan" "LANJUT KE PBP" "LAINNYA" ...
## $ ...17: chr [1:897] NA "SLA" "5" "5" ...
## $ ...18: chr [1:897] NA "Usulan" "OKE LANJUT" "PENGHASILAN BLM LAYAK DIAKUI" ...
# ============================================================
# LANGKAH 5 — CEK ISI DATA
# ============================================================
head(data_awal, 5)
## # A tibble: 5 × 18
## `2023` ...2 ...3 ...4 ...5 ...6 ...7 ...8 ...9 ...10 ...11 ...12 ...13
## <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
## 1 JANUA… <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA>
## 2 No Nama… Nama… Tang… Tang… Segm… Prod… Maxi… Perm… Inst… Anal… TGL … Nomi…
## 3 1 DHEVY REST… 44921 44921 FIX … BNI … 4500… 120 NES … ERIKA 44928 4250…
## 4 2 MUS … ABDU… 44922 44922 FIX … BNI … 1000… 180 TOP … KIRM… 44929 1000…
## 5 3 ERLI… EDDY… 44923 44923 FIX … BNI … 4000… 120 TOP … ERIKA 44929 3510…
## # ℹ 5 more variables: ...14 <chr>, ...15 <chr>, ...16 <chr>, ...17 <chr>,
## # ...18 <chr>
# ============================================================
# LANGKAH 6 — AMBIL HEADER ASLI
# ============================================================
header <- as.character(data_awal[2, ])
print(header)
## [1] "No" "Nama Sales"
## [3] "Nama Debitur" "Tanggal Masuk Berkas"
## [5] "Tanggal di Analisis" "Segmen FIX/ Non Fix"
## [7] "Produk" "Maximum Permohonan"
## [9] "Permohonan Jangka Waktu" "Instansi Bekrja"
## [11] "Analis" "TGL USUL/TGL KELUAR"
## [13] "Nominal Keputusan" "Jangka Waktu Keputusan"
## [15] "Hasil Keputusan" "Keterangan/ Alasan"
## [17] "SLA" "Usulan"
# ============================================================
# LANGKAH 7 — BUANG BARIS JUDUL DAN HEADER
# ============================================================
data_model <- data_awal[-c(1, 2), ]
cat("Jumlah data :", nrow(data_model), "\n")
## Jumlah data : 895
# ============================================================
# LANGKAH 8 — PASANG NAMA KOLOM
# ============================================================
names(data_model) <- make.names(header, unique = TRUE)
print(names(data_model))
## [1] "No" "Nama.Sales"
## [3] "Nama.Debitur" "Tanggal.Masuk.Berkas"
## [5] "Tanggal.di.Analisis" "Segmen.FIX..Non.Fix"
## [7] "Produk" "Maximum.Permohonan"
## [9] "Permohonan.Jangka.Waktu" "Instansi.Bekrja"
## [11] "Analis" "TGL.USUL.TGL.KELUAR"
## [13] "Nominal.Keputusan" "Jangka.Waktu.Keputusan"
## [15] "Hasil.Keputusan" "Keterangan..Alasan"
## [17] "SLA" "Usulan"
# ============================================================
# LANGKAH 9 — CEK HASIL KEPUTUSAN
# ============================================================
cat("=== Hasil Keputusan ===\n")
## === Hasil Keputusan ===
print(table(data_model$Hasil.Keputusan, useNA = "ifany"))
##
## BACK TO SALES CANCEL BY BANK Hasil Keputusan REJECT USUL
## 123 70 11 1 668
## <NA>
## 22
# ============================================================
# LANGKAH 10 — BENTUK TARGET KEPUTUSAN
# ============================================================
data_model$Keputusan <- ifelse(
data_model$Hasil.Keputusan == "USUL",
"USUL",
"NON_USUL"
)
data_model$Keputusan <- factor(
data_model$Keputusan,
levels = c("NON_USUL", "USUL")
)
# ============================================================
# LANGKAH 11 — CEK DISTRIBUSI TARGET
# ============================================================
cat("Jumlah data :", nrow(data_model), "\n")
## Jumlah data : 895
cat("\nDistribusi Keputusan:\n")
##
## Distribusi Keputusan:
print(table(data_model$Keputusan))
##
## NON_USUL USUL
## 205 668
cat("\nProporsi Keputusan:\n")
##
## Proporsi Keputusan:
print(round(prop.table(table(data_model$Keputusan)) * 100, 2))
##
## NON_USUL USUL
## 23.48 76.52
# ============================================================
# LANGKAH 12 — CEK NA PADA TARGET
# ============================================================
cat("Jumlah NA Keputusan :", sum(is.na(data_model$Keputusan)), "\n")
## Jumlah NA Keputusan : 22
# ============================================================
# LANGKAH 13 — HAPUS DATA NA TARGET
# ============================================================
data_model <- data_model %>%
filter(!is.na(Keputusan))
cat("Jumlah data setelah hapus NA target :", nrow(data_model), "\n")
## Jumlah data setelah hapus NA target : 873
# ============================================================
# LANGKAH 14 — CEK ULANG DISTRIBUSI TARGET
# ============================================================
cat("=== DISTRIBUSI TARGET ===\n")
## === DISTRIBUSI TARGET ===
print(table(data_model$Keputusan))
##
## NON_USUL USUL
## 205 668
cat("\n=== PROPORSI TARGET ===\n")
##
## === PROPORSI TARGET ===
print(round(prop.table(table(data_model$Keputusan)) * 100, 2))
##
## NON_USUL USUL
## 23.48 76.52
cat("\n=== CEK NA ===\n")
##
## === CEK NA ===
cat("NA :", sum(is.na(data_model$Keputusan)), "\n")
## NA : 0
# ============================================================
# LANGKAH 12 — HAPUS DATA TANPA HASIL KEPUTUSAN
# ============================================================
data_model <- data_model %>%
filter(!is.na(Hasil.Keputusan))
cat("Jumlah data setelah hapus NA target :", nrow(data_model), "\n")
## Jumlah data setelah hapus NA target : 873
cat("\nDistribusi Keputusan:\n")
##
## Distribusi Keputusan:
print(table(data_model$Keputusan))
##
## NON_USUL USUL
## 205 668
cat("\nProporsi Keputusan:\n")
##
## Proporsi Keputusan:
print(round(prop.table(table(data_model$Keputusan)) * 100, 2))
##
## NON_USUL USUL
## 23.48 76.52
# ============================================================
# LANGKAH 13 — RAPIKAN NAMA VARIABEL
# ============================================================
data_model <- data_model %>%
rename(
Segmen = Segmen.FIX..Non.Fix,
Produk = Produk,
Maksimum_Permohonan = Maximum.Permohonan,
Jangka_Waktu = Permohonan.Jangka.Waktu,
Instansi = Instansi.Bekrja,
Nominal_Keputusan = Nominal.Keputusan,
Jangka_Waktu_Keputusan = Jangka.Waktu.Keputusan,
SLA = SLA
)
print(names(data_model))
## [1] "No" "Nama.Sales" "Nama.Debitur"
## [4] "Tanggal.Masuk.Berkas" "Tanggal.di.Analisis" "Segmen"
## [7] "Produk" "Maksimum_Permohonan" "Jangka_Waktu"
## [10] "Instansi" "Analis" "TGL.USUL.TGL.KELUAR"
## [13] "Nominal_Keputusan" "Jangka_Waktu_Keputusan" "Hasil.Keputusan"
## [16] "Keterangan..Alasan" "SLA" "Usulan"
## [19] "Keputusan"
# ============================================================
# LANGKAH 14 — CEK TIPE DATA
# ============================================================
str(
data_model %>%
select(
Keputusan,
Segmen,
Produk,
Maksimum_Permohonan,
Jangka_Waktu,
Instansi,
Nominal_Keputusan,
Jangka_Waktu_Keputusan,
SLA
)
)
## tibble [873 × 9] (S3: tbl_df/tbl/data.frame)
## $ Keputusan : Factor w/ 2 levels "NON_USUL","USUL": 2 1 2 2 1 1 1 2 1 1 ...
## $ Segmen : chr [1:873] "FIX INCOME" "FIX INCOME" "FIX INCOME" "FIX INCOME" ...
## $ Produk : chr [1:873] "BNI GRIYA" "BNI GRIYA" "BNI GRIYA" "BNI GRIYA" ...
## $ Maksimum_Permohonan : chr [1:873] "450000000" "1000000000" "400000000" "525000000" ...
## $ Jangka_Waktu : chr [1:873] "120" "180" "120" "120" ...
## $ Instansi : chr [1:873] "NES GLOBAL" "TOP UP" "TOP UP" "TOP UP" ...
## $ Nominal_Keputusan : chr [1:873] "425000000" "1000000000" "351000000" "525000000" ...
## $ Jangka_Waktu_Keputusan: chr [1:873] "140" "120" "120" "180" ...
## $ SLA : chr [1:873] "5" "5" "6" "0" ...
# ============================================================
# LANGKAH 15 — KONVERSI VARIABEL NUMERIK
# ============================================================
data_model <- data_model %>%
mutate(
Maksimum_Permohonan = as.numeric(Maksimum_Permohonan),
Jangka_Waktu = as.numeric(Jangka_Waktu),
Nominal_Keputusan = as.numeric(Nominal_Keputusan),
Jangka_Waktu_Keputusan = as.numeric(Jangka_Waktu_Keputusan),
SLA = as.numeric(SLA)
)
## Warning: There were 5 warnings in `mutate()`.
## The first warning was:
## ℹ In argument: `Maksimum_Permohonan = as.numeric(Maksimum_Permohonan)`.
## Caused by warning:
## ! NAs introduced by coercion
## ℹ Run `dplyr::last_dplyr_warnings()` to see the 4 remaining warnings.
# CEK
str(
data_model %>%
select(
Maksimum_Permohonan,
Jangka_Waktu,
Nominal_Keputusan,
Jangka_Waktu_Keputusan,
SLA
)
)
## tibble [873 × 5] (S3: tbl_df/tbl/data.frame)
## $ Maksimum_Permohonan : num [1:873] 4.50e+08 1.00e+09 4.00e+08 5.25e+08 8.29e+08 ...
## $ Jangka_Waktu : num [1:873] 120 180 120 120 120 120 180 180 36 36 ...
## $ Nominal_Keputusan : num [1:873] 4.25e+08 1.00e+09 3.51e+08 5.25e+08 8.29e+08 ...
## $ Jangka_Waktu_Keputusan: num [1:873] 140 120 120 180 180 120 180 140 36 36 ...
## $ SLA : num [1:873] 5 5 6 0 4 1 3 1 1 2 ...
# ============================================================
# LANGKAH 16 — CEK NA VARIABEL NUMERIK
# ============================================================
cat("NA Maksimum_Permohonan :", sum(is.na(data_model$Maksimum_Permohonan)), "\n")
## NA Maksimum_Permohonan : 11
cat("NA Jangka_Waktu :", sum(is.na(data_model$Jangka_Waktu)), "\n")
## NA Jangka_Waktu : 11
cat("NA Nominal_Keputusan :", sum(is.na(data_model$Nominal_Keputusan)), "\n")
## NA Nominal_Keputusan : 11
cat("NA Jangka_Waktu_Keputusan :", sum(is.na(data_model$Jangka_Waktu_Keputusan)), "\n")
## NA Jangka_Waktu_Keputusan : 11
cat("NA SLA :", sum(is.na(data_model$SLA)), "\n")
## NA SLA : 11
# ============================================================
# LANGKAH 17 — CEK BARIS YANG MENGANDUNG NA
# ============================================================
data_model %>%
filter(
is.na(Maksimum_Permohonan) |
is.na(Jangka_Waktu) |
is.na(Nominal_Keputusan) |
is.na(Jangka_Waktu_Keputusan) |
is.na(SLA)
) %>%
select(
No,
Nama.Debitur,
Segmen,
Produk,
Maksimum_Permohonan,
Jangka_Waktu,
Instansi,
Nominal_Keputusan,
Jangka_Waktu_Keputusan,
SLA,
Hasil.Keputusan,
Keputusan
)
## # A tibble: 11 × 12
## No Nama.Debitur Segmen Produk Maksimum_Permohonan Jangka_Waktu Instansi
## <chr> <chr> <chr> <chr> <dbl> <dbl> <chr>
## 1 No Nama Debitur Segmen F… Produk NA NA Instans…
## 2 No Nama Debitur Segmen F… Produk NA NA Instans…
## 3 No Nama Debitur Segmen F… Produk NA NA Instans…
## 4 No Nama Debitur Segmen F… Produk NA NA Instans…
## 5 No Nama Debitur Segmen F… Produk NA NA Instans…
## 6 No Nama Debitur Segmen F… Produk NA NA Instans…
## 7 No Nama Debitur Segmen F… Produk NA NA Instans…
## 8 No Nama Debitur Segmen F… Produk NA NA Instans…
## 9 No Nama Debitur Segmen F… Produk NA NA Instans…
## 10 No Nama Debitur Segmen F… Produk NA NA Instans…
## 11 No Nama Debitur Segmen F… Produk NA NA Instans…
## # ℹ 5 more variables: Nominal_Keputusan <dbl>, Jangka_Waktu_Keputusan <dbl>,
## # SLA <dbl>, Hasil.Keputusan <chr>, Keputusan <fct>
# ============================================================
# LANGKAH 18 — HAPUS BARIS HEADER YANG NYASAR
# ============================================================
data_model <- data_model %>%
filter(No != "No")
cat("Jumlah data setelah menghapus header nyasar :", nrow(data_model), "\n")
## Jumlah data setelah menghapus header nyasar : 862
# ============================================================
# LANGKAH 19 — CEK ULANG NA
# ============================================================
cat("NA Maksimum_Permohonan :", sum(is.na(data_model$Maksimum_Permohonan)), "\n")
## NA Maksimum_Permohonan : 0
cat("NA Jangka_Waktu :", sum(is.na(data_model$Jangka_Waktu)), "\n")
## NA Jangka_Waktu : 0
cat("NA Nominal_Keputusan :", sum(is.na(data_model$Nominal_Keputusan)), "\n")
## NA Nominal_Keputusan : 0
cat("NA Jangka_Waktu_Keputusan :", sum(is.na(data_model$Jangka_Waktu_Keputusan)), "\n")
## NA Jangka_Waktu_Keputusan : 0
cat("NA SLA :", sum(is.na(data_model$SLA)), "\n")
## NA SLA : 0
# ============================================================
# LANGKAH 20 — CEK DATA SETELAH PEMBERSIHAN
# ============================================================
cat("Jumlah data :", nrow(data_model), "\n")
## Jumlah data : 862
cat("\nDistribusi Keputusan:\n")
##
## Distribusi Keputusan:
print(table(data_model$Keputusan))
##
## NON_USUL USUL
## 194 668
cat("\nProporsi Keputusan:\n")
##
## Proporsi Keputusan:
print(round(prop.table(table(data_model$Keputusan)) * 100, 2))
##
## NON_USUL USUL
## 22.51 77.49
# ============================================================
# LANGKAH 21 — CEK NA PREDIKTOR MODEL
# ============================================================
cat("=== CEK NA PREDIKTOR ===\n")
## === CEK NA PREDIKTOR ===
print(
sapply(
data_model %>%
select(
Keputusan,
Segmen,
Produk,
Maksimum_Permohonan,
Jangka_Waktu,
Nominal_Keputusan,
Jangka_Waktu_Keputusan,
SLA
),
function(x) sum(is.na(x))
)
)
## Keputusan Segmen Produk
## 0 0 0
## Maksimum_Permohonan Jangka_Waktu Nominal_Keputusan
## 0 0 0
## Jangka_Waktu_Keputusan SLA
## 0 0
# ============================================================
# LANGKAH 22 — CEK KATEGORI PREDIKTOR
# ============================================================
cat("=== SEGMEN ===\n")
## === SEGMEN ===
print(table(data_model$Segmen, useNA = "ifany"))
##
## FIX INCOME NON FIX INCOME
## 828 34
cat("\n=== PRODUK ===\n")
##
## === PRODUK ===
print(table(data_model$Produk, useNA = "ifany"))
##
## BNI FLEKSI BNI FLEKSI PENSIUN BNI GRIYA BNI GRIYA MULTIGUNA
## 528 3 320 11
# ============================================================
# LANGKAH 23 — CEK VARIABEL NUMERIK
# ============================================================
summary(
data_model %>%
select(
Maksimum_Permohonan,
Jangka_Waktu,
Nominal_Keputusan,
Jangka_Waktu_Keputusan,
SLA
)
)
## Maksimum_Permohonan Jangka_Waktu Nominal_Keputusan Jangka_Waktu_Keputusan
## Min. :1.000e+07 Min. : 12.0 Min. :1.000e+07 Min. : 12.00
## 1st Qu.:8.000e+07 1st Qu.: 48.0 1st Qu.:7.500e+07 1st Qu.: 48.00
## Median :1.800e+08 Median : 72.0 Median :1.712e+08 Median : 75.00
## Mean :3.512e+08 Mean : 98.2 Mean :3.487e+08 Mean : 99.98
## 3rd Qu.:4.000e+08 3rd Qu.:144.0 3rd Qu.:4.000e+08 3rd Qu.:177.00
## Max. :6.000e+09 Max. :240.0 Max. :6.000e+09 Max. :300.00
## SLA
## Min. :-3.000
## 1st Qu.: 1.000
## Median : 2.000
## Mean : 2.799
## 3rd Qu.: 4.000
## Max. :25.000
# ============================================================
# LANGKAH 24 — CEK DUPLIKASI
# ============================================================
cat("Jumlah baris duplikat :", sum(duplicated(data_model)), "\n")
## Jumlah baris duplikat : 0
# ============================================================
# LANGKAH 25 — TRAIN-TEST SPLIT 80:20
# ============================================================
library(caret)
set.seed(123)
index_train <- createDataPartition(
data_model$Keputusan,
p = 0.80,
list = FALSE
)
train_data <- data_model[index_train, ]
test_data <- data_model[-index_train, ]
cat("Jumlah data total :", nrow(data_model), "\n")
## Jumlah data total : 862
cat("Jumlah data train :", nrow(train_data), "\n")
## Jumlah data train : 691
cat("Jumlah data test :", nrow(test_data), "\n")
## Jumlah data test : 171
cat("\nProporsi target TRAIN:\n")
##
## Proporsi target TRAIN:
print(round(
prop.table(table(train_data$Keputusan)) * 100,
2
))
##
## NON_USUL USUL
## 22.58 77.42
cat("\nProporsi target TEST:\n")
##
## Proporsi target TEST:
print(round(
prop.table(table(test_data$Keputusan)) * 100,
2
))
##
## NON_USUL USUL
## 22.22 77.78
# ============================================================
# LANGKAH 26 — FIT CART PADA DATA TRAIN
# ============================================================
library(rpart)
model_cart <- rpart(
Keputusan ~
Segmen +
Produk +
Maksimum_Permohonan +
Jangka_Waktu +
Nominal_Keputusan +
Jangka_Waktu_Keputusan +
SLA,
data = train_data,
method = "class",
control = rpart.control(
cp = 0.001,
minsplit = 20,
minbucket = 10,
maxdepth = 5
)
)
print(model_cart)
## n= 691
##
## node), split, n, loss, yval, (yprob)
## * denotes terminal node
##
## 1) root 691 156 USUL (0.2257598 0.7742402)
## 2) Segmen=NON FIX INCOME 28 13 USUL (0.4642857 0.5357143)
## 4) Maksimum_Permohonan< 1.45e+09 18 8 NON_USUL (0.5555556 0.4444444) *
## 5) Maksimum_Permohonan>=1.45e+09 10 3 USUL (0.3000000 0.7000000) *
## 3) Segmen=FIX INCOME 663 143 USUL (0.2156863 0.7843137)
## 6) Jangka_Waktu_Keputusan< 39 167 46 USUL (0.2754491 0.7245509)
## 12) Nominal_Keputusan>=6.75e+07 47 18 USUL (0.3829787 0.6170213)
## 24) Maksimum_Permohonan< 9.5e+07 14 6 NON_USUL (0.5714286 0.4285714) *
## 25) Maksimum_Permohonan>=9.5e+07 33 10 USUL (0.3030303 0.6969697) *
## 13) Nominal_Keputusan< 6.75e+07 120 28 USUL (0.2333333 0.7666667) *
## 7) Jangka_Waktu_Keputusan>=39 496 97 USUL (0.1955645 0.8044355)
## 14) Nominal_Keputusan>=4.1528e+08 123 33 USUL (0.2682927 0.7317073)
## 28) SLA>=2.5 56 22 USUL (0.3928571 0.6071429)
## 56) Jangka_Waktu_Keputusan< 150 23 9 NON_USUL (0.6086957 0.3913043) *
## 57) Jangka_Waktu_Keputusan>=150 33 8 USUL (0.2424242 0.7575758) *
## 29) SLA< 2.5 67 11 USUL (0.1641791 0.8358209) *
## 15) Nominal_Keputusan< 4.1528e+08 373 64 USUL (0.1715818 0.8284182) *
# ============================================================
# LANGKAH 27 — CEK HASIL CART
# ============================================================
cat("=== CP TABLE ===\n")
## === CP TABLE ===
print(model_cart$cptable)
## CP nsplit rel error xerror xstd
## 1 0.007478632 0 1.0000000 1.000000 0.07044912
## 2 0.006410256 6 0.9551282 1.044872 0.07153970
## 3 0.001000000 8 0.9423077 1.076923 0.07228395
cat("\n=== VARIABLE IMPORTANCE ===\n")
##
## === VARIABLE IMPORTANCE ===
print(model_cart$variable.importance)
## Nominal_Keputusan Maksimum_Permohonan Jangka_Waktu_Keputusan
## 7.3014764 7.0055717 5.5411224
## SLA Segmen Jangka_Waktu
## 3.4324167 3.3206553 3.1688214
## Produk
## 0.5634858
cat("\n=== JUMLAH SPLIT ===\n")
##
## === JUMLAH SPLIT ===
cat(nrow(model_cart$splits), "\n")
## 64
# ============================================================
# LANGKAH 28 — CP 1-SE RULE
# ============================================================
cp_table <- model_cart$cptable
min_xerror <- min(cp_table[, "xerror"])
se_min <- cp_table[
which.min(cp_table[, "xerror"]),
"xstd"
]
cp_1se <- cp_table[
which(
cp_table[, "xerror"] <= min_xerror + se_min
)[1],
"CP"
]
cat("Minimum xerror :", min_xerror, "\n")
## Minimum xerror : 1
cat("SE minimum :", se_min, "\n")
## SE minimum : 0.07044912
cat("CP 1-SE :", cp_1se, "\n")
## CP 1-SE : 0.007478632
# ============================================================
# LANGKAH 29 — PRUNING CART
# ============================================================
model_cart_pruned <- prune(
model_cart,
cp = cp_1se
)
print(model_cart_pruned)
## n= 691
##
## node), split, n, loss, yval, (yprob)
## * denotes terminal node
##
## 1) root 691 156 USUL (0.2257598 0.7742402) *
cat("\nJumlah split setelah pruning :",
nrow(model_cart_pruned$splits), "\n")
##
## Jumlah split setelah pruning : 0
# ============================================================
# LANGKAH 28 — COBA CP YANG LEBIH KECIL
# ============================================================
cp_test <- 0.006
model_cart_pruned <- prune(
model_cart,
cp = cp_test
)
print(model_cart_pruned)
## n= 691
##
## node), split, n, loss, yval, (yprob)
## * denotes terminal node
##
## 1) root 691 156 USUL (0.2257598 0.7742402)
## 2) Segmen=NON FIX INCOME 28 13 USUL (0.4642857 0.5357143)
## 4) Maksimum_Permohonan< 1.45e+09 18 8 NON_USUL (0.5555556 0.4444444) *
## 5) Maksimum_Permohonan>=1.45e+09 10 3 USUL (0.3000000 0.7000000) *
## 3) Segmen=FIX INCOME 663 143 USUL (0.2156863 0.7843137)
## 6) Jangka_Waktu_Keputusan< 39 167 46 USUL (0.2754491 0.7245509)
## 12) Nominal_Keputusan>=6.75e+07 47 18 USUL (0.3829787 0.6170213)
## 24) Maksimum_Permohonan< 9.5e+07 14 6 NON_USUL (0.5714286 0.4285714) *
## 25) Maksimum_Permohonan>=9.5e+07 33 10 USUL (0.3030303 0.6969697) *
## 13) Nominal_Keputusan< 6.75e+07 120 28 USUL (0.2333333 0.7666667) *
## 7) Jangka_Waktu_Keputusan>=39 496 97 USUL (0.1955645 0.8044355)
## 14) Nominal_Keputusan>=4.1528e+08 123 33 USUL (0.2682927 0.7317073)
## 28) SLA>=2.5 56 22 USUL (0.3928571 0.6071429)
## 56) Jangka_Waktu_Keputusan< 150 23 9 NON_USUL (0.6086957 0.3913043) *
## 57) Jangka_Waktu_Keputusan>=150 33 8 USUL (0.2424242 0.7575758) *
## 29) SLA< 2.5 67 11 USUL (0.1641791 0.8358209) *
## 15) Nominal_Keputusan< 4.1528e+08 373 64 USUL (0.1715818 0.8284182) *
cat("\nJumlah split setelah pruning :",
nrow(model_cart_pruned$splits), "\n")
##
## Jumlah split setelah pruning : 64
# ============================================================
# LANGKAH 29 — PREDIKSI CART PADA DATA TEST
# ============================================================
pred_test <- predict(
model_cart_pruned,
newdata = test_data,
type = "class"
)
cat("=== DISTRIBUSI PREDIKSI TEST ===\n")
## === DISTRIBUSI PREDIKSI TEST ===
print(table(pred_test))
## pred_test
## NON_USUL USUL
## 14 157
cat("\n=== DISTRIBUSI AKTUAL TEST ===\n")
##
## === DISTRIBUSI AKTUAL TEST ===
print(table(test_data$Keputusan))
##
## NON_USUL USUL
## 38 133
cat("\n=== CONFUSION MATRIX ===\n")
##
## === CONFUSION MATRIX ===
library(caret)
cm_cart <- confusionMatrix(
pred_test,
test_data$Keputusan,
positive = "USUL"
)
print(cm_cart)
## Confusion Matrix and Statistics
##
## Reference
## Prediction NON_USUL USUL
## NON_USUL 3 11
## USUL 35 122
##
## Accuracy : 0.731
## 95% CI : (0.658, 0.7958)
## No Information Rate : 0.7778
## P-Value [Acc > NIR] : 0.938460
##
## Kappa : -0.0049
##
## Mcnemar's Test P-Value : 0.000696
##
## Sensitivity : 0.91729
## Specificity : 0.07895
## Pos Pred Value : 0.77707
## Neg Pred Value : 0.21429
## Prevalence : 0.77778
## Detection Rate : 0.71345
## Detection Prevalence : 0.91813
## Balanced Accuracy : 0.49812
##
## 'Positive' Class : USUL
##
SMOTE
library(smotefamily)
## Warning: package 'smotefamily' was built under R version 4.4.3
# ============================================================
# LANGKAH 29 — CEK PACKAGE SMOTE
# ============================================================
library(smotefamily)
cat("Package smotefamily berhasil dipanggil.\n")
## Package smotefamily berhasil dipanggil.
# ============================================================
# LANGKAH 30 — SIAPKAN DATA TRAIN UNTUK SMOTE
# ============================================================
library(dplyr)
library(smotefamily)
# Salin data train
train_smote <- train_data %>%
select(
Keputusan,
Segmen,
Produk,
Maksimum_Permohonan,
Jangka_Waktu,
Nominal_Keputusan,
Jangka_Waktu_Keputusan,
SLA
)
# Ubah variabel kategorik menjadi factor
train_smote$Segmen <- as.factor(train_smote$Segmen)
train_smote$Produk <- as.factor(train_smote$Produk)
# Cek struktur
str(train_smote)
## tibble [691 × 8] (S3: tbl_df/tbl/data.frame)
## $ Keputusan : Factor w/ 2 levels "NON_USUL","USUL": 1 2 1 1 2 1 1 2 2 2 ...
## $ Segmen : Factor w/ 2 levels "FIX INCOME","NON FIX INCOME": 1 1 1 1 1 1 1 1 1 1 ...
## $ Produk : Factor w/ 4 levels "BNI FLEKSI","BNI FLEKSI PENSIUN",..: 3 3 3 3 3 1 1 3 3 3 ...
## $ Maksimum_Permohonan : num [1:691] 1.00e+09 4.00e+08 3.10e+08 4.16e+08 5.97e+08 ...
## $ Jangka_Waktu : num [1:691] 180 120 120 180 180 36 36 180 180 180 ...
## $ Nominal_Keputusan : num [1:691] 1.00e+09 3.51e+08 3.10e+08 4.16e+08 5.97e+08 ...
## $ Jangka_Waktu_Keputusan: num [1:691] 120 120 120 180 140 36 36 120 240 300 ...
## $ SLA : num [1:691] 5 6 1 3 1 1 2 3 1 0 ...
# Cek distribusi target sebelum SMOTE
cat("\n=== TARGET SEBELUM SMOTE ===\n")
##
## === TARGET SEBELUM SMOTE ===
print(table(train_smote$Keputusan))
##
## NON_USUL USUL
## 156 535
print(
round(
prop.table(table(train_smote$Keputusan)) * 100,
2
)
)
##
## NON_USUL USUL
## 22.58 77.42
# ============================================================
# LANGKAH 31 — CEK FUNGSI SMOTE
# ============================================================
library(smotefamily)
print(exists("SMOTE"))
## [1] TRUE
print(args(SMOTE))
## function (X, target, K = 5, dup_size = 0)
## NULL
# ============================================================
# LANGKAH 31 — DUMMY ENCODING DATA TRAIN
# ============================================================
library(dplyr)
train_smote_dummy <- train_smote %>%
mutate(
Segmen = as.factor(Segmen),
Produk = as.factor(Produk)
)
# Buat dummy variable
dummy_model <- model.matrix(
Keputusan ~ Segmen + Produk - 1,
data = train_smote_dummy
)
# Gabungkan dummy + variabel numerik
X_train_smote <- cbind(
dummy_model,
train_smote_dummy %>%
select(
Maksimum_Permohonan,
Jangka_Waktu,
Nominal_Keputusan,
Jangka_Waktu_Keputusan,
SLA
)
)
# Target
y_train_smote <- train_smote_dummy$Keputusan
cat("=== DIMENSI X ===\n")
## === DIMENSI X ===
print(dim(X_train_smote))
## [1] 691 10
cat("\n=== NAMA VARIABEL ===\n")
##
## === NAMA VARIABEL ===
print(colnames(X_train_smote))
## [1] "SegmenFIX INCOME" "SegmenNON FIX INCOME"
## [3] "ProdukBNI FLEKSI PENSIUN" "ProdukBNI GRIYA"
## [5] "ProdukBNI GRIYA MULTIGUNA" "Maksimum_Permohonan"
## [7] "Jangka_Waktu" "Nominal_Keputusan"
## [9] "Jangka_Waktu_Keputusan" "SLA"
cat("\n=== TARGET ===\n")
##
## === TARGET ===
print(table(y_train_smote))
## y_train_smote
## NON_USUL USUL
## 156 535
# ============================================================
# LANGKAH 32 — SMOTE
# ============================================================
set.seed(123)
smote_result <- SMOTE(
X = X_train_smote,
target = y_train_smote,
K = 5,
dup_size = 3
)
cat("=== SMOTE BERHASIL ===\n")
## === SMOTE BERHASIL ===
cat("\nJumlah data hasil SMOTE :", nrow(smote_result$data), "\n")
##
## Jumlah data hasil SMOTE : 1159
cat("\nNama kolom hasil SMOTE:\n")
##
## Nama kolom hasil SMOTE:
print(names(smote_result$data))
## [1] "SegmenFIX INCOME" "SegmenNON FIX INCOME"
## [3] "ProdukBNI FLEKSI PENSIUN" "ProdukBNI GRIYA"
## [5] "ProdukBNI GRIYA MULTIGUNA" "Maksimum_Permohonan"
## [7] "Jangka_Waktu" "Nominal_Keputusan"
## [9] "Jangka_Waktu_Keputusan" "SLA"
## [11] "class"
cat("\nDistribusi target setelah SMOTE:\n")
##
## Distribusi target setelah SMOTE:
print(table(smote_result$data$class))
##
## NON_USUL USUL
## 624 535
cat("\nProporsi target setelah SMOTE:\n")
##
## Proporsi target setelah SMOTE:
print(
round(
prop.table(table(smote_result$data$class)) * 100,
2
)
)
##
## NON_USUL USUL
## 53.84 46.16
# ============================================================
# LANGKAH 33 — DATA TRAIN HASIL SMOTE
# ============================================================
train_smote_final <- smote_result$data
# Ubah nama target menjadi Keputusan
names(train_smote_final)[names(train_smote_final) == "class"] <- "Keputusan"
# Jadikan target factor
train_smote_final$Keputusan <- factor(
train_smote_final$Keputusan,
levels = c("NON_USUL", "USUL")
)
cat("=== STRUKTUR DATA SMOTE ===\n")
## === STRUKTUR DATA SMOTE ===
str(train_smote_final)
## 'data.frame': 1159 obs. of 11 variables:
## $ SegmenFIX INCOME : num 1 1 1 1 1 1 1 1 1 1 ...
## $ SegmenNON FIX INCOME : num 0 0 0 0 0 0 0 0 0 0 ...
## $ ProdukBNI FLEKSI PENSIUN : num 0 0 0 0 0 0 0 0 0 0 ...
## $ ProdukBNI GRIYA : num 0 0 0 0 0 1 0 1 0 0 ...
## $ ProdukBNI GRIYA MULTIGUNA: num 0 0 0 0 0 0 0 0 0 0 ...
## $ Maksimum_Permohonan : num 5.0e+08 7.0e+07 6.0e+07 1.1e+08 1.5e+08 9.5e+08 2.5e+08 1.4e+08 5.0e+07 5.0e+08 ...
## $ Jangka_Waktu : num 96 60 48 36 36 120 188 120 60 72 ...
## $ Nominal_Keputusan : num 5.0e+08 7.0e+07 6.0e+07 1.5e+08 1.5e+08 9.5e+08 2.5e+08 1.4e+08 5.0e+07 5.0e+08 ...
## $ Jangka_Waktu_Keputusan : num 96 60 48 36 36 120 188 120 60 72 ...
## $ SLA : num 3 0 2 1 0 6 2 5 1 3 ...
## $ Keputusan : Factor w/ 2 levels "NON_USUL","USUL": 1 1 1 1 1 1 1 1 1 1 ...
cat("\n=== DIMENSI DATA ===\n")
##
## === DIMENSI DATA ===
print(dim(train_smote_final))
## [1] 1159 11
cat("\n=== DISTRIBUSI TARGET ===\n")
##
## === DISTRIBUSI TARGET ===
print(table(train_smote_final$Keputusan))
##
## NON_USUL USUL
## 624 535
cat("\n=== PROPORSI TARGET ===\n")
##
## === PROPORSI TARGET ===
print(
round(
prop.table(table(train_smote_final$Keputusan)) * 100,
2
)
)
##
## NON_USUL USUL
## 53.84 46.16
# ============================================================
# LANGKAH 34 — FIT CART PADA DATA HASIL SMOTE
# ============================================================
library(rpart)
model_cart_smote <- rpart(
Keputusan ~
`SegmenFIX INCOME` +
`SegmenNON FIX INCOME` +
`ProdukBNI FLEKSI PENSIUN` +
`ProdukBNI GRIYA` +
`ProdukBNI GRIYA MULTIGUNA` +
Maksimum_Permohonan +
Jangka_Waktu +
Nominal_Keputusan +
Jangka_Waktu_Keputusan +
SLA,
data = train_smote_final,
method = "class",
control = rpart.control(
cp = 0.001,
minsplit = 20,
minbucket = 10,
maxdepth = 5
)
)
print(model_cart_smote)
## n= 1159
##
## node), split, n, loss, yval, (yprob)
## * denotes terminal node
##
## 1) root 1159 535 NON_USUL (0.5383952 0.4616048)
## 2) SegmenFIX INCOME< 0.9997023 95 15 NON_USUL (0.8421053 0.1578947)
## 4) SegmenFIX INCOME>=0.004714953 58 0 NON_USUL (1.0000000 0.0000000) *
## 5) SegmenFIX INCOME< 0.004714953 37 15 NON_USUL (0.5945946 0.4054054)
## 10) Maksimum_Permohonan< 1.572274e+09 27 8 NON_USUL (0.7037037 0.2962963) *
## 11) Maksimum_Permohonan>=1.572274e+09 10 3 USUL (0.3000000 0.7000000) *
## 3) SegmenFIX INCOME>=0.9997023 1064 520 NON_USUL (0.5112782 0.4887218)
## 6) Jangka_Waktu< 179.4978 888 399 NON_USUL (0.5506757 0.4493243)
## 12) SLA>=1.002053 636 246 NON_USUL (0.6132075 0.3867925)
## 24) SLA< 1.99192 52 0 NON_USUL (1.0000000 0.0000000) *
## 25) SLA>=1.99192 584 246 NON_USUL (0.5787671 0.4212329)
## 50) SLA>=2.003915 435 154 NON_USUL (0.6459770 0.3540230) *
## 51) SLA< 2.003915 149 57 USUL (0.3825503 0.6174497) *
## 13) SLA< 1.002053 252 99 USUL (0.3928571 0.6071429) *
## 7) Jangka_Waktu>=179.4978 176 55 USUL (0.3125000 0.6875000)
## 14) ProdukBNI GRIYA< 0.8853115 32 13 NON_USUL (0.5937500 0.4062500)
## 28) ProdukBNI GRIYA>=0.004482841 10 0 NON_USUL (1.0000000 0.0000000) *
## 29) ProdukBNI GRIYA< 0.004482841 22 9 USUL (0.4090909 0.5909091)
## 58) Maksimum_Permohonan>=4.25e+08 11 5 NON_USUL (0.5454545 0.4545455) *
## 59) Maksimum_Permohonan< 4.25e+08 11 3 USUL (0.2727273 0.7272727) *
## 15) ProdukBNI GRIYA>=0.8853115 144 36 USUL (0.2500000 0.7500000) *
# ============================================================
# LANGKAH 35 — CEK CP TABLE CART-SMOTE
# ============================================================
cat("=== CP TABLE CART-SMOTE ===\n")
## === CP TABLE CART-SMOTE ===
print(model_cart_smote$cptable)
## CP nsplit rel error xerror xstd
## 1 0.061682243 0 1.0000000 1.0000000 0.03172296
## 2 0.032710280 3 0.7757009 0.7775701 0.03052429
## 3 0.011214953 5 0.7102804 0.7532710 0.03030525
## 4 0.007476636 6 0.6990654 0.7570093 0.03034015
## 5 0.003738318 7 0.6915888 0.7383178 0.03016128
## 6 0.001869159 9 0.6841121 0.7364486 0.03014278
## 7 0.001000000 10 0.6822430 0.7308411 0.03008663
# ============================================================
# LANGKAH 36 — FIT CART-SMOTE DENGAN CP = 0
# ============================================================
model_cart_smote_full <- rpart(
Keputusan ~
`SegmenFIX INCOME` +
`SegmenNON FIX INCOME` +
`ProdukBNI FLEKSI PENSIUN` +
`ProdukBNI GRIYA` +
`ProdukBNI GRIYA MULTIGUNA` +
Maksimum_Permohonan +
Jangka_Waktu +
Nominal_Keputusan +
Jangka_Waktu_Keputusan +
SLA,
data = train_smote_final,
method = "class",
control = rpart.control(
cp = 0,
minsplit = 20,
minbucket = 10,
maxdepth = 5
)
)
cat("=== CP TABLE CART-SMOTE FULL ===\n")
## === CP TABLE CART-SMOTE FULL ===
print(model_cart_smote_full$cptable)
## CP nsplit rel error xerror xstd
## 1 0.0616822430 0 1.0000000 1.0000000 0.03172296
## 2 0.0327102804 3 0.7757009 0.7719626 0.03047537
## 3 0.0112149533 5 0.7102804 0.7271028 0.03004863
## 4 0.0074766355 6 0.6990654 0.6822430 0.02955706
## 5 0.0037383178 7 0.6915888 0.6803738 0.02953512
## 6 0.0018691589 9 0.6841121 0.6803738 0.02953512
## 7 0.0009345794 10 0.6822430 0.6710280 0.02942366
## 8 0.0000000000 12 0.6803738 0.6710280 0.02942366
# ============================================================
# LANGKAH 37 — PRUNING CART-SMOTE
# ============================================================
cp_optimal_smote <- 0.0009345794
model_cart_smote_pruned <- prune(
model_cart_smote_full,
cp = cp_optimal_smote
)
cat("=== CART-SMOTE SETELAH PRUNING ===\n")
## === CART-SMOTE SETELAH PRUNING ===
print(model_cart_smote_pruned)
## n= 1159
##
## node), split, n, loss, yval, (yprob)
## * denotes terminal node
##
## 1) root 1159 535 NON_USUL (0.53839517 0.46160483)
## 2) SegmenFIX INCOME< 0.9997023 95 15 NON_USUL (0.84210526 0.15789474)
## 4) SegmenFIX INCOME>=0.004714953 58 0 NON_USUL (1.00000000 0.00000000) *
## 5) SegmenFIX INCOME< 0.004714953 37 15 NON_USUL (0.59459459 0.40540541)
## 10) Maksimum_Permohonan< 1.572274e+09 27 8 NON_USUL (0.70370370 0.29629630) *
## 11) Maksimum_Permohonan>=1.572274e+09 10 3 USUL (0.30000000 0.70000000) *
## 3) SegmenFIX INCOME>=0.9997023 1064 520 NON_USUL (0.51127820 0.48872180)
## 6) Jangka_Waktu< 179.4978 888 399 NON_USUL (0.55067568 0.44932432)
## 12) SLA>=1.002053 636 246 NON_USUL (0.61320755 0.38679245)
## 24) SLA< 1.99192 52 0 NON_USUL (1.00000000 0.00000000) *
## 25) SLA>=1.99192 584 246 NON_USUL (0.57876712 0.42123288)
## 50) SLA>=2.003915 435 154 NON_USUL (0.64597701 0.35402299) *
## 51) SLA< 2.003915 149 57 USUL (0.38255034 0.61744966) *
## 13) SLA< 1.002053 252 99 USUL (0.39285714 0.60714286) *
## 7) Jangka_Waktu>=179.4978 176 55 USUL (0.31250000 0.68750000)
## 14) ProdukBNI GRIYA< 0.8853115 32 13 NON_USUL (0.59375000 0.40625000)
## 28) ProdukBNI GRIYA>=0.004482841 10 0 NON_USUL (1.00000000 0.00000000) *
## 29) ProdukBNI GRIYA< 0.004482841 22 9 USUL (0.40909091 0.59090909)
## 58) Maksimum_Permohonan>=4.25e+08 11 5 NON_USUL (0.54545455 0.45454545) *
## 59) Maksimum_Permohonan< 4.25e+08 11 3 USUL (0.27272727 0.72727273) *
## 15) ProdukBNI GRIYA>=0.8853115 144 36 USUL (0.25000000 0.75000000)
## 30) Nominal_Keputusan>=2.82984e+08 107 34 USUL (0.31775701 0.68224299)
## 60) Maksimum_Permohonan< 4.356475e+08 45 22 NON_USUL (0.51111111 0.48888889) *
## 61) Maksimum_Permohonan>=4.356475e+08 62 11 USUL (0.17741935 0.82258065) *
## 31) Nominal_Keputusan< 2.82984e+08 37 2 USUL (0.05405405 0.94594595) *
cat("\nJumlah split setelah pruning :",
nrow(model_cart_smote_pruned$splits), "\n")
##
## Jumlah split setelah pruning : 86
# ============================================================
# LANGKAH 38 — VARIABLE IMPORTANCE CART-SMOTE
# ============================================================
cat("=== VARIABLE IMPORTANCE CART-SMOTE ===\n")
## === VARIABLE IMPORTANCE CART-SMOTE ===
importance_smote <- model_cart_smote_pruned$variable.importance
print(importance_smote)
## SLA SegmenFIX INCOME SegmenNON FIX INCOME
## 51.417915 26.515669 26.515669
## Jangka_Waktu Maksimum_Permohonan Nominal_Keputusan
## 18.969465 16.420693 14.810142
## Jangka_Waktu_Keputusan ProdukBNI GRIYA ProdukBNI GRIYA MULTIGUNA
## 12.100397 10.988636 0.996578
cat("\n=== VARIABLE IMPORTANCE (%) ===\n")
##
## === VARIABLE IMPORTANCE (%) ===
importance_percent <- round(
importance_smote / sum(importance_smote) * 100,
2
)
print(importance_percent)
## SLA SegmenFIX INCOME SegmenNON FIX INCOME
## 28.77 14.84 14.84
## Jangka_Waktu Maksimum_Permohonan Nominal_Keputusan
## 10.61 9.19 8.29
## Jangka_Waktu_Keputusan ProdukBNI GRIYA ProdukBNI GRIYA MULTIGUNA
## 6.77 6.15 0.56
# ============================================================
# LANGKAH 39A — BUAT DUMMY TEST SESUAI DATA SMOTE
# ============================================================
test_smote <- test_data %>%
mutate(
Segmen = factor(
Segmen,
levels = c("FIX INCOME", "NON FIX INCOME")
),
Produk = factor(
Produk,
levels = c(
"BNI FLEKSI",
"BNI FLEKSI PENSIUN",
"BNI GRIYA",
"BNI GRIYA MULTIGUNA"
)
)
) %>%
mutate(
`SegmenFIX INCOME` =
ifelse(Segmen == "FIX INCOME", 1, 0),
`SegmenNON FIX INCOME` =
ifelse(Segmen == "NON FIX INCOME", 1, 0),
`ProdukBNI FLEKSI PENSIUN` =
ifelse(Produk == "BNI FLEKSI PENSIUN", 1, 0),
`ProdukBNI GRIYA` =
ifelse(Produk == "BNI GRIYA", 1, 0),
`ProdukBNI GRIYA MULTIGUNA` =
ifelse(Produk == "BNI GRIYA MULTIGUNA", 1, 0)
)
cat("=== CEK KOLOM TEST ===\n")
## === CEK KOLOM TEST ===
print(
names(
test_smote %>%
select(
`SegmenFIX INCOME`,
`SegmenNON FIX INCOME`,
`ProdukBNI FLEKSI PENSIUN`,
`ProdukBNI GRIYA`,
`ProdukBNI GRIYA MULTIGUNA`,
Maksimum_Permohonan,
Jangka_Waktu,
Nominal_Keputusan,
Jangka_Waktu_Keputusan,
SLA
)
)
)
## [1] "SegmenFIX INCOME" "SegmenNON FIX INCOME"
## [3] "ProdukBNI FLEKSI PENSIUN" "ProdukBNI GRIYA"
## [5] "ProdukBNI GRIYA MULTIGUNA" "Maksimum_Permohonan"
## [7] "Jangka_Waktu" "Nominal_Keputusan"
## [9] "Jangka_Waktu_Keputusan" "SLA"
# ============================================================
# LANGKAH 39B — PREDIKSI CART-SMOTE PADA TEST ASLI
# ============================================================
pred_test_smote <- predict(
model_cart_smote_pruned,
newdata = test_smote,
type = "class"
)
cat("=== PREDIKSI CART-SMOTE SELESAI ===\n")
## === PREDIKSI CART-SMOTE SELESAI ===
cat("\nJumlah prediksi:\n")
##
## Jumlah prediksi:
print(table(pred_test_smote))
## pred_test_smote
## NON_USUL USUL
## 64 107
cat("\nProporsi prediksi (%):\n")
##
## Proporsi prediksi (%):
print(
round(
prop.table(table(pred_test_smote)) * 100,
2
)
)
## pred_test_smote
## NON_USUL USUL
## 37.43 62.57
# ============================================================
# LANGKAH 40 — CONFUSION MATRIX CART-SMOTE
# ============================================================
library(caret)
cm_cart_smote <- confusionMatrix(
data = pred_test_smote,
reference = test_data$Keputusan,
positive = "USUL"
)
cat("=== CONFUSION MATRIX CART-SMOTE ===\n")
## === CONFUSION MATRIX CART-SMOTE ===
print(cm_cart_smote)
## Confusion Matrix and Statistics
##
## Reference
## Prediction NON_USUL USUL
## NON_USUL 17 47
## USUL 21 86
##
## Accuracy : 0.6023
## 95% CI : (0.5248, 0.6763)
## No Information Rate : 0.7778
## P-Value [Acc > NIR] : 1.000000
##
## Kappa : 0.0755
##
## Mcnemar's Test P-Value : 0.002432
##
## Sensitivity : 0.6466
## Specificity : 0.4474
## Pos Pred Value : 0.8037
## Neg Pred Value : 0.2656
## Prevalence : 0.7778
## Detection Rate : 0.5029
## Detection Prevalence : 0.6257
## Balanced Accuracy : 0.5470
##
## 'Positive' Class : USUL
##