1 Pendahuluan

Data pelanggan dan transaksi dapat digunakan untuk memahami karakteristik pelanggan serta aktivitas pembelian. Sebelum digunakan untuk analisis, data perlu diperiksa dan dipersiapkan karena masih terdapat beberapa masalah kualitas data.

Pada kasus ini digunakan dua sumber data, yaitu data pelanggan dan data transaksi. Tujuan preprocessing adalah menghasilkan dataset yang lebih konsisten dan siap digunakan untuk analisis clustering.

Alur preprocessing: Understand → Clean → Transform → Integrate → Evaluate

2 1. Understand

2.1 1.1 Tujuan dan Unit Observasi

Unit observasi adalah pelanggan e-commerce. Atribut yang akan digunakan untuk analisis meliputi usia, pendapatan, jumlah transaksi, dan total pembelian. customer_id digunakan sebagai identifier, bukan sebagai variabel clustering.

2.2 1.2 Data Awal

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
)

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
)

2.2.1 Data pelanggan

datatable(pelanggan_raw, filter="top", rownames=FALSE,
          options=list(pageLength=10, scrollX=TRUE))

2.2.2 Data transaksi

datatable(transaksi_raw, filter="top", rownames=FALSE,
          options=list(pageLength=10, scrollX=TRUE))

Data pelanggan terdiri dari 12 baris dan 6 variabel. Data transaksi terdiri dari 11 baris dan menggunakan identifier cust_id.

2.3 1.3 Masalah Data

Masalah yang ditemukan pada data awal adalah:

  • missing value pada usia, pendapatan, dan kota;
  • kategori kota dan status ditulis dengan format berbeda;
  • customer_id C010 tercatat dua kali;
  • usia C004 bernilai 150;
  • pendapatan C007 sebesar Rp500.000.000 jauh lebih tinggi daripada observasi lainnya;
  • identifier transaksi menggunakan cust_id, sedangkan data pelanggan menggunakan customer_id.

3 2. Clean

3.1 2.1 Pemeriksaan Missing Value

missing_awal <- data.frame(
  atribut = names(pelanggan_raw),
  jumlah_missing = sapply(pelanggan_raw, function(x) sum(is.na(x))),
  persen_missing = round(sapply(pelanggan_raw, function(x) mean(is.na(x))*100),2)
)

datatable(missing_awal, filter="top", rownames=FALSE,
          options=list(pageLength=10))

3.2 2.2 Standardisasi Kategori

pelanggan <- pelanggan_raw

pelanggan$kota <- tolower(trimws(pelanggan$kota))
pelanggan$status <- tolower(trimws(pelanggan$status))

pelanggan$kota[pelanggan$kota %in% c("pku","pekanbaru")] <- "Pekanbaru"
pelanggan$kota[pelanggan$kota == "dumai"] <- "Dumai"
pelanggan$kota[pelanggan$kota == "siak"] <- "Siak"

pelanggan$status[pelanggan$status %in% c("aktif","active","a")] <- "Aktif"
pelanggan$status[pelanggan$status %in% c("tidak aktif","nonaktif")] <- "Tidak Aktif"

Setelah standardisasi, kategori kota menjadi Pekanbaru, Dumai, dan Siak, sedangkan status menjadi Aktif dan Tidak Aktif.

3.3 2.3 Menghapus Duplikasi

# C010 muncul dua kali, sehingga salah satu baris dihapus
pelanggan <- pelanggan[!duplicated(pelanggan$customer_id), ]
rownames(pelanggan) <- NULL

Jumlah pelanggan setelah deduplikasi menjadi 11 pelanggan.

3.4 2.4 Memperbaiki Nilai Usia

pelanggan$usia[pelanggan$customer_id == "C004"] <- 50

Usia C004 dikoreksi dari 150 menjadi 50 berdasarkan skenario data yang digunakan. Pendapatan tidak memiliki nilai negatif.

4 3. Clean — Missing Value dan Outlier

4.1 3.1 Imputasi Missing Value

Untuk variabel numerik digunakan median karena terdapat nilai pendapatan yang sangat ekstrem. Missing value pada kota diberi kategori eksplisit Tidak diketahui.

median_usia <- median(pelanggan$usia, na.rm=TRUE)
median_pendapatan <- median(pelanggan$pendapatan, na.rm=TRUE)

pelanggan$usia_imputasi <- pelanggan$usia
pelanggan$usia_imputasi[is.na(pelanggan$usia_imputasi)] <- median_usia

pelanggan$pendapatan_imputasi <- pelanggan$pendapatan
pelanggan$pendapatan_imputasi[is.na(pelanggan$pendapatan_imputasi)] <- median_pendapatan

pelanggan$kota_imputasi <- pelanggan$kota
pelanggan$kota_imputasi[is.na(pelanggan$kota_imputasi)] <- "Tidak diketahui"

pelanggan$pendapatan_missing <- as.integer(is.na(pelanggan$pendapatan))

4.2 3.2 Deteksi Outlier dengan IQR

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

pelanggan$outlier_pendapatan <- pelanggan$pendapatan_imputasi < batas_bawah | pelanggan$pendapatan_imputasi > batas_atas

hasil_outlier <- pelanggan[pelanggan$outlier_pendapatan,
                           c("customer_id","nama","pendapatan_imputasi")]

hasil_outlier
##   customer_id   nama pendapatan_imputasi
## 7        C007 Gilang               5e+08

Pendapatan C007 sebesar Rp500.000.000 merupakan kandidat outlier. Nilai tersebut tidak langsung dihapus karena belum ada bukti bahwa nilai tersebut merupakan kesalahan pencatatan.

