Identitas Praktikum

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

Capaian Praktikum

Setelah menyelesaikan praktikum, mahasiswa mampu:

  1. menjelaskan kondisi data yang menyebabkan preprocessing diperlukan;
  2. mengidentifikasi masalah kualitas data menggunakan R;
  3. menerapkan data cleaning secara sistematis;
  4. memilih dan menerapkan strategi penanganan missing values;
  5. mendeteksi serta mengevaluasi outlier;
  6. melakukan transformasi atribut numerik; dan
  7. mengintegrasikan dua sumber data serta memvalidasi hasilnya.

Skenario Praktikum

Sebuah perusahaan e-commerce akan melakukan analisis pelanggan. Data berasal dari dua sumber:

  • Data pelanggan, yang memuat identitas, usia, kota, pendapatan, dan status pelanggan.
  • Data transaksi, yang memuat jumlah transaksi dan total pembelian.

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.

Persiapan RStudio

Membuat Proyek

  1. Buka RStudio.
  2. Pilih File → New Project → New Directory → New Project.
  3. Beri nama proyek, misalnya praktikum_preprocessing.
  4. Simpan file .Rmd di dalam folder proyek.
  5. Klik Knit untuk menghasilkan HTML.

Memeriksa Lingkungan Kerja

getwd()
## [1] "C:/Users/user/Documents/SEM 5/DATA MINING"
R.version.string
## [1] "R version 4.5.0 (2025-04-11 ucrt)"

Membangun Dataset Praktikum

Dataset dibuat secara sengaja memiliki beberapa masalah kualitas data agar setiap tahap preprocessing dapat dipraktikkan.

Data Pelanggan

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_raw

Kualitas 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.

Data Transaksi

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

Konsep Data Preprocessing

Memahami Struktur Data

Dimensi Data

dim(pelanggan_raw)
## [1] 20  6

Nama Variabel

names(pelanggan_raw)
## [1] "customer_id" "nama"        "usia"        "pendapatan"  "kota"       
## [6] "status"

Struktur Data

str(pelanggan_raw)
## '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" ...

Lima Baris Pertama

head(pelanggan_raw)

Ringkasan Statistik

summary(pelanggan_raw)
##  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  
##                                       
##                                       
##                                       
## 

Mengukur Kualitas Awal

Missing Value

colSums(is.na(pelanggan_raw))
## customer_id        nama        usia  pendapatan        kota      status 
##           0           0           2           3           2           2

Persentase Missing Value

round(
  colMeans(is.na(pelanggan_raw)) * 100,
  2
)
## customer_id        nama        usia  pendapatan        kota      status 
##           0           0          10          15          10          10

Duplikasi Baris

sum(duplicated(pelanggan_raw))
## [1] 2

Duplikasi Customer ID

sum(duplicated(pelanggan_raw$customer_id))
## [1] 2

Kategori Kota

sort(unique(pelanggan_raw$kota))
##  [1] " PEKANBARU " " PKU"        "dumai"       "Dumai"       "DUMAI"      
##  [6] "pekanbaru"   "Pekanbaru"   "PEKANBARU"   "Pekanbaru "  "PKU"        
## [11] "Siak"        "Siak "

Kategori Status

sort(unique(pelanggan_raw$status))
## [1] "A"           "ACTIVE"      "aktif"       "Aktif"       "AKTIF"      
## [6] "nonaktif"    "Tidak aktif" "Tidak Aktif"

Rentang Usia

range(
  pelanggan_raw$usia,
  na.rm = TRUE
)
## [1]  21 200

Rentang Pendapatan

range(
  pelanggan_raw$pendapatan,
  na.rm = TRUE
)
## [1] 4.5e+06 7.5e+08

Membuat Fungsi Ringkasan Kualitas

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

Interpretasi awal: audit digunakan untuk menemukan atribut yang memerlukan pemeriksaan lebih lanjut. Hasil audit belum merupakan keputusan untuk menghapus, mengganti, atau mempertahankan data.

Implementasi Data Cleaning

Membuat Salinan Kerja

pelanggan <- pelanggan_raw

Membersihkan Spasi dan Kapitalisasi

Menghapus Spasi

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

Menyeragamkan Huruf

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

Melihat Kategori Kota

