Identitas

Nama: Talitah Kinasih Sawity

NIM: 2403111547

Persiapan RStudio

Membuat Proyek

Sebelum memulai proses pengolahan data, terlebih dahulu dibuat sebuah proyek pada RStudio. Proyek ini digunakan sebagai tempat untuk menyimpan file .Rmd, data, serta hasil preprocessing yang akan dihasilkan.

Langkah-langkahnya adalah sebagai berikut:

  • Buka aplikasi RStudio.
  • Pilih menu File → New Project.
  • Selanjutnya pilih New Directory → New Project.
  • Tentukan nama proyek, misalnya praktikum_preprocessing.
  • Simpan file .Rmd pada folder proyek tersebut.
  • Setelah seluruh proses selesai, klik Knit untuk menghasilkan output dalam bentuk HTML.

Memeriksa Lingkungan Kerja

Langkah awal yang dapat dilakukan adalah mengetahui direktori kerja yang sedang digunakan oleh RStudio.

getwd()
## [1] "D:/Users/HP/Documents/SEMESTER 5/DATA MINING"

Selain itu, versi R yang digunakan juga dapat diperiksa.

R.version.string
## [1] "R version 4.6.1 (2026-06-24 ucrt)"

Dalam proses ini digunakan fungsi-fungsi dasar dari R sehingga tidak memerlukan instalasi package tambahan.

Dataset Praktikum

Pada praktikum ini digunakan dua dataset, yaitu dataset pelanggan dan dataset transaksi. Dataset tersebut dibuat sebagai contoh data yang masih memiliki beberapa permasalahan kualitas data.

Beberapa masalah yang terdapat dalam data antara lain:

  • Missing value
  • Data duplikat
  • Penulisan kategori yang tidak konsisten
  • Nilai yang tidak wajar
  • Perbedaan format penulisan data
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
)

Menampilkan Dataset Pelanggan

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

Menampilkan Dataset Transaksi

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

Memahami Struktur Data

Sebelum melakukan proses preprocessing, struktur data perlu diperiksa terlebih dahulu. Tahap ini dilakukan untuk mengetahui jumlah observasi, jumlah variabel, nama variabel, tipe data, serta gambaran umum dari dataset.

Dimensi Data

digunakan untuk melihat jumlah baris dan kolom pada dataset.

dim(pelanggan_raw)
## [1] 12  6

Nama Variabel

digunakan untuk menampilkan nama setiap variabel atau kolom.

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

Struktur Data

digunakan untuk melihat struktur dataset secara keseluruhan, termasuk tipe data dari setiap variabel.

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

Lima Data Pertama

head(pelanggan_raw)
##   customer_id  nama usia pendapatan      kota      status
## 1        C001   Ani   21    4500000 Pekanbaru       Aktif
## 2        C002  Budi   25         NA       PKU       aktif
## 3        C003 Citra   23    5200000 PEKANBARU      ACTIVE
## 4        C004  Dodi  150    4800000     Dumai           A
## 5        C005   Eka   27    4900000 pekanbaru Tidak Aktif
## 6        C006  Fani   NA    5100000     DUMAI    nonaktif

Statistik Deskriptif

summary(pelanggan_raw)
##     customer_id        nama         usia          pendapatan       
##  Length   :12   Length   :12   Min.   : 21.00   Min.   :  4500000  
##  N.unique :11   N.unique :11   1st Qu.: 24.00   1st Qu.:  4725000  
##  N.blank  : 0   N.blank  : 0   Median : 28.00   Median :  5000000  
##  Min.nchar: 4   Min.nchar: 3   Mean   : 38.73   Mean   : 54440000  
##  Max.nchar: 4   Max.nchar: 6   3rd Qu.: 33.00   3rd Qu.:  5275000  
##                                Max.   :150.00   Max.   :500000000  
##                                NAs    :1        NAs    :2          
##         kota          status  
##  Length   :12   Length   :12  
##  N.unique : 9   N.unique : 8  
##  N.blank  : 0   N.blank  : 0  
##  Min.nchar: 3   Min.nchar: 1  
##  Max.nchar:10   Max.nchar:11  
##  NAs      : 1                 
## 