5 4. Transform

Variabel numerik memiliki skala berbeda sehingga perlu ditransformasikan sebelum analisis berbasis jarak. Pada bagian ini digunakan normalisasi Min-Max sebagai hasil transformasi utama.

Rumus Min-Max:

nilai baru = (nilai - minimum) / (maksimum - minimum)

minmax <- function(x) {
  r <- max(x, na.rm=TRUE) - min(x, na.rm=TRUE)
  if(r == 0) return(rep(0, length(x)))
  (x - min(x, na.rm=TRUE)) / r
}

pelanggan$usia_minmax <- minmax(pelanggan$usia_imputasi)
pelanggan$pendapatan_minmax <- minmax(pelanggan$pendapatan_imputasi)

5.0.1 Hasil Transformasi

transformasi <- pelanggan[, c("customer_id","usia_imputasi","usia_minmax",
                             "pendapatan_imputasi","pendapatan_minmax")]

datatable(transformasi, filter="top", rownames=FALSE,
          options=list(pageLength=10, scrollX=TRUE))

Hasil normalisasi berada pada rentang 0 sampai 1 sehingga skala variabel numerik menjadi lebih sebanding untuk analisis selanjutnya.

6 5. Integrate

6.1 5.1 Menyamakan Identifier

Data transaksi menggunakan cust_id, sedangkan data pelanggan menggunakan customer_id. Nama identifier disamakan sebelum penggabungan.

transaksi <- transaksi_raw
names(transaksi)[names(transaksi) == "cust_id"] <- "customer_id"

pelanggan_tanpa_transaksi <- setdiff(pelanggan$customer_id, transaksi$customer_id)
transaksi_tanpa_pelanggan <- setdiff(transaksi$customer_id, pelanggan$customer_id)

list(
  pelanggan_tanpa_transaksi = pelanggan_tanpa_transaksi,
  transaksi_tanpa_pelanggan = transaksi_tanpa_pelanggan
)
## $pelanggan_tanpa_transaksi
## [1] "C011"
## 
## $transaksi_tanpa_pelanggan
## [1] "C012"

C011 terdapat pada data pelanggan tetapi tidak memiliki pasangan transaksi. Sebaliknya, C012 terdapat pada data transaksi tetapi tidak terdapat pada data pelanggan.

6.2 5.2 Menggabungkan Data

Karena unit observasi adalah pelanggan, seluruh pelanggan dipertahankan menggunakan merge() dengan all.x = TRUE.

data_terintegrasi <- merge(
  pelanggan,
  transaksi,
  by = "customer_id",
  all.x = TRUE
)

7 6. Evaluate

7.1 6.1 Menangani Pelanggan Tanpa Transaksi

Pada kasus ini diasumsikan bahwa pelanggan tanpa data transaksi berarti belum melakukan transaksi. Oleh karena itu, nilai transaksi yang kosong 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

7.2 6.2 Dataset Akhir

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) == "usia_imputasi"] <- "usia"
names(data_final)[names(data_final) == "kota_imputasi"] <- "kota"

datatable(data_final, filter="top", rownames=FALSE,
          options=list(pageLength=10, scrollX=TRUE, autoWidth=TRUE))

Tabel di atas bersifat interaktif. Kolom dapat dicari, difilter, dan diurutkan. Tabel juga dapat digeser secara horizontal apabila layar tidak cukup lebar.

7.3 6.3 Perbandingan Sebelum dan Sesudah

perbandingan <- data.frame(
  indikator = c("Jumlah baris", "Duplikasi customer_id", "Total missing value"),
  sebelum = c(
    nrow(pelanggan_raw),
    sum(duplicated(pelanggan_raw$customer_id)),
    sum(is.na(pelanggan_raw))
  ),
  sesudah = c(
    nrow(data_final),
    sum(duplicated(data_final$customer_id)),
    sum(is.na(data_final))
  )
)

datatable(perbandingan, rownames=FALSE, options=list(dom="t"))

7.4 6.4 Evaluasi

Hasil preprocessing menunjukkan bahwa jumlah pelanggan berkurang dari 12 menjadi 11 karena satu duplikasi C010 dihapus. Duplikasi identifier menjadi 0. Missing value pada variabel utama pelanggan telah ditangani melalui imputasi, sedangkan data transaksi pelanggan tanpa transaksi direpresentasikan sebagai 0 sesuai asumsi kasus.

Kategori kota dan status juga telah diseragamkan. Usia C004 diperbaiki dan pendapatan C007 ditandai sebagai kandidat outlier tanpa menghapus nilai aslinya.

Apakah dataset lebih siap untuk clustering?

Ya. Dataset sudah lebih konsisten karena duplikasi telah ditangani, kategori telah distandardisasi, missing value telah ditangani, outlier telah diperiksa, variabel numerik telah ditransformasi, dan data pelanggan telah diintegrasikan dengan data transaksi.

8 Kesimpulan

Preprocessing dilakukan melalui lima tahapan utama, yaitu Understand, Clean, Transform, Integrate, dan Evaluate. Data awal memiliki beberapa permasalahan berupa missing value, ketidakkonsistenan kategori, duplikasi identifier, kesalahan nilai usia, dan nilai pendapatan ekstrem.

Setelah proses preprocessing, data menjadi lebih terstruktur dan konsisten. Dataset akhir dapat digunakan sebagai dasar untuk analisis clustering karena variabel numerik telah ditransformasikan dan informasi transaksi telah digabungkan dengan data pelanggan.

Dataset akhir siap digunakan untuk tahap analisis berikutnya. 🌸