sort(unique(pelanggan$kota))
## [1] "dumai"     "pekanbaru" "pku"       "siak"

Melihat Kategori Status

sort(unique(pelanggan$status))
## [1] "a"           "active"      "aktif"       "nonaktif"    "tidak aktif"

Menyeragamkan Kategori

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"

Hasil Standardisasi Kota

sort(unique(pelanggan$kota))
## [1] "Dumai"     "Pekanbaru" "Siak"

Hasil Standardisasi Status

sort(unique(pelanggan$status))
## [1] "Aktif"       "Tidak Aktif"

Mendeteksi dan Menghapus Duplikasi

Menampilkan Customer ID yang Berulang

pelanggan[
  duplicated(pelanggan$customer_id) |
    duplicated(pelanggan$customer_id, fromLast = TRUE),
]

Menghapus Duplikasi

pelanggan <- pelanggan[
  !duplicated(pelanggan$customer_id),
]

rownames(pelanggan) <- NULL

dim(pelanggan)
## [1] 18  6

Penghapusan duplikasi hanya dilakukan karena customer_id ditetapkan sebagai identifier unik untuk satu pelanggan.

Memeriksa Aturan Domain

Pemeriksaan Usia

Aturan domain yang digunakan adalah usia antara 15 sampai 100 tahun.

pelanggan[
  pelanggan$usia < 15 |
    pelanggan$usia > 100,
]

Pemeriksaan Pendapatan Negatif

pelanggan[
  pelanggan$pendapatan < 0,
]

Koreksi Nilai Usia

Jika pemeriksaan terhadap sumber asli menunjukkan bahwa nilai C004 seharusnya 50, maka dilakukan koreksi.

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

Memeriksa Hasil Koreksi

pelanggan[
  pelanggan$customer_id == "C004",
]

Membuat Log Perubahan

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

Penanganan Missing Values

Mengidentifikasi Lokasi Missing Value

Jumlah Missing Value

colSums(is.na(pelanggan))
## customer_id        nama        usia  pendapatan        kota      status 
##           0           0           2           3           2           1

Menampilkan Baris yang Memiliki Missing Value

pelanggan[
  !complete.cases(pelanggan),
]

Strategi 1 — Menghapus Baris

pelanggan_complete <- pelanggan[
  complete.cases(pelanggan),
]

nrow(pelanggan)
## [1] 18
nrow(pelanggan_complete)
## [1] 11

Persentase Data yang Hilang

round(
  (
    1 -
      nrow(pelanggan_complete) /
      nrow(pelanggan)
  ) * 100,
  2
)
## [1] 38.89

Strategi 2 — Imputasi Mean dan Median

Mean Pendapatan

mean_pendapatan <- mean(
  pelanggan$pendapatan,
  na.rm = TRUE
)

mean_pendapatan
## [1] 87610000

Median Pendapatan

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

median_pendapatan
## [1] 5050000

Imputasi Pendapatan dengan Median

pelanggan$pendapatan_imputasi <-
  pelanggan$pendapatan

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

Imputasi Usia dengan Median

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

pelanggan$usia_imputasi <-
  pelanggan$usia

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

Membandingkan Nilai

pelanggan[
  ,
  c(
    "customer_id",
    "usia",
    "usia_imputasi",
    "pendapatan",
    "pendapatan_imputasi"
  )
]

Strategi 3 — Imputasi Nilai Kategorik

pelanggan$kota_imputasi <-
  pelanggan$kota

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

Frekuensi Kota

table(
  pelanggan$kota_imputasi,
  useNA = "ifany"
)
## 
##           Dumai       Pekanbaru            Siak Tidak diketahui 
##               5               9               2               2

Menambahkan Indikator Missing

pelanggan$pendapatan_missing <-
  as.integer(
    is.na(pelanggan$pendapatan)
  )
table(
  pelanggan$pendapatan_missing
)
## 
##  0  1 
## 15  3

Membandingkan Distribusi Sebelum dan Sesudah Imputasi

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
)

par(mfrow = c(1, 1))

Imputasi dapat mengubah distribusi dan mengurangi variasi data. Karena itu, pemeriksaan perlu dilanjutkan setelah imputasi.

Penanganan Outlier

Visualisasi dengan Boxplot