Pemeriksaan Kualitas Data Awal

Pada tahap ini dilakukan pemeriksaan terhadap beberapa masalah yang mungkin terdapat dalam dataset.

Missing Value

Missing value merupakan data yang nilainya kosong atau tidak tersedia.

Jumlah missing value pada setiap variabel dapat diperiksa menggunakan kode berikut.

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

Persentase missing value juga dapat dihitung sebagai berikut.

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

Duplikasi Data

Data duplikat dapat terjadi ketika terdapat observasi yang sama atau identifier pelanggan yang muncul lebih dari satu kali.

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

Pemeriksaan duplikasi berdasarkan customer_id dilakukan dengan:

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

Konsistensi Kategori

Selanjutnya dilakukan pemeriksaan terhadap kategori pada variabel kota dan status.

sort(unique(pelanggan_raw$kota))
## [1] " PKU"       "Dumai"      "DUMAI"      "pekanbaru"  "Pekanbaru" 
## [6] "PEKANBARU"  "Pekanbaru " "PKU"        "Siak"
sort(unique(pelanggan_raw$status))
## [1] "A"           "ACTIVE"      "aktif"       "Aktif"       "AKTIF"      
## [6] "nonaktif"    "Tidak aktif" "Tidak Aktif"

Dari hasil tersebut dapat terlihat bahwa terdapat beberapa kategori yang sebenarnya memiliki makna sama tetapi ditulis dengan format yang berbeda.

Pemeriksaan Nilai Numerik

Nilai minimum dan maksimum dari variabel numerik dapat diperiksa sebagai berikut.

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

Untuk mempermudah pemeriksaan kondisi dataset, dibuat sebuah fungsi audit data.

Fungsi ini digunakan untuk menampilkan:

  • Nama atribut
  • Tipe data
  • Jumlah missing value
  • Persentase missing value
  • Jumlah nilai unik
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 data awal dilakukan menggunakan:

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          10
## 6      status character              0           0.00           8

Data Cleaning

Agar dataset asli tetap tersimpan, proses pembersihan dilakukan menggunakan salinan dari dataset awal.

pelanggan <- pelanggan_raw

Membersihkan Spasi

Beberapa data pada variabel kota memiliki spasi yang tidak diperlukan. Oleh karena itu digunakan fungsi trimws().

pelanggan$kota <- trimws(pelanggan$kota)

pelanggan$status <- trimws(pelanggan$status)

Menyeragamkan Huruf

Untuk memudahkan proses standardisasi, seluruh kategori sementara diubah menjadi huruf kecil.

pelanggan$kota <- tolower(pelanggan$kota)

pelanggan$status <- tolower(pelanggan$status)

Hasil kategori setelah dibersihkan dapat diperiksa kembali.

sort(unique(pelanggan$kota))
## [1] "dumai"     "pekanbaru" "pku"       "siak"
sort(unique(pelanggan$status))
## [1] "a"           "active"      "aktif"       "nonaktif"    "tidak aktif"

Standardisasi Kota

Beberapa kategori kota yang berbeda sebenarnya mengacu pada lokasi yang sama.

pelanggan$kota[
  pelanggan$kota %in% c("pku", "pekanbaru")
] <- "Pekanbaru"

pelanggan$kota[
  pelanggan$kota == "dumai"
] <- "Dumai"

pelanggan$kota[
  pelanggan$kota == "siak"
] <- "Siak"

Hasil standardisasi kota:

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

Standardisasi Status

Kategori status juga diseragamkan agar memiliki format yang konsisten.

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

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

Hasil standardisasi status:

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

Menangani Data Duplikat

Data dengan customer_id yang muncul lebih dari satu kali diperiksa terlebih dahulu.

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

Selanjutnya, data duplikat dihapus berdasarkan customer_id.

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

rownames(pelanggan) <- NULL

dim(pelanggan)
## [1] 11  6

Koreksi Nilai Berdasarkan Domain

Pada variabel usia terdapat nilai 150 yang dianggap tidak wajar untuk data pelanggan pada contoh ini.

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 tersebut kemudian dikoreksi menjadi 50.

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

