Data Mining — Pertemuan 03
Dokumen ini merupakan laporan praktikum mengenai Data Preprocessing Menggunakan RStudio. Struktur materi mengikuti alur praktikum dosen: pemahaman data, data cleaning, missing values, outlier, transformasi, integrasi, dan evaluasi dataset akhir.
| Komponen | Keterangan |
|---|---|
| Mata kuliah | Data Mining |
| Pertemuan | 03 |
| Topik | Data Preprocessing |
| Perangkat lunak | R dan RStudio |
| Alokasi waktu | 3 SKS / 150 menit |
| Acuan utama | Han, Kamber, dan Pei (2012), Bab 3 |
Setelah menyelesaikan praktikum, mahasiswa mampu:
Sebuah perusahaan e-commerce akan melakukan analisis pelanggan. Data berasal dari dua sumber:
Data belum dapat langsung digunakan karena mengandung nilai hilang, kategori tidak konsisten, duplikasi, nilai ekstrem, dan perbedaan nama identifier. Data kemudian diproses secara bertahap sampai menjadi dataset yang siap dianalisis.
Prinsip preprocessing: jangan mengubah data hanya karena sebuah nilai terlihat aneh. Setiap perubahan harus memiliki alasan, aturan, dan catatan.
praktikum_preprocessing..Rmd di dalam folder proyek.Dataset dibuat secara sengaja memiliki beberapa masalah kualitas data agar setiap tahap preprocessing dapat dipraktikkan.
pelanggan_raw <- data.frame(
customer_id = c(
"C001", "C002", "C003", "C004", "C005", "C006",
"C007", "C008", "C009", "C010", "C010", "C011",
"C012", "C013", "C014", "C015", "C016", "C017",
"C018", "C018"
),
nama = c(
"Ani", "Budi", "Citra", "Dodi", "Eka", "Fani",
"Gilang", "Hana", "Indra", "Joko", "Joko", "Kiki",
"Lala", "Miko", "Nisa", "Oki", "Putri", "Rian",
"Sari", "Sari"
),
usia = c(
21, 25, 23, 150, 27, NA,
31, 29, 22, 35, 35, 28,
26, NA, 30, 24, 200, 29,
33, 33
),
pendapatan = c(
4500000, NA, 5200000, 4800000, 4900000, 5100000,
500000000, 4700000, 4600000, 5300000, 5300000, NA,
5100000, 4950000, 750000000, NA, 4800000, 5050000,
5150000, 5150000
),
kota = c(
"Pekanbaru", " PKU", "PEKANBARU", "Dumai", "pekanbaru",
"DUMAI", "Pekanbaru ", "Siak", "PKU", "Dumai", "Dumai", NA,
" PEKANBARU ", "dumai", "DUMAI", "PKU", "Siak ", NA,
"pekanbaru", "pekanbaru"
),
status = c(
"Aktif", "aktif", "ACTIVE", "A", "Tidak Aktif", "nonaktif",
"Aktif", "AKTIF", "A", "Tidak aktif", "Tidak aktif", "Aktif",
"aktif", "A", "ACTIVE", "nonaktif", "AKTIF", "Tidak Aktif",
NA, NA
),
stringsAsFactors = FALSE
)
pelanggan_rawKualitas data sengaja dibuat tidak sempurna. Data
tambahan mencakup missing value, kategori kota/status yang
tidak konsisten, spasi berlebih, duplikasi customer_id,
serta nilai ekstrem pada usia dan pendapatan. Masalah tersebut
dipertahankan agar dapat ditemukan dan ditangani pada tahap
preprocessing berikutnya.
transaksi_raw <- data.frame(
cust_id = c(
"C001", "C002", "C003", "C004", "C005", "C006",
"C007", "C008", "C009", "C010", "C012",
"C013", "C014", "C015", "C016", "C017", "C018", "C012"
),
jumlah_transaksi = c(
5, 3, 7, 2, 6, 4, 20, 5, 3, 8, 1,
4, 6, 2, 9, 3, 5, 1
),
total_purchase = c(
1500000, 900000, 2700000, 600000, 2100000, 1300000,
25000000, 1700000, 800000, 3200000, 250000,
1200000, 18000000, 500000, 3200000, 1100000, 2100000, 250000
),
stringsAsFactors = FALSE
)
transaksi_raw## [1] "customer_id" "nama" "usia" "pendapatan" "kota"
## [6] "status"
## 'data.frame': 20 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" ...
## customer_id nama usia pendapatan
## Length:20 Length:20 Min. : 21.00 Min. : 4500000
## Class :character Class :character 1st Qu.: 25.25 1st Qu.: 4800000
## Mode :character Mode :character Median : 29.00 Median : 5100000
## Mean : 44.50 Mean : 77917647
## 3rd Qu.: 33.00 3rd Qu.: 5200000
## Max. :200.00 Max. :750000000
## NA's :2 NA's :3
## kota status
## Length:20 Length:20
## Class :character Class :character
## Mode :character Mode :character
##
##
##
##
## customer_id nama usia pendapatan kota status
## 0 0 2 3 2 2
## customer_id nama usia pendapatan kota status
## 0 0 10 15 10 10
## [1] " PEKANBARU " " PKU" "dumai" "Dumai" "DUMAI"
## [6] "pekanbaru" "Pekanbaru" "PEKANBARU" "Pekanbaru " "PKU"
## [11] "Siak" "Siak "
## [1] "A" "ACTIVE" "aktif" "Aktif" "AKTIF"
## [6] "nonaktif" "Tidak aktif" "Tidak Aktif"
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_awalInterpretasi awal: audit digunakan untuk menemukan atribut yang memerlukan pemeriksaan lebih lanjut. Hasil audit belum merupakan keputusan untuk menghapus, mengganti, atau mempertahankan data.
Aturan domain yang digunakan adalah usia antara 15 sampai 100 tahun.
Jika pemeriksaan terhadap sumber asli menunjukkan bahwa nilai C004 seharusnya 50, maka dilakukan koreksi.
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## customer_id nama usia pendapatan kota status
## 0 0 2 3 2 1
## [1] 18
## [1] 11
## [1] 87610000
## [1] 5050000
##
## 0 1
## 15 3
par(mfrow = c(1, 2))
hist(
pelanggan$pendapatan,
main = "Sebelum Imputasi",
xlab = "Pendapatan",
breaks = 8
)
hist(
pelanggan$pendapatan_imputasi,
main = "Sesudah Imputasi Median",
xlab = "Pendapatan",
breaks = 8
)Imputasi dapat mengubah distribusi dan mengurangi variasi data. Karena itu, pemeriksaan perlu dilanjutkan setelah imputasi.
boxplot(
pelanggan$pendapatan_imputasi,
horizontal = TRUE,
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%
## 4825000 5137500 312500 4356250 5606250
Rumus normalisasi min-max:
\[ x' = \frac{x-\min(x)} {\max(x)-\min(x)} \]
Rumus z-score:
\[ z = \frac{x-\bar{x}}{s} \]
decimal_scale <- function(x) {
maks <-
max(
abs(x),
na.rm = TRUE
)
if (maks == 0) {
return(x)
}
j <-
ceiling(
log10(maks + 1)
)
x / (10 ^ j)
}transformasi <- pelanggan[
,
c(
"customer_id",
"pendapatan_imputasi",
"pendapatan_minmax",
"pendapatan_z",
"pendapatan_decimal"
)
]
transformasiPenting: plot() dan
abline() sengaja berada dalam chunk yang
sama agar proses Knit tidak mengalami error
plot.new has not been called yet.
plot(
pelanggan$pendapatan_minmax,
pelanggan$pendapatan_winsor_minmax,
pch = 19,
xlab = "Min-Max Data Asli",
ylab = "Min-Max Data Winsorized",
main = "Dampak Penanganan Outlier terhadap Normalisasi"
)
abline(
a = 0,
b = 1,
lty = 2
)## [1] "C011"
## character(0)
transaksi <- transaksi_raw
names(transaksi)[
names(transaksi) == "cust_id"
] <- "customer_id"
names(transaksi)## [1] "customer_id" "jumlah_transaksi" "total_purchase"
## sebelum sesudah
## 18 19
## jumlah_transaksi total_purchase
## 1 1
NA pada transaksi dapat berarti pelanggan belum pernah
bertransaksi atau data transaksi tidak tersedia. Nilai hanya boleh
diganti menjadi 0 jika definisi tersebut telah dikonfirmasi.
Pada skenario praktikum, NA dianggap sebagai pelanggan
yang belum memiliki transaksi.
perbandingan <- data.frame(
indikator = c(
"Jumlah baris",
"Duplikasi customer_id",
"Total missing value",
"Kategori kota unik",
"Kategori status unik"
),
sebelum = c(
nrow(pelanggan_raw),
sum(
duplicated(
pelanggan_raw$customer_id
)
),
sum(
is.na(pelanggan_raw)
),
length(
unique(
pelanggan_raw$kota
)
),
length(
unique(
pelanggan_raw$status
)
)
),
sesudah = c(
nrow(data_final),
sum(
duplicated(
data_final$customer_id
)
),
sum(
is.na(data_final)
),
length(
unique(
data_final$kota
)
),
length(
unique(
data_final$status
)
)
)
)
perbandinganTidak selalu. Penghapusan atau imputasi missing value dapat mengurangi informasi atau mengubah distribusi data. Kualitas data perlu dinilai berdasarkan tujuan analisis dan alasan munculnya missing value.
Outlier dapat merupakan kesalahan pencatatan, tetapi dapat pula merupakan observasi yang benar dan penting. Oleh karena itu, outlier perlu diperiksa berdasarkan konteks dan aturan domain.
Preprocessing dapat menimbulkan bias apabila data dihapus, diimputasi, atau ditransformasikan menggunakan aturan yang tidak sesuai sehingga distribusi atau karakteristik asli data berubah.
Agar informasi dari data pengujian tidak masuk ke proses pembentukan model. Jika parameter dihitung menggunakan seluruh data, dapat terjadi data leakage.
Identifier yang tidak unik dapat menyebabkan satu baris data bergabung dengan beberapa baris pada sumber lain sehingga jumlah baris bertambah secara tidak semestinya dan menghasilkan data yang salah.
Alur preprocessing yang telah dilakukan:
Kesimpulan: preprocessing bukan hanya menjalankan fungsi R, tetapi merupakan proses pengambilan keputusan berdasarkan struktur data, konteks, tujuan analisis, dan aturan domain.
Han, J., Kamber, M., & Pei, J. (2012). Data Mining: Concepts and Techniques (3rd ed.). Morgan Kaufmann. Chapter 3: Data Preprocessing.