| Komponen | Keterangan |
|---|---|
| Mata kuliah | Data Mining |
| Pertemuan | 03 |
| Topik | Data Preprocessing |
| Perangkat lunak | R dan RStudio |
| Alokasi waktu | 2 SKS / 100 menit |
| Acuan utama | Han, Kamber, dan Pei (2012), Bab 3 |
Setelah menyelesaikan praktikum, mahasiswa mampu:
Data berasal dari dua sumber:
Dataset awal sengaja mengandung missing values, kategori yang tidak konsisten, duplikasi, nilai ekstrem, dan perbedaan nama identifier. Tahapan preprocessing dilakukan secara sistematis sampai menghasilkan satu dataset analisis yang bersih.
Pada versi ini, proses preprocessing tetap ditampilkan agar hasil dapat direproduksi, tetapi seluruh analisis akhir menggunakan dataset yang sudah dipreprocessing.
Prinsip utama: jangan membersihkan data hanya karena sebuah nilai terlihat aneh. Setiap perubahan harus memiliki alasan, aturan, dan catatan.
knitr::opts_chunk$set(
echo = TRUE,
warning = FALSE,
message = FALSE
)
getwd()
## [1] "D:/Downloads"
R.version.string
## [1] "R version 4.5.1 (2025-06-13 ucrt)"
Modul menggunakan fungsi dasar R sehingga tidak memerlukan paket
tambahan selain knitr, yang otomatis tersedia saat proses
Knit.
pelanggan_raw <- data.frame(
customer_id = c(
"C001","C002","C003","C004","C005","C006",
"C007","C008","C009","C010","C010","C011"
),
nama = c(
"Ani","Budi","Citra","Dodi","Eka","Fani",
"Gilang","Hana","Indra","Joko","Joko","Kiki"
),
usia = c(21,25,23,150,27,NA,31,29,22,35,35,28),
pendapatan = c(
4500000,NA,5200000,4800000,4900000,5100000,
500000000,4700000,4600000,5300000,5300000,NA
),
kota = c(
"Pekanbaru","PKU","PEKANBARU","Dumai","pekanbaru","DUMAI",
"Pekanbaru","Siak","PKU","Dumai","Dumai",NA
),
status = c(
"Aktif","aktif","ACTIVE","A","Tidak Aktif","nonaktif",
"Aktif","AKTIF","A","Tidak aktif","Tidak aktif","Aktif"
),
stringsAsFactors = FALSE
)
pelanggan_raw
## customer_id nama usia pendapatan kota status
## 1 C001 Ani 21 4.5e+06 Pekanbaru Aktif
## 2 C002 Budi 25 NA PKU aktif
## 3 C003 Citra 23 5.2e+06 PEKANBARU ACTIVE
## 4 C004 Dodi 150 4.8e+06 Dumai A
## 5 C005 Eka 27 4.9e+06 pekanbaru Tidak Aktif
## 6 C006 Fani NA 5.1e+06 DUMAI nonaktif
## 7 C007 Gilang 31 5.0e+08 Pekanbaru Aktif
## 8 C008 Hana 29 4.7e+06 Siak AKTIF
## 9 C009 Indra 22 4.6e+06 PKU A
## 10 C010 Joko 35 5.3e+06 Dumai Tidak aktif
## 11 C010 Joko 35 5.3e+06 Dumai Tidak aktif
## 12 C011 Kiki 28 NA <NA> Aktif
transaksi_raw <- data.frame(
cust_id = c(
"C001","C002","C003","C004","C005","C006",
"C007","C008","C009","C010","C012"
),
jumlah_transaksi = c(5,3,7,2,6,4,20,5,3,8,1),
total_purchase = c(
1500000,900000,2700000,600000,2100000,1300000,
25000000,1700000,800000,3200000,250000
),
stringsAsFactors = FALSE
)
transaksi_raw
## cust_id jumlah_transaksi total_purchase
## 1 C001 5 1.5e+06
## 2 C002 3 9.0e+05
## 3 C003 7 2.7e+06
## 4 C004 2 6.0e+05
## 5 C005 6 2.1e+06
## 6 C006 4 1.3e+06
## 7 C007 20 2.5e+07
## 8 C008 5 1.7e+06
## 9 C009 3 8.0e+05
## 10 C010 8 3.2e+06
## 11 C012 1 2.5e+05
str(pelanggan_raw)
## 'data.frame': 12 obs. of 6 variables:
## $ customer_id: chr "C001" "C002" "C003" "C004" ...
## $ nama : chr "Ani" "Budi" "Citra" "Dodi" ...
## $ usia : num 21 25 23 150 27 NA 31 29 22 35 ...
## $ pendapatan : num 4.5e+06 NA 5.2e+06 4.8e+06 4.9e+06 5.1e+06 5.0e+08 4.7e+06 4.6e+06 5.3e+06 ...
## $ kota : chr "Pekanbaru" "PKU" "PEKANBARU" "Dumai" ...
## $ status : chr "Aktif" "aktif" "ACTIVE" "A" ...
str(transaksi_raw)
## 'data.frame': 11 obs. of 3 variables:
## $ cust_id : chr "C001" "C002" "C003" "C004" ...
## $ jumlah_transaksi: num 5 3 7 2 6 4 20 5 3 8 ...
## $ total_purchase : num 1.5e+06 9.0e+05 2.7e+06 6.0e+05 2.1e+06 1.3e+06 2.5e+07 1.7e+06 8.0e+05 3.2e+06 ...
dim(pelanggan_raw)
## [1] 12 6
dim(transaksi_raw)
## [1] 11 3
Enam dimensi kualitas data yang dibahas Han, Kamber, dan Pei meliputi accuracy, completeness, consistency, timeliness, believability, dan interpretability. Tidak semua dimensi dapat dihitung hanya dari isi tabel.
Pemeriksaan awal berikut berfokus pada masalah yang dapat dideteksi dari dataset.
# Banyak missing value per atribut
colSums(is.na(pelanggan_raw))
## customer_id nama usia pendapatan kota status
## 0 0 1 2 1 0
# Persentase missing value per atribut
round(colMeans(is.na(pelanggan_raw)) * 100, 2)
## customer_id nama usia pendapatan kota status
## 0.00 0.00 8.33 16.67 8.33 0.00
# Banyak baris duplikat penuh
sum(duplicated(pelanggan_raw))
## [1] 1
# Banyak customer_id yang berulang
sum(duplicated(pelanggan_raw$customer_id))
## [1] 1
# Kategori yang tercatat
sort(unique(pelanggan_raw$kota))
## [1] "Dumai" "DUMAI" "pekanbaru" "Pekanbaru" "PEKANBARU" "PKU"
## [7] "Siak"
sort(unique(pelanggan_raw$status))
## [1] "A" "ACTIVE" "aktif" "Aktif" "AKTIF"
## [6] "nonaktif" "Tidak aktif" "Tidak Aktif"
# Rentang atribut numerik
range(pelanggan_raw$usia, na.rm = TRUE)
## [1] 21 150
range(pelanggan_raw$pendapatan, na.rm = TRUE)
## [1] 4.5e+06 5.0e+08
audit_data <- function(data) {
data.frame(
atribut = names(data),
tipe = sapply(data, function(x) class(x)[1]),
jumlah_missing = sapply(data, function(x) sum(is.na(x))),
persen_missing = round(
sapply(data, function(x) mean(is.na(x)) * 100), 2
),
jumlah_unik = sapply(data, function(x) length(unique(x))),
row.names = NULL
)
}
audit_awal <- audit_data(pelanggan_raw)
audit_awal
## atribut tipe jumlah_missing persen_missing jumlah_unik
## 1 customer_id character 0 0.00 11
## 2 nama character 0 0.00 11
## 3 usia numeric 1 8.33 11
## 4 pendapatan numeric 2 16.67 10
## 5 kota character 1 8.33 8
## 6 status character 0 0.00 8
Interpretasi: Audit awal digunakan untuk mengidentifikasi bagian data yang membutuhkan pemeriksaan lebih lanjut. Audit bukan berarti setiap nilai yang berbeda harus dihapus atau diubah.
pelanggan <- pelanggan_raw
pelanggan$kota <- trimws(pelanggan$kota)
pelanggan$status <- trimws(pelanggan$status)
pelanggan$kota <- tolower(pelanggan$kota)
pelanggan$status <- tolower(pelanggan$status)
sort(unique(pelanggan$kota))
## [1] "dumai" "pekanbaru" "pku" "siak"
sort(unique(pelanggan$status))
## [1] "a" "active" "aktif" "nonaktif" "tidak aktif"
# Standardisasi kota
pelanggan$kota[pelanggan$kota %in% c("pku", "pekanbaru")] <- "Pekanbaru"
pelanggan$kota[pelanggan$kota == "dumai"] <- "Dumai"
pelanggan$kota[pelanggan$kota == "siak"] <- "Siak"
# Standardisasi status
pelanggan$status[
pelanggan$status %in% c("aktif", "active", "a")
] <- "Aktif"
pelanggan$status[
pelanggan$status %in% c("tidak aktif", "nonaktif")
] <- "Tidak Aktif"
sort(unique(pelanggan$kota))
## [1] "Dumai" "Pekanbaru" "Siak"
sort(unique(pelanggan$status))
## [1] "Aktif" "Tidak Aktif"
pelanggan[
duplicated(pelanggan$customer_id) |
duplicated(pelanggan$customer_id, fromLast = TRUE),
]
## customer_id nama usia pendapatan kota status
## 10 C010 Joko 35 5300000 Dumai Tidak Aktif
## 11 C010 Joko 35 5300000 Dumai Tidak Aktif
pelanggan <- pelanggan[!duplicated(pelanggan$customer_id), ]
rownames(pelanggan) <- NULL
dim(pelanggan)
## [1] 11 6
Duplikasi dihapus karena pada skenario ini setiap
customer_id mewakili satu pelanggan.
# Kandidat usia tidak valid berdasarkan aturan bisnis 15–100 tahun
pelanggan[
pelanggan$usia < 15 | pelanggan$usia > 100,
]
## customer_id nama usia pendapatan kota status
## 4 C004 Dodi 150 4800000 Dumai Aktif
## NA <NA> <NA> NA NA <NA> <NA>
# Nilai C004 dikoreksi berdasarkan sumber asli:
# 150 -> 50
pelanggan$usia[pelanggan$customer_id == "C004"] <- 50
pelanggan[pelanggan$customer_id == "C004", ]
## customer_id nama usia pendapatan kota status
## 4 C004 Dodi 50 4800000 Dumai Aktif
log_perubahan <- data.frame(
tahap = c(
"Standardisasi",
"Standardisasi",
"Deduplikasi",
"Koreksi domain"
),
atribut = c(
"kota",
"status",
"customer_id",
"usia"
),
tindakan = c(
"PKU dan variasi kapital menjadi Pekanbaru",
"ACTIVE/A menjadi Aktif; nonaktif menjadi Tidak Aktif",
"Menghapus kemunculan kedua C010",
"Usia C004 dikoreksi dari 150 menjadi 50 berdasarkan sumber asli"
),
stringsAsFactors = FALSE
)
log_perubahan
## tahap atribut
## 1 Standardisasi kota
## 2 Standardisasi status
## 3 Deduplikasi customer_id
## 4 Koreksi domain usia
## tindakan
## 1 PKU dan variasi kapital menjadi Pekanbaru
## 2 ACTIVE/A menjadi Aktif; nonaktif menjadi Tidak Aktif
## 3 Menghapus kemunculan kedua C010
## 4 Usia C004 dikoreksi dari 150 menjadi 50 berdasarkan sumber asli
colSums(is.na(pelanggan))
## customer_id nama usia pendapatan kota status
## 0 0 1 2 1 0
pelanggan[!complete.cases(pelanggan), ]
## customer_id nama usia pendapatan kota status
## 2 C002 Budi 25 NA Pekanbaru Aktif
## 6 C006 Fani NA 5100000 Dumai Tidak Aktif
## 11 C011 Kiki 28 NA <NA> Aktif
Strategi ini ditampilkan sebagai pembanding. Dataset utama tidak langsung menggunakan strategi ini karena dapat menghilangkan terlalu banyak observasi.
pelanggan_complete <- pelanggan[complete.cases(pelanggan), ]
nrow(pelanggan)
## [1] 11
nrow(pelanggan_complete)
## [1] 8
round(
(1 - nrow(pelanggan_complete) / nrow(pelanggan)) * 100,
2
)
## [1] 27.27
Karena pendapatan memiliki nilai ekstrem, median dipilih sebagai nilai imputasi yang lebih stabil.
mean_pendapatan <- mean(pelanggan$pendapatan, na.rm = TRUE)
median_pendapatan <- median(pelanggan$pendapatan, na.rm = TRUE)
mean_pendapatan
## [1] 59900000
median_pendapatan
## [1] 4900000
pelanggan$pendapatan_imputasi <- pelanggan$pendapatan
pelanggan$pendapatan_imputasi[
is.na(pelanggan$pendapatan_imputasi)
] <- median_pendapatan
median_usia <- median(pelanggan$usia, na.rm = TRUE)
pelanggan$usia_imputasi <- pelanggan$usia
pelanggan$usia_imputasi[
is.na(pelanggan$usia_imputasi)
] <- median_usia
pelanggan[, c(
"customer_id",
"usia",
"usia_imputasi",
"pendapatan",
"pendapatan_imputasi"
)]
## customer_id usia usia_imputasi pendapatan pendapatan_imputasi
## 1 C001 21 21.0 4.5e+06 4.5e+06
## 2 C002 25 25.0 NA 4.9e+06
## 3 C003 23 23.0 5.2e+06 5.2e+06
## 4 C004 50 50.0 4.8e+06 4.8e+06
## 5 C005 27 27.0 4.9e+06 4.9e+06
## 6 C006 NA 27.5 5.1e+06 5.1e+06
## 7 C007 31 31.0 5.0e+08 5.0e+08
## 8 C008 29 29.0 4.7e+06 4.7e+06
## 9 C009 22 22.0 4.6e+06 4.6e+06
## 10 C010 35 35.0 5.3e+06 5.3e+06
## 11 C011 28 28.0 NA 4.9e+06
Nilai kota yang hilang diberi kategori eksplisit
Tidak diketahui agar ketidakpastian tidak
disembunyikan.
pelanggan$kota_imputasi <- pelanggan$kota
pelanggan$kota_imputasi[
is.na(pelanggan$kota_imputasi)
] <- "Tidak diketahui"
table(pelanggan$kota_imputasi, useNA = "ifany")
##
## Dumai Pekanbaru Siak Tidak diketahui
## 3 6 1 1
pelanggan$pendapatan_missing <- as.integer(
is.na(pelanggan$pendapatan)
)
table(pelanggan$pendapatan_missing)
##
## 0 1
## 9 2
par(mfrow = c(1, 2))
hist(
pelanggan$pendapatan,
main = "Sebelum Imputasi",
xlab = "Pendapatan",
col = "skyblue",
breaks = 8
)
hist(
pelanggan$pendapatan_imputasi,
main = "Sesudah Imputasi Median",
xlab = "Pendapatan",
col = "lightgreen",
breaks = 8
)
par(mfrow = c(1, 1))
boxplot(
pelanggan$pendapatan_imputasi,
horizontal = TRUE,
col = "lightblue",
main = "Boxplot Pendapatan",
xlab = "Pendapatan"
)
q1 <- quantile(pelanggan$pendapatan_imputasi, 0.25)
q3 <- quantile(pelanggan$pendapatan_imputasi, 0.75)
iqr <- IQR(pelanggan$pendapatan_imputasi)
batas_bawah <- q1 - 1.5 * iqr
batas_atas <- q3 + 1.5 * iqr
c(
Q1 = q1,
Q3 = q3,
IQR = iqr,
batas_bawah = batas_bawah,
batas_atas = batas_atas
)
## Q1.25% Q3.75% IQR batas_bawah.25% batas_atas.75%
## 4750000 5150000 400000 4150000 5750000
pelanggan$outlier_pendapatan <-
pelanggan$pendapatan_imputasi < batas_bawah |
pelanggan$pendapatan_imputasi > batas_atas
pelanggan[
pelanggan$outlier_pendapatan,
c("customer_id", "nama", "pendapatan_imputasi")
]
## customer_id nama pendapatan_imputasi
## 7 C007 Gilang 5e+08
Nilai Rp500.000.000 tidak otomatis dihapus. Nilai tersebut dipertahankan sebagai observasi valid yang ekstrem, kemudian dibuat versi winsorized untuk melihat dampak pembatasan nilai ekstrem.
pelanggan$pendapatan_winsor <- pmin(
pmax(pelanggan$pendapatan_imputasi, batas_bawah),
batas_atas
)
pelanggan[
pelanggan$outlier_pendapatan,
c(
"customer_id",
"pendapatan_imputasi",
"pendapatan_winsor"
)
]
## customer_id pendapatan_imputasi pendapatan_winsor
## 7 C007 5e+08 5750000
Rumus normalisasi min–maks pada rentang [0,1]
adalah:
\[ x' = \frac{x-\min(x)}{\max(x)-\min(x)}. \]
minmax <- function(x) {
if (all(is.na(x))) {
return(rep(NA_real_, length(x)))
}
rentang <- max(x, na.rm = TRUE) - min(x, na.rm = TRUE)
if (rentang == 0) {
return(rep(0, length(x)))
}
(x - min(x, na.rm = TRUE)) / rentang
}
pelanggan$usia_minmax <-
minmax(pelanggan$usia_imputasi)
pelanggan$pendapatan_minmax <-
minmax(pelanggan$pendapatan_imputasi)
pelanggan[, c(
"customer_id",
"usia",
"usia_minmax",
"pendapatan_imputasi",
"pendapatan_minmax"
)]
## customer_id usia usia_minmax pendapatan_imputasi pendapatan_minmax
## 1 C001 21 0.00000000 4.5e+06 0.0000000000
## 2 C002 25 0.13793103 4.9e+06 0.0008072654
## 3 C003 23 0.06896552 5.2e+06 0.0014127144
## 4 C004 50 1.00000000 4.8e+06 0.0006054490
## 5 C005 27 0.20689655 4.9e+06 0.0008072654
## 6 C006 NA 0.22413793 5.1e+06 0.0012108981
## 7 C007 31 0.34482759 5.0e+08 1.0000000000
## 8 C008 29 0.27586207 4.7e+06 0.0004036327
## 9 C009 22 0.03448276 4.6e+06 0.0002018163
## 10 C010 35 0.48275862 5.3e+06 0.0016145308
## 11 C011 28 0.24137931 4.9e+06 0.0008072654
\[ z = \frac{x-\bar{x}}{s}. \]
pelanggan$usia_z <-
as.numeric(scale(pelanggan$usia_imputasi))
pelanggan$pendapatan_z <-
as.numeric(scale(pelanggan$pendapatan_imputasi))
round(
pelanggan[, c("usia_z", "pendapatan_z")],
3
)
## usia_z pendapatan_z
## 1 -0.984 -0.304
## 2 -0.489 -0.301
## 3 -0.737 -0.299
## 4 2.604 -0.302
## 5 -0.242 -0.301
## 6 -0.180 -0.300
## 7 0.253 3.015
## 8 0.006 -0.303
## 9 -0.860 -0.303
## 10 0.748 -0.299
## 11 -0.118 -0.301
decimal_scale <- function(x) {
maks <- max(abs(x), na.rm = TRUE)
if (maks == 0) {
return(x)
}
j <- ceiling(log10(maks + 1))
x / (10 ^ j)
}
pelanggan$pendapatan_decimal <-
decimal_scale(pelanggan$pendapatan_imputasi)
range(
pelanggan$pendapatan_decimal,
na.rm = TRUE
)
## [1] 0.0045 0.5000
transformasi <- pelanggan[, c(
"customer_id",
"pendapatan_imputasi",
"pendapatan_minmax",
"pendapatan_z",
"pendapatan_decimal"
)]
transformasi
## customer_id pendapatan_imputasi pendapatan_minmax pendapatan_z
## 1 C001 4.5e+06 0.0000000000 -0.3041235
## 2 C002 4.9e+06 0.0008072654 -0.3014440
## 3 C003 5.2e+06 0.0014127144 -0.2994343
## 4 C004 4.8e+06 0.0006054490 -0.3021138
## 5 C005 4.9e+06 0.0008072654 -0.3014440
## 6 C006 5.1e+06 0.0012108981 -0.3001042
## 7 C007 5.0e+08 1.0000000000 3.0151095
## 8 C008 4.7e+06 0.0004036327 -0.3027837
## 9 C009 4.6e+06 0.0002018163 -0.3034536
## 10 C010 5.3e+06 0.0016145308 -0.2987645
## 11 C011 4.9e+06 0.0008072654 -0.3014440
## pendapatan_decimal
## 1 0.0045
## 2 0.0049
## 3 0.0052
## 4 0.0048
## 5 0.0049
## 6 0.0051
## 7 0.5000
## 8 0.0047
## 9 0.0046
## 10 0.0053
## 11 0.0049
pelanggan$pendapatan_winsor_minmax <-
minmax(pelanggan$pendapatan_winsor)
plot(
pelanggan$pendapatan_minmax,
pelanggan$pendapatan_winsor_minmax,
pch = 19,
col = "navy",
xlab = "Min–maks Data Asli",
ylab = "Min–maks Data Winsorized",
main = "Dampak Penanganan Outlier terhadap Normalisasi"
)
abline(
0, 1,
col = "red",
lty = 2
)
setdiff(
pelanggan$customer_id,
transaksi_raw$cust_id
)
## [1] "C011"
setdiff(
transaksi_raw$cust_id,
pelanggan$customer_id
)
## [1] "C012"
Hasil menunjukkan bahwa C011 merupakan pelanggan tanpa
transaksi pada sumber transaksi, sedangkan C012 merupakan
transaksi yang tidak memiliki pasangan pada data pelanggan.
transaksi <- transaksi_raw
names(transaksi)[
names(transaksi) == "cust_id"
] <- "customer_id"
merge()data_terintegrasi <- merge(
pelanggan,
transaksi,
by = "customer_id",
all.x = TRUE
)
data_terintegrasi[, c(
"customer_id",
"nama",
"jumlah_transaksi",
"total_purchase"
)]
## customer_id nama jumlah_transaksi total_purchase
## 1 C001 Ani 5 1.5e+06
## 2 C002 Budi 3 9.0e+05
## 3 C003 Citra 7 2.7e+06
## 4 C004 Dodi 2 6.0e+05
## 5 C005 Eka 6 2.1e+06
## 6 C006 Fani 4 1.3e+06
## 7 C007 Gilang 20 2.5e+07
## 8 C008 Hana 5 1.7e+06
## 9 C009 Indra 3 8.0e+05
## 10 C010 Joko 8 3.2e+06
## 11 C011 Kiki NA NA
Karena C011 tidak mempunyai catatan transaksi, nilai
transaksi yang hilang dianggap sebagai belum pernah
bertransaksi dalam skenario ini. Oleh sebab itu, nilai
NA diubah menjadi 0.
data_terintegrasi$jumlah_transaksi_final <-
data_terintegrasi$jumlah_transaksi
data_terintegrasi$total_purchase_final <-
data_terintegrasi$total_purchase
data_terintegrasi$jumlah_transaksi_final[
is.na(data_terintegrasi$jumlah_transaksi_final)
] <- 0
data_terintegrasi$total_purchase_final[
is.na(data_terintegrasi$total_purchase_final)
] <- 0
Dataset akhir menggunakan atribut yang telah dibersihkan, diimputasi, ditransformasi, dan diintegrasikan.
data_final <- data_terintegrasi[, c(
"customer_id",
"nama",
"usia_imputasi",
"kota_imputasi",
"status",
"pendapatan_imputasi",
"pendapatan_missing",
"outlier_pendapatan",
"usia_minmax",
"pendapatan_minmax",
"jumlah_transaksi_final",
"total_purchase_final"
)]
names(data_final)[
names(data_final) == "kota_imputasi"
] <- "kota"
names(data_final)[
names(data_final) == "usia_imputasi"
] <- "usia"
data_final
## customer_id nama usia kota status pendapatan_imputasi
## 1 C001 Ani 21.0 Pekanbaru Aktif 4.5e+06
## 2 C002 Budi 25.0 Pekanbaru Aktif 4.9e+06
## 3 C003 Citra 23.0 Pekanbaru Aktif 5.2e+06
## 4 C004 Dodi 50.0 Dumai Aktif 4.8e+06
## 5 C005 Eka 27.0 Pekanbaru Tidak Aktif 4.9e+06
## 6 C006 Fani 27.5 Dumai Tidak Aktif 5.1e+06
## 7 C007 Gilang 31.0 Pekanbaru Aktif 5.0e+08
## 8 C008 Hana 29.0 Siak Aktif 4.7e+06
## 9 C009 Indra 22.0 Pekanbaru Aktif 4.6e+06
## 10 C010 Joko 35.0 Dumai Tidak Aktif 5.3e+06
## 11 C011 Kiki 28.0 Tidak diketahui Aktif 4.9e+06
## pendapatan_missing outlier_pendapatan usia_minmax pendapatan_minmax
## 1 0 FALSE 0.00000000 0.0000000000
## 2 1 FALSE 0.13793103 0.0008072654
## 3 0 FALSE 0.06896552 0.0014127144
## 4 0 FALSE 1.00000000 0.0006054490
## 5 0 FALSE 0.20689655 0.0008072654
## 6 0 FALSE 0.22413793 0.0012108981
## 7 0 TRUE 0.34482759 1.0000000000
## 8 0 FALSE 0.27586207 0.0004036327
## 9 0 FALSE 0.03448276 0.0002018163
## 10 0 FALSE 0.48275862 0.0016145308
## 11 1 FALSE 0.24137931 0.0008072654
## jumlah_transaksi_final total_purchase_final
## 1 5 1.5e+06
## 2 3 9.0e+05
## 3 7 2.7e+06
## 4 2 6.0e+05
## 5 6 2.1e+06
## 6 4 1.3e+06
## 7 20 2.5e+07
## 8 5 1.7e+06
## 9 3 8.0e+05
## 10 8 3.2e+06
## 11 0 0.0e+00
audit_akhir <- audit_data(data_final)
audit_akhir
## atribut tipe jumlah_missing persen_missing jumlah_unik
## 1 customer_id character 0 0 11
## 2 nama character 0 0 11
## 3 usia numeric 0 0 11
## 4 kota character 0 0 4
## 5 status character 0 0 2
## 6 pendapatan_imputasi numeric 0 0 9
## 7 pendapatan_missing integer 0 0 2
## 8 outlier_pendapatan logical 0 0 2
## 9 usia_minmax numeric 0 0 11
## 10 pendapatan_minmax numeric 0 0 9
## 11 jumlah_transaksi_final numeric 0 0 9
## 12 total_purchase_final numeric 0 0 11
# Jumlah customer_id yang masih duplikat
sum(duplicated(data_final$customer_id))
## [1] 0
# Jumlah missing value setiap atribut
colSums(is.na(data_final))
## customer_id nama usia
## 0 0 0
## kota status pendapatan_imputasi
## 0 0 0
## pendapatan_missing outlier_pendapatan usia_minmax
## 0 0 0
## pendapatan_minmax jumlah_transaksi_final total_purchase_final
## 0 0 0
# Jumlah baris dan kolom
dim(data_final)
## [1] 11 12
Data akhir diharapkan memiliki:
customer_id yang duplikat;perbandingan <- data.frame(
kondisi = c(
"Sebelum preprocessing",
"Sesudah preprocessing"
),
jumlah_baris = c(
nrow(pelanggan_raw),
nrow(data_final)
),
jumlah_kolom = c(
ncol(pelanggan_raw),
ncol(data_final)
),
jumlah_missing_total = c(
sum(is.na(pelanggan_raw)),
sum(is.na(data_final))
),
jumlah_customer_id_duplikat = c(
sum(duplicated(pelanggan_raw$customer_id)),
sum(duplicated(data_final$customer_id))
)
)
perbandingan
## kondisi jumlah_baris jumlah_kolom jumlah_missing_total
## 1 Sebelum preprocessing 12 6 4
## 2 Sesudah preprocessing 11 12 0
## jumlah_customer_id_duplikat
## 1 1
## 2 0
write.csv(
data_final,
"data_final_preprocessed.csv",
row.names = FALSE
)
write.csv(
log_perubahan,
"log_perubahan_preprocessing.csv",
row.names = FALSE
)
1. Mengapa nilai ekstrem tidak selalu harus dihapus?
Nilai ekstrem dapat merupakan observasi yang benar-benar valid. Penghapusan tanpa verifikasi dapat menghilangkan informasi penting dan menghasilkan bias.
2. Mengapa median digunakan untuk imputasi pendapatan?
Karena pendapatan memiliki nilai ekstrem Rp500.000.000 sehingga mean menjadi sangat besar dan kurang representatif terhadap sebagian besar pelanggan. Median lebih tahan terhadap pengaruh nilai ekstrem.
3. Mengapa C012 tidak muncul pada dataset
akhir?
C012 hanya terdapat pada data transaksi dan tidak
memiliki pasangan pada data pelanggan. Karena integrasi menggunakan
left join dari data pelanggan, C012 tidak masuk ke
dataset akhir.
4. Mengapa C011 tetap
dipertahankan?
C011 merupakan pelanggan yang valid, tetapi tidak
mempunyai transaksi. Setelah dikonfirmasi bahwa NA berarti
belum pernah bertransaksi, nilai jumlah transaksi dan total pembelian
dapat direpresentasikan sebagai 0.
Tahapan preprocessing yang dilakukan meliputi:
customer_id;Hasil akhir berupa data_final merupakan dataset yang
telah melalui preprocessing dan siap digunakan untuk tahap analisis atau
data mining berikutnya.
Han, J., Kamber, M., & Pei, J. (2012). Data Mining: Concepts and Techniques (3rd ed.). Morgan Kaufmann.