Log Perubahan Data

Setiap perubahan yang dilakukan selama preprocessing dapat dicatat dalam sebuah log.

log_perubahan <- data.frame(
  
  tahap = c(
    "Standardisasi",
    "Standardisasi",
    "Deduplikasi",
    "Koreksi domain"
  ),
  
  atribut = c(
    "kota",
    "status",
    "customer_id",
    "usia"
  ),
  
  tindakan = c(
    "PKU dan variasi kapital diseragamkan menjadi Pekanbaru",
    "ACTIVE dan A menjadi Aktif, sedangkan nonaktif menjadi Tidak Aktif",
    "Menghapus data customer_id C010 yang muncul lebih dari satu kali",
    "Usia C004 dikoreksi dari 150 menjadi 50"
  ),
  
  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 diseragamkan menjadi Pekanbaru
## 2 ACTIVE dan A menjadi Aktif, sedangkan nonaktif menjadi Tidak Aktif
## 3   Menghapus data customer_id C010 yang muncul lebih dari satu kali
## 4                            Usia C004 dikoreksi dari 150 menjadi 50

Penanganan Missing Value

Identifikasi Missing Value

Setelah proses cleaning, missing value kembali diperiksa.

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

Baris yang memiliki missing value dapat ditampilkan dengan:

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

Penghapusan Baris

Sebagai perbandingan, dapat dilihat jumlah data jika seluruh baris yang memiliki missing value dihapus.

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

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

Persentase data yang hilang apabila seluruh baris missing dihapus adalah:

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

Imputasi Pendapatan

Pada variabel pendapatan terdapat nilai yang sangat besar sehingga mean dapat terpengaruh oleh nilai ekstrem.

Oleh karena itu dilakukan perbandingan antara mean dan median.

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

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

mean_pendapatan
## [1] 59900000
median_pendapatan
## [1] 4900000

Dalam kasus ini, median digunakan untuk mengisi missing value karena lebih tahan terhadap pengaruh outlier.

pelanggan$pendapatan_imputasi <- pelanggan$pendapatan

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

Imputasi Usia

Nilai usia yang hilang juga ditangani menggunakan median.

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

pelanggan$usia_imputasi <- pelanggan$usia

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

Hasil imputasi dapat dilihat sebagai berikut.

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

Imputasi Variabel Kategorik

Missing value pada variabel kota diberikan kategori Tidak diketahui.

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

Indikator Missing

Untuk mengetahui data mana yang sebelumnya memiliki missing value pada pendapatan, dibuat variabel indikator.

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

table(pelanggan$pendapatan_missing)
## 
## 0 1 
## 9 2

Penanganan Outlier

Visualisasi Boxplot

Outlier pada pendapatan dapat dilihat menggunakan boxplot.

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

Metode IQR

Identifikasi outlier dilakukan menggunakan metode Interquartile Range atau 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% 
##         4750000         5150000          400000         4150000         5750000

Menandai Outlier

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

Data yang termasuk outlier:

pelanggan[
  pelanggan$outlier_pendapatan,
  c(
    "customer_id",
    "nama",
    "pendapatan_imputasi"
  )
]
##   customer_id   nama pendapatan_imputasi
## 7        C007 Gilang               5e+08

Winsorizing

Nilai ekstrem tidak langsung dihapus. Sebagai contoh penanganan, dilakukan winsorizing dengan membatasi nilai berdasarkan batas IQR.

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

Perbandingan nilai sebelum dan sesudah winsorizing:

pelanggan[
  pelanggan$outlier_pendapatan,
  c(
    "customer_id",
    "pendapatan_imputasi",
    "pendapatan_winsor"
  )
]
##   customer_id pendapatan_imputasi pendapatan_winsor
## 7        C007               5e+08           5750000

Transformasi Data

Transformasi data dilakukan agar variabel numerik dapat memiliki skala yang lebih sesuai dengan kebutuhan analisis.

Normalisasi Min-Max

Rumus normalisasi Min-Max adalah:

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

Fungsi normalisasi:

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
}

Normalisasi dilakukan pada variabel usia dan pendapatan.