boxplot(
  pelanggan$pendapatan_imputasi,
  horizontal = TRUE,
  main = "Boxplot Pendapatan",
  xlab = "Pendapatan"
)

Menghitung Batas 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

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

Menandai Kandidat Outlier

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

Menampilkan Kandidat Outlier

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

Winsorization

Nilai ekstrem dipertahankan, kemudian dibuat variabel pembanding winsorized.

pelanggan$pendapatan_winsor <-
  pmin(
    pmax(
      pelanggan$pendapatan_imputasi,
      batas_bawah
    ),
    batas_atas
  )

Membandingkan Nilai Outlier

pelanggan[
  pelanggan$outlier_pendapatan,
  c(
    "customer_id",
    "pendapatan_imputasi",
    "pendapatan_winsor"
  )
]

Transformasi Data

Normalisasi Min-Max

Rumus normalisasi min-max:

\[ x' = \frac{x-\min(x)} {\max(x)-\min(x)} \]

Membuat Fungsi Min-Max

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
}

Transformasi Usia

pelanggan$usia_minmax <-
  minmax(
    pelanggan$usia_imputasi
  )

Transformasi Pendapatan

pelanggan$pendapatan_minmax <-
  minmax(
    pelanggan$pendapatan_imputasi
  )

Hasil Normalisasi

pelanggan[
  ,
  c(
    "customer_id",
    "usia",
    "usia_minmax",
    "pendapatan_imputasi",
    "pendapatan_minmax"
  )
]

Normalisasi Z-Score

Rumus z-score:

\[ z = \frac{x-\bar{x}}{s} \]

Z-Score Usia

pelanggan$usia_z <-
  as.numeric(
    scale(
      pelanggan$usia_imputasi
    )
  )

Z-Score Pendapatan

pelanggan$pendapatan_z <-
  as.numeric(
    scale(
      pelanggan$pendapatan_imputasi
    )
  )

Hasil Z-Score

round(
  pelanggan[
    ,
    c(
      "usia_z",
      "pendapatan_z"
    )
  ],
  3
)

Decimal Scaling

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 Decimal Scaling

pelanggan$pendapatan_decimal <-
  decimal_scale(
    pelanggan$pendapatan_imputasi
  )

Rentang Hasil

range(
  pelanggan$pendapatan_decimal,
  na.rm = TRUE
)
## [1] 0.0045 0.7500

Membandingkan Metode Transformasi

transformasi <- pelanggan[
  ,
  c(
    "customer_id",
    "pendapatan_imputasi",
    "pendapatan_minmax",
    "pendapatan_z",
    "pendapatan_decimal"
  )
]

transformasi

Dampak Outlier terhadap Normalisasi

pelanggan$pendapatan_winsor_minmax <-
  minmax(
    pelanggan$pendapatan_winsor
  )

Penting: 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
)

Integrasi Data

Memeriksa Kunci pada Kedua Sumber

Duplikasi pada Data Pelanggan

sum(
  duplicated(
    pelanggan$customer_id
  )
)
## [1] 0

Duplikasi pada Data Transaksi

sum(
  duplicated(
    transaksi_raw$cust_id
  )
)
## [1] 1

Pelanggan yang Tidak Memiliki Transaksi

setdiff(
  pelanggan$customer_id,
  transaksi_raw$cust_id
)
## [1] "C011"

Transaksi yang Tidak Memiliki Data Pelanggan

setdiff(
  transaksi_raw$cust_id,
  pelanggan$customer_id
)
## character(0)

Menyelaraskan Nama Identifier

transaksi <- transaksi_raw

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

names(transaksi)
## [1] "customer_id"      "jumlah_transaksi" "total_purchase"

Melakukan Integrasi dengan Merge

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

Melihat Hasil Integrasi

data_terintegrasi[
  ,
  c(
    "customer_id",
    "nama",
    "jumlah_transaksi",
    "total_purchase"
  )
]

all.x = TRUE mempertahankan seluruh pelanggan dari tabel utama, termasuk pelanggan yang tidak memiliki pasangan transaksi.

Memvalidasi Hasil Integrasi

Membandingkan Jumlah Baris

c(
  sebelum = nrow(pelanggan),
  sesudah = nrow(data_terintegrasi)
)
## sebelum sesudah 
##      18      19

Memeriksa Duplikasi