pelanggan$usia_minmax <- minmax(
  pelanggan$usia_imputasi
)

pelanggan$pendapatan_minmax <- minmax(
  pelanggan$pendapatan_imputasi
)

Hasil normalisasi:

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

Standardisasi Z-Score

Rumus standardisasi Z-Score adalah:

\[ 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 Scaling

Decimal scaling dilakukan dengan membagi nilai berdasarkan pangkat 10 tertentu.

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

Integrasi Data

Setelah data pelanggan dibersihkan, dataset tersebut digabungkan dengan data transaksi.

Pemeriksaan Kunci

Sebelum melakukan penggabungan, dilakukan pemeriksaan terhadap identifier pada kedua dataset.

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

Pemeriksaan ID yang tidak memiliki pasangan:

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

Menyamakan Nama Identifier

Variabel cust_id pada dataset transaksi diubah menjadi customer_id.

transaksi <- transaksi_raw

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

Menggabungkan Dataset

Penggabungan dilakukan menggunakan fungsi merge().

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

Hasil integrasi:

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

Validasi Hasil Integrasi

Jumlah data sebelum dan sesudah penggabungan diperiksa kembali.

c(
  sebelum = nrow(pelanggan),
  sesudah = nrow(data_terintegrasi)
)
## sebelum sesudah 
##      11      11

Pemeriksaan duplikasi:

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

Pemeriksaan missing value setelah integrasi:

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

Data yang belum memiliki transaksi:

data_terintegrasi[
  is.na(
    data_terintegrasi$jumlah_transaksi
  ),
  c(
    "customer_id",
    "nama"
  )
]
##    customer_id nama
## 11        C011 Kiki

Menangani Missing Setelah Integrasi

Jika nilai NA berarti pelanggan belum pernah melakukan transaksi, maka nilai tersebut dapat diganti menjadi nol.

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

Setelah seluruh proses preprocessing selesai, dipilih variabel yang akan digunakan sebagai 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"
  )
]

Nama beberapa variabel kemudian disederhanakan.

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

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

Menampilkan dataset akhir:

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 kembali dilakukan untuk memastikan data hasil preprocessing sudah lebih siap digunakan.

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

Pemeriksaan duplikasi:

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

Pemeriksaan missing value:

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

Perbandingan Sebelum dan Sesudah

Untuk melihat perubahan kualitas data, dilakukan perbandingan antara dataset sebelum dan sesudah preprocessing.

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
##               indikator sebelum sesudah
## 1          Jumlah baris      12      11
## 2 Duplikasi customer_id       1       0
## 3   Total missing value       4       0
## 4    Kategori kota unik      10       4
## 5  Kategori status unik       8       2

Menyimpan Hasil

Dataset akhir dapat disimpan dalam format CSV.

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

Log perubahan juga dapat disimpan.

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

Kesimpulan

Berdasarkan proses yang telah dilakukan, preprocessing data dilakukan melalui beberapa tahapan utama, yaitu pemeriksaan struktur data, evaluasi kualitas data, data cleaning, penanganan missing value, identifikasi outlier, transformasi data, dan integrasi data.

Pada tahap data cleaning, dilakukan penyeragaman penulisan kategori, penghapusan data duplikat, serta perbaikan nilai yang dianggap tidak sesuai dengan kondisi data. Missing value pada variabel numerik ditangani menggunakan metode imputasi median, sedangkan missing value pada data kategorik diberikan kategori khusus.

Selanjutnya, keberadaan outlier pada variabel pendapatan diidentifikasi menggunakan metode IQR. Nilai ekstrem tersebut kemudian ditandai dan dilakukan contoh penanganan menggunakan metode winsorizing.

Transformasi data juga dilakukan melalui normalisasi Min-Max, standardisasi Z-Score, dan decimal scaling. Setelah itu, dataset pelanggan digabungkan dengan dataset transaksi berdasarkan customer_id.

Melalui seluruh tahapan tersebut, kualitas dataset menjadi lebih baik, lebih konsisten, dan lebih siap untuk digunakan pada proses analisis data maupun tahap data mining selanjutnya.

Daftar Pustaka

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

````