sum(
  duplicated(
    data_terintegrasi$customer_id
  )
)
## [1] 1

Missing Value pada Variabel Transaksi

colSums(
  is.na(
    data_terintegrasi[
      ,
      c(
        "jumlah_transaksi",
        "total_purchase"
      )
    ]
  )
)
## jumlah_transaksi   total_purchase 
##                1                1

Menampilkan Pelanggan Tanpa Transaksi

data_terintegrasi[
  is.na(
    data_terintegrasi$jumlah_transaksi
  ),
  c(
    "customer_id",
    "nama"
  )
]

Menentukan Penanganan NA pada Transaksi

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.

Membuat Variabel Final Transaksi

data_terintegrasi$jumlah_transaksi_final <-
  data_terintegrasi$jumlah_transaksi

data_terintegrasi$total_purchase_final <-
  data_terintegrasi$total_purchase

Mengganti NA dengan Nol

Pada skenario praktikum, NA dianggap sebagai pelanggan yang belum memiliki transaksi.

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

Memeriksa Hasil

data_terintegrasi[
  ,
  c(
    "customer_id",
    "jumlah_transaksi",
    "jumlah_transaksi_final",
    "total_purchase",
    "total_purchase_final"
  )
]

Dataset Akhir dan Evaluasi

Memilih Atribut 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"
  )
]

Mengubah Nama Variabel

names(data_final)[
  names(data_final) == "kota_imputasi"
] <- "kota"

names(data_final)[
  names(data_final) == "usia_imputasi"
] <- "usia"

Melihat Dataset Final

data_final

Audit Akhir

audit_akhir <-
  audit_data(
    data_final
  )

audit_akhir

Memeriksa Duplikasi Customer ID

sum(
  duplicated(
    data_final$customer_id
  )
)
## [1] 1

Memeriksa Missing Value

colSums(
  is.na(data_final)
)
##            customer_id                   nama                   usia 
##                      0                      0                      0 
##                   kota                 status    pendapatan_imputasi 
##                      0                      1                      0 
##     pendapatan_missing     outlier_pendapatan            usia_minmax 
##                      0                      0                      0 
##      pendapatan_minmax jumlah_transaksi_final   total_purchase_final 
##                      0                      0                      0

Membandingkan Kondisi Sebelum dan Sesudah

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
      )
    )
  )
)

perbandingan

Menyimpan Hasil

Menyimpan Dataset Final

write.csv(
  data_final,
  "data_pelanggan_setelah_preprocessing.csv",
  row.names = FALSE
)

Menyimpan Log Perubahan

write.csv(
  log_perubahan,
  "log_perubahan_preprocessing.csv",
  row.names = FALSE
)

Pertanyaan Refleksi

1. Apakah dataset tanpa missing value selalu lebih berkualitas?

Tidak 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.

2. Mengapa outlier tidak boleh otomatis dihapus?

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.

3. Bagaimana preprocessing dapat menimbulkan bias?

Preprocessing dapat menimbulkan bias apabila data dihapus, diimputasi, atau ditransformasikan menggunakan aturan yang tidak sesuai sehingga distribusi atau karakteristik asli data berubah.

4. Mengapa parameter imputasi dan transformasi seharusnya dihitung dari data pelatihan?

Agar informasi dari data pengujian tidak masuk ke proses pembentukan model. Jika parameter dihitung menggunakan seluruh data, dapat terjadi data leakage.

5. Apa risiko integrasi data jika identifier tidak unik?

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.

Ringkasan

Alur preprocessing yang telah dilakukan:

  1. memahami struktur dan kualitas awal data;
  2. membersihkan kategori, duplikasi, dan pelanggaran domain;
  3. menangani missing values;
  4. mendeteksi dan mengevaluasi outlier;
  5. melakukan transformasi atribut numerik;
  6. mengintegrasikan dua sumber data; dan
  7. melakukan audit terhadap dataset akhir.

Kesimpulan: preprocessing bukan hanya menjalankan fungsi R, tetapi merupakan proses pengambilan keputusan berdasarkan struktur data, konteks, tujuan analisis, dan aturan domain.

Daftar Pustaka

Han, J., Kamber, M., & Pei, J. (2012). Data Mining: Concepts and Techniques (3rd ed.). Morgan Kaufmann. Chapter 3: Data Preprocessing.