DATA PREPROCASSING MENGGUNAKAN R

Pendahuluan

Data mining tidak hanya membutuhkan metode analisis yang tepat, tetapi juga membutuhkan data yang sudah diperiksa dan dipersiapkan dengan baik. Data yang diperoleh dari suatu sumber biasanya belum langsung dapat digunakan karena masih dapat ditemukan berbagai masalah, seperti data kosong, data yang terduplikasi, penulisan kategori yang tidak konsisten, serta nilai yang terlalu besar atau terlalu kecil dibandingkan data lainnya.

Pada tugas ini digunakan dua dataset sederhana, yaitu dataset pelanggan dan dataset transaksi. Dataset pelanggan berisi informasi mengenai identitas pelanggan, usia, pendapatan, kota tempat tinggal, dan status pelanggan. Sementara itu, dataset transaksi berisi jumlah transaksi dan total pembelian dari pelanggan.

Data tersebut sengaja dibuat memiliki beberapa masalah agar proses preprocessing dapat dilakukan secara langsung. Beberapa masalah yang terdapat pada data antara lain missing value, duplikasi customer_id, perbedaan penulisan kategori, nilai usia yang tidak wajar, serta nilai pendapatan yang cukup jauh dibandingkan nilai lainnya.

Tahapan yang dilakukan meliputi pemeriksaan kondisi awal data, data cleaning, penanganan duplikasi, pemeriksaan nilai tidak wajar, penanganan missing value, pemeriksaan dan penanganan outlier, transformasi data, integrasi data, serta pemeriksaan dataset akhir. Setiap tahap dilakukan secara bertahap agar kondisi data sebelum dan sesudah preprocessing dapat dibandingkan.

Tujuan dari preprocessing ini adalah menghasilkan dataset yang lebih rapi, konsisten, dan siap digunakan untuk proses analisis data mining selanjutnya.

1. Membangun Dataset

Dataset dibuat secara langsung menggunakan fungsi data.frame(). Data dibuat dengan beberapa kondisi yang umum ditemukan dalam proses preprocessing, sehingga setiap tahapan dapat diterapkan pada data yang sama.

1.1 Dataset Pelanggan

Dataset pelanggan berisi informasi mengenai identitas pelanggan, nama, usia, pendapatan, kota tempat tinggal, dan status pelanggan.

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
)

1.2 Dataset Transaksi

Dataset kedua adalah dataset transaksi. Dataset ini berisi jumlah transaksi dan total pembelian yang dilakukan oleh setiap pelanggan.

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
)

Dataset transaksi nantinya akan digabungkan dengan dataset pelanggan. Identifier yang digunakan pada dataset transaksi adalah cust_id, sedangkan dataset pelanggan menggunakan customer_id. Perbedaan nama tersebut akan diperbaiki sebelum proses integrasi.

1.3 Melihat Data Awal

Dataset pelanggan ditampilkan untuk melihat kondisi awal data.

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

Dataset transaksi juga ditampilkan.

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

2. Memahami Struktur Data

Sebelum melakukan perubahan, kondisi awal data perlu dilihat terlebih dahulu. Hal ini dilakukan untuk mengetahui ukuran dataset, nama variabel, tipe data, dan gambaran umum dari nilai yang terdapat di dalam data.

2.1 Ukuran dan Nama Variabel

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

Fungsi dim() digunakan untuk mengetahui jumlah baris dan kolom. Sementara itu, names() digunakan untuk melihat nama variabel yang terdapat pada dataset.

2.2 Struktur Data

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

Fungsi str() digunakan untuk melihat tipe data setiap variabel. Dari hasil tersebut dapat diketahui variabel mana yang berupa numerik dan mana yang berupa karakter.

2.3 Ringkasan Data

summary(pelanggan_raw)
##  customer_id            nama                usia          pendapatan       
##  Length:12          Length:12          Min.   : 21.00   Min.   :  4500000  
##  Class :character   Class :character   1st Qu.: 24.00   1st Qu.:  4725000  
##  Mode  :character   Mode  :character   Median : 28.00   Median :  5000000  
##                                        Mean   : 38.73   Mean   : 54440000  
##                                        3rd Qu.: 33.00   3rd Qu.:  5275000  
##                                        Max.   :150.00   Max.   :500000000  
##                                        NA's   :1        NA's   :2          
##      kota              status         
##  Length:12          Length:12         
##  Class :character   Class :character  
##  Mode  :character   Mode  :character  
##                                       
##                                       
##                                       
## 

Fungsi summary() digunakan untuk melihat ringkasan data. Pada variabel numerik dapat dilihat nilai minimum, kuartil, median, mean, dan maksimum. Ringkasan ini membantu melihat apakah terdapat nilai yang terlihat tidak wajar.

3. Pemeriksaan Kualitas Data Awal

Setelah struktur data diketahui, langkah berikutnya adalah memeriksa masalah yang terdapat pada dataset. Pemeriksaan dilakukan terhadap missing value, duplikasi, kategori, serta rentang nilai numerik.

3.1 Pemeriksaan Missing Value

Jumlah missing value pada setiap variabel diperiksa menggunakan is.na().

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

Persentase missing value juga dihitung agar dapat diketahui seberapa besar proporsi data yang kosong.

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

Dari pemeriksaan tersebut dapat diketahui bahwa terdapat missing value pada variabel usia, pendapatan, dan kota.

3.2 Pemeriksaan Duplikasi

Pemeriksaan pertama dilakukan terhadap duplikasi baris secara keseluruhan.

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

Selanjutnya diperiksa apakah terdapat customer_id yang berulang.

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

Pemeriksaan berdasarkan customer_id diperlukan karena variabel tersebut digunakan sebagai identitas pelanggan. Satu pelanggan seharusnya tidak memiliki lebih dari satu data pada dataset utama.

3.3 Pemeriksaan Kategori

Kategori pada variabel kota diperiksa menggunakan unique().

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

Kategori pada variabel status juga diperiksa.

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

Dari hasil tersebut terlihat bahwa terdapat beberapa penulisan yang berbeda. Misalnya Pekanbaru, PEKANBARU, dan PKU sebenarnya digunakan untuk menunjukkan kota yang sama. Hal yang sama juga terjadi pada variabel status.

3.4 Pemeriksaan Rentang Data Numerik

Rentang usia diperiksa terlebih dahulu.

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

Rentang pendapatan juga diperiksa.

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

Pemeriksaan ini dilakukan untuk mengetahui nilai minimum dan maksimum. Dari sini dapat terlihat bahwa terdapat nilai yang cukup jauh dari nilai lainnya dan perlu diperiksa lebih lanjut.

4. Membuat Fungsi Audit Data

Agar pemeriksaan kualitas data dapat dilakukan dengan lebih praktis, dibuat fungsi audit_data(). Fungsi ini memberikan informasi mengenai tipe data, jumlah missing value, persentase missing value, dan 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
  )
}

Fungsi tersebut diterapkan pada dataset awal.

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

Audit ini digunakan sebagai gambaran kondisi data sebelum dilakukan perbaikan. Hasilnya nantinya dapat dibandingkan dengan audit setelah seluruh proses preprocessing selesai.

5. Data Cleaning

Setelah masalah pada data diketahui, tahap berikutnya adalah melakukan cleaning. Pada tahap ini dilakukan perbaikan terhadap penulisan kategori, duplikasi, dan nilai yang tidak wajar.

Data asli tetap dipertahankan dengan membuat salinan baru.

pelanggan <- pelanggan_raw

5.1 Membersihkan Spasi

Beberapa nilai kota memiliki spasi tambahan. Spasi tersebut dapat membuat kategori yang sebenarnya sama dianggap berbeda.

pelanggan$kota <- trimws(
  pelanggan$kota
)

Kategori kota diperiksa kembali.

sort(
  unique(
    pelanggan$kota
  )
)
## [1] "Dumai"     "DUMAI"     "pekanbaru" "Pekanbaru" "PEKANBARU" "PKU"      
## [7] "Siak"

5.2 Menyamakan Huruf pada Kota

Perbedaan huruf besar dan kecil juga diperbaiki agar penulisan kota menjadi lebih seragam.

pelanggan$kota <- tolower(
  pelanggan$kota
)

Kategori kota diperiksa kembali.

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

5.3 Standardisasi Nama Kota

Beberapa nama kota memiliki bentuk yang berbeda tetapi memiliki arti yang sama. PKU dan Pekanbaru diseragamkan menjadi pekanbaru.

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

Kategori kota setelah standardisasi diperiksa kembali.

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

Setelah langkah ini, kategori kota menjadi lebih konsisten. Kota Dumai tetap ditulis sebagai dumai, sedangkan Pekanbaru ditulis sebagai pekanbaru.

5.4 Standardisasi Status

Variabel status juga memiliki beberapa bentuk penulisan. Pertama, seluruh nilai diubah menjadi huruf kecil dan spasi tambahan dihapus.

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

Selanjutnya kategori status diseragamkan.

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

Kategori status diperiksa kembali.

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

Dengan demikian, status pelanggan hanya menggunakan dua bentuk kategori, yaitu aktif dan tidak aktif.

6. Penanganan Duplikasi

Setelah data kategorik diperbaiki, pemeriksaan duplikasi dilakukan kembali. Duplikasi diperiksa berdasarkan customer_id karena variabel tersebut menjadi identifier utama pelanggan.

6.1 Menampilkan Data Duplikat

pelanggan[
  duplicated(
    pelanggan$customer_id
  ),
]
##    customer_id nama usia pendapatan  kota      status
## 11        C010 Joko   35    5300000 dumai tidak aktif

Dari hasil pemeriksaan terlihat bahwa C010 muncul lebih dari satu kali.

6.2 Menghapus Data Duplikat

Duplikasi dihapus dengan mempertahankan data yang muncul pertama kali.

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

Jumlah baris setelah penghapusan diperiksa.

nrow(pelanggan)
## [1] 11

Kemudian diperiksa kembali apakah masih terdapat customer_id yang berulang.

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

Jika hasilnya 0, berarti tidak terdapat lagi duplikasi berdasarkan customer_id.

7. Pemeriksaan dan Perbaikan Nilai Tidak Wajar

Selain data kosong dan duplikasi, terdapat nilai yang tidak sesuai dengan kondisi umum. Contohnya adalah usia 150 tahun. Nilai tersebut perlu diperiksa sebelum digunakan dalam analisis.

7.1 Menemukan Nilai Usia Tidak Wajar

pelanggan[
  pelanggan$usia > 100,
]
##    customer_id nama usia pendapatan  kota status
## 4         C004 Dodi  150    4800000 dumai  aktif
## NA        <NA> <NA>   NA         NA  <NA>   <NA>

Usia 150 tahun dianggap tidak wajar untuk data pelanggan. Nilai tersebut tidak langsung diganti dengan angka tertentu karena tidak diketahui nilai usia sebenarnya.

7.2 Mengubah Nilai Tidak Wajar Menjadi NA

Nilai usia yang tidak wajar diubah menjadi NA.

pelanggan$usia[
  pelanggan$usia > 100
] <- NA

Kemudian kondisi usia diperiksa kembali.

pelanggan$usia
##  [1] 21 25 23 NA 27 NA 31 29 22 35 28

Setelah menjadi NA, nilai tersebut dapat ditangani bersama dengan missing value lainnya pada tahap imputasi.

8. Log Perubahan Data

Agar perubahan yang dilakukan dapat diketahui, dibuat log sederhana. Log ini berisi tahapan dan keterangan perubahan yang dilakukan pada dataset.

log_perubahan <- data.frame(
  
  tahap = c(
    "Standardisasi kota",
    "Standardisasi status",
    "Penghapusan duplikasi",
    "Koreksi usia"
  ),
  
  keterangan = c(
    "Menyamakan penulisan kategori kota",
    "Menyamakan penulisan kategori status",
    "Menghapus customer_id yang duplikat",
    "Mengubah usia tidak wajar menjadi NA"
  ),
  
  stringsAsFactors = FALSE
)

log_perubahan
##                   tahap                           keterangan
## 1    Standardisasi kota   Menyamakan penulisan kategori kota
## 2  Standardisasi status Menyamakan penulisan kategori status
## 3 Penghapusan duplikasi  Menghapus customer_id yang duplikat
## 4          Koreksi usia Mengubah usia tidak wajar menjadi NA

Log tersebut membantu melihat kembali perubahan yang sudah dilakukan selama proses cleaning.

9. Penanganan Missing Value

Setelah cleaning dilakukan, masih terdapat beberapa nilai yang kosong. Missing value perlu ditangani karena dapat mengganggu proses analisis apabila dibiarkan begitu saja.

Metode pengisian disesuaikan dengan jenis variabel. Untuk data numerik digunakan median, sedangkan untuk data kategorik digunakan modus.

9.1 Missing Value pada Usia

Missing value pada usia diperiksa terlebih dahulu.

pelanggan[
  is.na(
    pelanggan$usia
  ),
]
##   customer_id nama usia pendapatan  kota      status
## 4        C004 Dodi   NA    4800000 dumai       aktif
## 6        C006 Fani   NA    5100000 dumai tidak aktif

Karena usia merupakan variabel numerik, median digunakan sebagai nilai pengganti. Median dipilih karena tidak terlalu dipengaruhi oleh nilai ekstrem.

median_usia <- median(
  pelanggan$usia,
  na.rm = TRUE
)
median_usia
## [1] 27

Variabel baru dibuat untuk menyimpan hasil imputasi.

pelanggan$usia_imputasi <- pelanggan$usia

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

Hasil sebelum dan sesudah imputasi dapat dibandingkan.

pelanggan[
  ,
  c(
    "customer_id",
    "usia",
    "usia_imputasi"
  )
]
##    customer_id usia usia_imputasi
## 1         C001   21            21
## 2         C002   25            25
## 3         C003   23            23
## 4         C004   NA            27
## 5         C005   27            27
## 6         C006   NA            27
## 7         C007   31            31
## 8         C008   29            29
## 9         C009   22            22
## 10        C010   35            35
## 12        C011   28            28

9.2 Missing Value pada Pendapatan

Missing value pada pendapatan diperiksa.

pelanggan[
  is.na(
    pelanggan$pendapatan
  ),
]
##    customer_id nama usia pendapatan      kota status usia_imputasi
## 2         C002 Budi   25         NA pekanbaru  aktif            25
## 12        C011 Kiki   28         NA      <NA>  aktif            28

Karena pendapatan merupakan data numerik, median digunakan sebagai nilai pengganti.

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

median_pendapatan
## [1] 4900000

Hasil imputasi disimpan dalam variabel baru.

pelanggan$pendapatan_imputasi <-
  pelanggan$pendapatan

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

Hasilnya diperiksa.

pelanggan[
  ,
  c(
    "customer_id",
    "pendapatan",
    "pendapatan_imputasi"
  )
]
##    customer_id pendapatan pendapatan_imputasi
## 1         C001    4.5e+06             4.5e+06
## 2         C002         NA             4.9e+06
## 3         C003    5.2e+06             5.2e+06
## 4         C004    4.8e+06             4.8e+06
## 5         C005    4.9e+06             4.9e+06
## 6         C006    5.1e+06             5.1e+06
## 7         C007    5.0e+08             5.0e+08
## 8         C008    4.7e+06             4.7e+06
## 9         C009    4.6e+06             4.6e+06
## 10        C010    5.3e+06             5.3e+06
## 12        C011         NA             4.9e+06

9.3 Missing Value pada Kota

Missing value pada kota diperiksa.

pelanggan[
  is.na(
    pelanggan$kota
  ),
]
##    customer_id nama usia pendapatan kota status usia_imputasi
## 12        C011 Kiki   28         NA <NA>  aktif            28
##    pendapatan_imputasi
## 12             4900000

Karena kota merupakan data kategorik, nilai yang kosong diisi menggunakan modus atau kategori yang paling sering muncul.

modus_kota <- names(
  sort(
    table(
      pelanggan$kota
    ),
    decreasing = TRUE
  )
)[1]

modus_kota
## [1] "pekanbaru"

Hasil imputasi disimpan dalam variabel baru.

pelanggan$kota_imputasi <-
  pelanggan$kota

pelanggan$kota_imputasi[
  is.na(
    pelanggan$kota_imputasi
  )
] <- modus_kota

Hasilnya diperiksa kembali.

pelanggan[
  ,
  c(
    "customer_id",
    "kota",
    "kota_imputasi"
  )
]
##    customer_id      kota kota_imputasi
## 1         C001 pekanbaru     pekanbaru
## 2         C002 pekanbaru     pekanbaru
## 3         C003 pekanbaru     pekanbaru
## 4         C004     dumai         dumai
## 5         C005 pekanbaru     pekanbaru
## 6         C006     dumai         dumai
## 7         C007 pekanbaru     pekanbaru
## 8         C008      siak          siak
## 9         C009 pekanbaru     pekanbaru
## 10        C010     dumai         dumai
## 12        C011      <NA>     pekanbaru

9.4 Penanda Missing Value

Selain melakukan imputasi, dibuat variabel yang menunjukkan apakah pendapatan pada awalnya merupakan missing value.

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

Jumlah data yang sebelumnya memiliki missing value dapat dilihat dengan:

table(
  pelanggan$pendapatan_missing
)
## 
## FALSE  TRUE 
##     9     2

Penanda ini berguna agar informasi mengenai kondisi awal data tetap tersimpan.

9.5 Pemeriksaan Setelah Imputasi

Setelah seluruh proses imputasi selesai, jumlah missing value diperiksa kembali.

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

Pemeriksaan ini dilakukan untuk memastikan variabel yang menjadi target imputasi sudah tidak memiliki nilai kosong.

10. Pemeriksaan Outlier

Setelah missing value ditangani, tahap berikutnya adalah pemeriksaan outlier. Outlier merupakan nilai yang jauh dari sebagian besar pengamatan.

Pada tugas ini pemeriksaan dilakukan pada variabel usia dan pendapatan. Pemeriksaan menggunakan boxplot dan metode IQR.

10.1 Boxplot Usia

boxplot(
  pelanggan$usia_imputasi,
  horizontal = TRUE,
  col = "skyblue",
  main = "Boxplot Usia",
  xlab = "Usia"
)

Boxplot digunakan untuk melihat penyebaran data dan mengetahui apakah terdapat nilai yang berada jauh dari data lainnya.

10.2 Menghitung IQR Usia

Kuartil pertama, kuartil ketiga, dan IQR dihitung terlebih dahulu.

Q1_usia <- quantile(
  pelanggan$usia_imputasi,
  0.25,
  na.rm = TRUE
)

Q3_usia <- quantile(
  pelanggan$usia_imputasi,
  0.75,
  na.rm = TRUE
)

IQR_usia <- Q3_usia - Q1_usia

Q1_usia
## 25% 
##  24
Q3_usia
##  75% 
## 28.5
IQR_usia
## 75% 
## 4.5

Batas bawah dan batas atas ditentukan dengan rumus:

\[ \text{Batas Bawah} = Q_1 - 1.5 \times IQR \]

\[ \text{Batas Atas} = Q_3 + 1.5 \times IQR \]

batas_bawah_usia <-
  Q1_usia - 1.5 * IQR_usia

batas_atas_usia <-
  Q3_usia + 1.5 * IQR_usia

batas_bawah_usia
##   25% 
## 17.25
batas_atas_usia
##   75% 
## 35.25

10.3 Mengidentifikasi Outlier Usia

pelanggan$outlier_usia <-
  pelanggan$usia_imputasi < batas_bawah_usia |
  pelanggan$usia_imputasi > batas_atas_usia

Observasi yang terdeteksi sebagai outlier ditampilkan.

pelanggan[
  pelanggan$outlier_usia,
  c(
    "customer_id",
    "nama",
    "usia_imputasi"
  )
]
## [1] customer_id   nama          usia_imputasi
## <0 rows> (or 0-length row.names)

Hasil tersebut digunakan untuk melihat apakah nilai yang terdeteksi memang perlu mendapatkan perhatian lebih lanjut.

10.4 Boxplot Pendapatan

Pendapatan juga diperiksa karena memiliki nilai yang cukup jauh dibandingkan sebagian besar data.

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

Boxplot membantu melihat apakah terdapat nilai pendapatan yang berada jauh dari pola umum data.

10.5 Menghitung IQR Pendapatan

Q1_pendapatan <- quantile(
  pelanggan$pendapatan_imputasi,
  0.25,
  na.rm = TRUE
)

Q3_pendapatan <- quantile(
  pelanggan$pendapatan_imputasi,
  0.75,
  na.rm = TRUE
)

IQR_pendapatan <-
  Q3_pendapatan - Q1_pendapatan

Q1_pendapatan
##     25% 
## 4750000
Q3_pendapatan
##     75% 
## 5150000
IQR_pendapatan
##   75% 
## 4e+05

Batas bawah dan batas atas dihitung.

batas_bawah_pendapatan <-
  Q1_pendapatan -
  1.5 * IQR_pendapatan

batas_atas_pendapatan <-
  Q3_pendapatan +
  1.5 * IQR_pendapatan

batas_bawah_pendapatan
##     25% 
## 4150000
batas_atas_pendapatan
##     75% 
## 5750000

10.6 Mengidentifikasi Outlier Pendapatan

pelanggan$outlier_pendapatan <-
  pelanggan$pendapatan_imputasi <
  batas_bawah_pendapatan |
  pelanggan$pendapatan_imputasi >
  batas_atas_pendapatan

Data yang terdeteksi sebagai outlier ditampilkan.

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

Nilai yang terdeteksi sebagai outlier tidak langsung dihapus. Nilai tersebut diperiksa terlebih dahulu karena outlier belum tentu merupakan kesalahan.

10.7 Melihat Nilai Pendapatan Terbesar

pelanggan[
  order(
    pelanggan$pendapatan_imputasi,
    decreasing = TRUE
  ),
  c(
    "customer_id",
    "nama",
    "pendapatan_imputasi"
  )
]
##    customer_id   nama pendapatan_imputasi
## 7         C007 Gilang             5.0e+08
## 10        C010   Joko             5.3e+06
## 3         C003  Citra             5.2e+06
## 6         C006   Fani             5.1e+06
## 2         C002   Budi             4.9e+06
## 5         C005    Eka             4.9e+06
## 12        C011   Kiki             4.9e+06
## 4         C004   Dodi             4.8e+06
## 8         C008   Hana             4.7e+06
## 9         C009  Indra             4.6e+06
## 1         C001    Ani             4.5e+06

Pemeriksaan ini membantu melihat nilai ekstrem secara lebih jelas dan membandingkannya dengan pendapatan pelanggan lainnya.

11. Penanganan Outlier

Outlier pada pendapatan tidak langsung dihapus karena masih mungkin merupakan nilai yang benar. Sebagai alternatif, digunakan winsorizing untuk membatasi nilai ekstrem tanpa menghapus observasi.

11.1 Winsorizing Pendapatan

pelanggan$pendapatan_winsor <-
  pmin(
    pmax(
      pelanggan$pendapatan_imputasi,
      batas_bawah_pendapatan
    ),
    batas_atas_pendapatan
  )

Nilai sebelum dan sesudah winsorizing dibandingkan.

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

Dengan cara ini, nilai ekstrem dibatasi pada batas yang sudah ditentukan tanpa menghapus baris pelanggan.

11.2 Membandingkan Boxplot

Perubahan sebelum dan sesudah winsorizing dapat dilihat menggunakan boxplot.

par(
  mfrow = c(1, 2)
)

boxplot(
  pelanggan$pendapatan_imputasi,
  horizontal = TRUE,
  col = "skyblue",
  main = "Sebelum Winsorizing",
  xlab = "Pendapatan"
)

boxplot(
  pelanggan$pendapatan_winsor,
  horizontal = TRUE,
  col = "lightblue",
  main = "Sesudah Winsorizing",
  xlab = "Pendapatan"
)

par(
  mfrow = c(1, 1)
)

Dari perbandingan tersebut dapat dilihat perubahan penyebaran data setelah nilai ekstrem dibatasi. Nilai pendapatan sebelum winsorizing tetap disimpan sehingga hasil sebelum dan sesudah perubahan masih dapat dibandingkan.

12. Transformasi Data

Setelah proses cleaning, imputasi, dan pemeriksaan outlier dilakukan, selanjutnya data numerik dapat ditransformasikan.

Transformasi digunakan untuk mengubah skala data. Hal ini berguna karena variabel usia dan pendapatan memiliki rentang nilai yang berbeda cukup jauh. Pada tugas ini digunakan tiga metode, yaitu Min-Max, Z-Score, dan Decimal Scaling.

12.1 Normalisasi Min-Max

Rumus Min-Max

Normalisasi Min-Max digunakan untuk mengubah nilai data ke dalam rentang 0 sampai 1.

Rumus Min-Max:

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

Keterangan:

  • \(x\) = nilai asli
  • \(x_{\min}\) = nilai minimum
  • \(x_{\max}\) = nilai maksimum
  • \(x'\) = nilai setelah normalisasi

Fungsi Min-Max dibuat sebagai berikut.

minmax <- function(x) {
  
  (
    x - min(
      x,
      na.rm = TRUE
    )
  ) /
    (
      max(
        x,
        na.rm = TRUE
      ) -
        min(
          x,
          na.rm = TRUE
        )
    )
}

Fungsi diterapkan pada usia dan pendapatan.

pelanggan$usia_minmax <-
  minmax(
    pelanggan$usia_imputasi
  )

pelanggan$pendapatan_minmax <-
  minmax(
    pelanggan$pendapatan_imputasi
  )

Hasilnya ditampilkan.

pelanggan[
  ,
  c(
    "customer_id",
    "usia_imputasi",
    "usia_minmax",
    "pendapatan_imputasi",
    "pendapatan_minmax"
  )
]
##    customer_id usia_imputasi usia_minmax pendapatan_imputasi pendapatan_minmax
## 1         C001            21  0.00000000             4.5e+06      0.0000000000
## 2         C002            25  0.28571429             4.9e+06      0.0008072654
## 3         C003            23  0.14285714             5.2e+06      0.0014127144
## 4         C004            27  0.42857143             4.8e+06      0.0006054490
## 5         C005            27  0.42857143             4.9e+06      0.0008072654
## 6         C006            27  0.42857143             5.1e+06      0.0012108981
## 7         C007            31  0.71428571             5.0e+08      1.0000000000
## 8         C008            29  0.57142857             4.7e+06      0.0004036327
## 9         C009            22  0.07142857             4.6e+06      0.0002018163
## 10        C010            35  1.00000000             5.3e+06      0.0016145308
## 12        C011            28  0.50000000             4.9e+06      0.0008072654

Nilai hasil Min-Max berada pada rentang 0 sampai 1.

12.2 Normalisasi Z-Score

Rumus Z-Score

Normalisasi Z-Score digunakan untuk mengubah data berdasarkan rata-rata dan simpangan baku.

Rumus Z-Score:

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

Keterangan:

  • \(x\) = nilai asli
  • \(\bar{x}\) = rata-rata data
  • \(s\) = simpangan baku
  • \(z\) = nilai setelah transformasi

Transformasi dilakukan menggunakan fungsi scale().

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

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

Hasil transformasi ditampilkan.

pelanggan[
  ,
  c(
    "customer_id",
    "usia_z",
    "pendapatan_z"
  )
]
##    customer_id      usia_z pendapatan_z
## 1         C001 -1.42958323   -0.3041235
## 2         C002 -0.44674476   -0.3014440
## 3         C003 -0.93816399   -0.2994343
## 4         C004  0.04467448   -0.3021138
## 5         C005  0.04467448   -0.3014440
## 6         C006  0.04467448   -0.3001042
## 7         C007  1.02751295    3.0151095
## 8         C008  0.53609371   -0.3027837
## 9         C009 -1.18387361   -0.3034536
## 10        C010  2.01035142   -0.2987645
## 12        C011  0.29038409   -0.3014440

Nilai Z-Score yang mendekati nol menunjukkan nilai yang dekat dengan rata-rata. Nilai positif menunjukkan nilai di atas rata-rata, sedangkan nilai negatif menunjukkan nilai di bawah rata-rata.

12.3 Decimal Scaling

Decimal Scaling dilakukan dengan membagi data menggunakan pangkat sepuluh tertentu. Metode ini digunakan untuk memperkecil skala angka.

decimal_scale <- function(x) {
  
  maks <- max(
    abs(x),
    na.rm = TRUE
  )
  
  if (maks == 0) {
    return(x)
  }
  
  j <- ceiling(
    log10(
      maks + 1
    )
  )
  
  x / (
    10 ^ j
  )
}

Fungsi tersebut diterapkan pada pendapatan.

pelanggan$pendapatan_decimal <-
  decimal_scale(
    pelanggan$pendapatan_imputasi
  )

Rentang hasil transformasi diperiksa.

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

12.4 Membandingkan Hasil Transformasi

Hasil ketiga metode dibandingkan agar perbedaannya dapat dilihat.

pelanggan[
  ,
  c(
    "customer_id",
    "pendapatan_imputasi",
    "pendapatan_minmax",
    "pendapatan_z",
    "pendapatan_decimal"
  )
]
##    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
## 12        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
## 12             0.0049

Min-Max menghasilkan nilai antara 0 dan 1, Z-Score menghasilkan nilai yang berpusat pada rata-rata, sedangkan Decimal Scaling mengecilkan nilai dengan membaginya menggunakan pangkat sepuluh.

13. Integrasi Data

Setelah dataset pelanggan selesai diproses, data tersebut digabungkan dengan dataset transaksi.

Tujuan integrasi adalah menggabungkan informasi pelanggan dengan informasi transaksi sehingga kedua informasi dapat digunakan dalam satu dataset.

13.1 Memeriksa Identifier

Identifier pada dataset pelanggan diperiksa.

sort(
  unique(
    pelanggan$customer_id
  )
)
##  [1] "C001" "C002" "C003" "C004" "C005" "C006" "C007" "C008" "C009" "C010"
## [11] "C011"

Identifier pada dataset transaksi juga diperiksa.

sort(
  unique(
    transaksi_raw$cust_id
  )
)
##  [1] "C001" "C002" "C003" "C004" "C005" "C006" "C007" "C008" "C009" "C010"
## [11] "C012"

Dari hasil tersebut terlihat bahwa terdapat beberapa ID yang hanya muncul pada salah satu dataset.

13.2 Mencari ID yang Tidak Memiliki Pasangan

ID yang terdapat pada pelanggan tetapi tidak terdapat pada transaksi dicari menggunakan setdiff().

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

Sebaliknya, ID yang terdapat pada transaksi tetapi tidak terdapat pada pelanggan juga diperiksa.

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

Pemeriksaan ini dilakukan sebelum merge agar perbedaan data dapat diketahui.

13.3 Menyamakan Nama Identifier

Nama cust_id pada dataset transaksi diubah menjadi customer_id.

transaksi <- transaksi_raw

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

Nama variabel diperiksa kembali.

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

Sekarang kedua dataset memiliki identifier dengan nama yang sama.

13.4 Menggabungkan Dataset

Penggabungan dilakukan menggunakan merge() dengan all.x = TRUE. Pengaturan ini digunakan agar seluruh pelanggan pada dataset utama tetap dipertahankan.

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

Hasil integrasi dilihat.

head(
  data_terintegrasi
)
##   customer_id  nama usia pendapatan      kota      status usia_imputasi
## 1        C001   Ani   21    4500000 pekanbaru       aktif            21
## 2        C002  Budi   25         NA pekanbaru       aktif            25
## 3        C003 Citra   23    5200000 pekanbaru       aktif            23
## 4        C004  Dodi   NA    4800000     dumai       aktif            27
## 5        C005   Eka   27    4900000 pekanbaru tidak aktif            27
## 6        C006  Fani   NA    5100000     dumai tidak aktif            27
##   pendapatan_imputasi kota_imputasi pendapatan_missing outlier_usia
## 1             4500000     pekanbaru              FALSE        FALSE
## 2             4900000     pekanbaru               TRUE        FALSE
## 3             5200000     pekanbaru              FALSE        FALSE
## 4             4800000         dumai              FALSE        FALSE
## 5             4900000     pekanbaru              FALSE        FALSE
## 6             5100000         dumai              FALSE        FALSE
##   outlier_pendapatan pendapatan_winsor usia_minmax pendapatan_minmax
## 1              FALSE           4500000   0.0000000      0.0000000000
## 2              FALSE           4900000   0.2857143      0.0008072654
## 3              FALSE           5200000   0.1428571      0.0014127144
## 4              FALSE           4800000   0.4285714      0.0006054490
## 5              FALSE           4900000   0.4285714      0.0008072654
## 6              FALSE           5100000   0.4285714      0.0012108981
##        usia_z pendapatan_z pendapatan_decimal jumlah_transaksi total_purchase
## 1 -1.42958323   -0.3041235             0.0045                5        1500000
## 2 -0.44674476   -0.3014440             0.0049                3         900000
## 3 -0.93816399   -0.2994343             0.0052                7        2700000
## 4  0.04467448   -0.3021138             0.0048                2         600000
## 5  0.04467448   -0.3014440             0.0049                6        2100000
## 6  0.04467448   -0.3001042             0.0051                4        1300000

Struktur data juga diperiksa.

str(
  data_terintegrasi
)
## 'data.frame':    11 obs. of  20 variables:
##  $ customer_id        : chr  "C001" "C002" "C003" "C004" ...
##  $ nama               : chr  "Ani" "Budi" "Citra" "Dodi" ...
##  $ usia               : num  21 25 23 NA 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" "pekanbaru" "pekanbaru" "dumai" ...
##  $ status             : chr  "aktif" "aktif" "aktif" "aktif" ...
##  $ usia_imputasi      : num  21 25 23 27 27 27 31 29 22 35 ...
##  $ pendapatan_imputasi: num  4.5e+06 4.9e+06 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_imputasi      : chr  "pekanbaru" "pekanbaru" "pekanbaru" "dumai" ...
##  $ pendapatan_missing : logi  FALSE TRUE FALSE FALSE FALSE FALSE ...
##  $ outlier_usia       : logi  FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ outlier_pendapatan : logi  FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ pendapatan_winsor  : num  4500000 4900000 5200000 4800000 4900000 5100000 5750000 4700000 4600000 5300000 ...
##  $ usia_minmax        : num  0 0.286 0.143 0.429 0.429 ...
##  $ pendapatan_minmax  : num  0 0.000807 0.001413 0.000605 0.000807 ...
##  $ usia_z             : num  -1.4296 -0.4467 -0.9382 0.0447 0.0447 ...
##  $ pendapatan_z       : num  -0.304 -0.301 -0.299 -0.302 -0.301 ...
##  $ pendapatan_decimal : num  0.0045 0.0049 0.0052 0.0048 0.0049 0.0051 0.5 0.0047 0.0046 0.0053 ...
##  $ 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 ...

13.5 Pemeriksaan Hasil Integrasi

Jumlah baris sebelum dan sesudah integrasi dibandingkan.

nrow(pelanggan)
## [1] 11
nrow(data_terintegrasi)
## [1] 11

Kemudian diperiksa apakah terdapat duplikasi customer_id.

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

Missing value pada data transaksi juga diperiksa.

colSums(
  is.na(
    data_terintegrasi
  )
)
##         customer_id                nama                usia          pendapatan 
##                   0                   0                   2                   2 
##                kota              status       usia_imputasi pendapatan_imputasi 
##                   1                   0                   0                   0 
##       kota_imputasi  pendapatan_missing        outlier_usia  outlier_pendapatan 
##                   0                   0                   0                   0 
##   pendapatan_winsor         usia_minmax   pendapatan_minmax              usia_z 
##                   0                   0                   0                   0 
##        pendapatan_z  pendapatan_decimal    jumlah_transaksi      total_purchase 
##                   0                   0                   1                   1

Pelanggan yang tidak memiliki data transaksi ditampilkan.

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

Nilai NA pada bagian transaksi menunjukkan bahwa pelanggan tersebut tidak memiliki pasangan data pada dataset transaksi.

13.6 Menangani Missing Value pada Transaksi

Jika NA pada transaksi menunjukkan bahwa pelanggan tidak memiliki transaksi, maka nilai tersebut dapat diubah menjadi nol.

Hasil penanganan disimpan pada variabel baru agar data transaksi asli tetap tersedia.

data_terintegrasi$jumlah_transaksi_final <-
  data_terintegrasi$jumlah_transaksi

data_terintegrasi$total_purchase_final <-
  data_terintegrasi$total_purchase

Missing value pada jumlah transaksi diganti dengan nol.

data_terintegrasi$jumlah_transaksi_final[
  is.na(
    data_terintegrasi$jumlah_transaksi_final
  )
] <- 0

Missing value pada total pembelian juga diganti dengan nol.

data_terintegrasi$total_purchase_final[
  is.na(
    data_terintegrasi$total_purchase_final
  )
] <- 0

Hasilnya diperiksa.

data_terintegrasi[
  ,
  c(
    "customer_id",
    "nama",
    "jumlah_transaksi",
    "total_purchase",
    "jumlah_transaksi_final",
    "total_purchase_final"
  )
]
##    customer_id   nama jumlah_transaksi total_purchase jumlah_transaksi_final
## 1         C001    Ani                5        1.5e+06                      5
## 2         C002   Budi                3        9.0e+05                      3
## 3         C003  Citra                7        2.7e+06                      7
## 4         C004   Dodi                2        6.0e+05                      2
## 5         C005    Eka                6        2.1e+06                      6
## 6         C006   Fani                4        1.3e+06                      4
## 7         C007 Gilang               20        2.5e+07                     20
## 8         C008   Hana                5        1.7e+06                      5
## 9         C009  Indra                3        8.0e+05                      3
## 10        C010   Joko                8        3.2e+06                      8
## 11        C011   Kiki               NA             NA                      0
##    total_purchase_final
## 1               1.5e+06
## 2               9.0e+05
## 3               2.7e+06
## 4               6.0e+05
## 5               2.1e+06
## 6               1.3e+06
## 7               2.5e+07
## 8               1.7e+06
## 9               8.0e+05
## 10              3.2e+06
## 11              0.0e+00

14. Membentuk Dataset Akhir

Setelah preprocessing dan integrasi selesai, variabel yang akan digunakan dipilih untuk membentuk dataset akhir.

data_final <- data_terintegrasi[
  ,
  c(
    "customer_id",
    "nama",
    "usia_imputasi",
    "kota_imputasi",
    "status",
    "pendapatan_imputasi",
    "pendapatan_missing",
    "outlier_usia",
    "outlier_pendapatan",
    "usia_minmax",
    "pendapatan_minmax",
    "usia_z",
    "pendapatan_z",
    "pendapatan_decimal",
    "jumlah_transaksi_final",
    "total_purchase_final"
  )
]

Beberapa nama variabel dibuat lebih sederhana agar lebih mudah dibaca.

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

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

names(data_final)[
  names(data_final) == "pendapatan_imputasi"
] <- "pendapatan"

Dataset akhir ditampilkan.

data_final
##    customer_id   nama usia      kota      status pendapatan pendapatan_missing
## 1         C001    Ani   21 pekanbaru       aktif    4.5e+06              FALSE
## 2         C002   Budi   25 pekanbaru       aktif    4.9e+06               TRUE
## 3         C003  Citra   23 pekanbaru       aktif    5.2e+06              FALSE
## 4         C004   Dodi   27     dumai       aktif    4.8e+06              FALSE
## 5         C005    Eka   27 pekanbaru tidak aktif    4.9e+06              FALSE
## 6         C006   Fani   27     dumai tidak aktif    5.1e+06              FALSE
## 7         C007 Gilang   31 pekanbaru       aktif    5.0e+08              FALSE
## 8         C008   Hana   29      siak       aktif    4.7e+06              FALSE
## 9         C009  Indra   22 pekanbaru       aktif    4.6e+06              FALSE
## 10        C010   Joko   35     dumai tidak aktif    5.3e+06              FALSE
## 11        C011   Kiki   28 pekanbaru       aktif    4.9e+06               TRUE
##    outlier_usia outlier_pendapatan usia_minmax pendapatan_minmax      usia_z
## 1         FALSE              FALSE  0.00000000      0.0000000000 -1.42958323
## 2         FALSE              FALSE  0.28571429      0.0008072654 -0.44674476
## 3         FALSE              FALSE  0.14285714      0.0014127144 -0.93816399
## 4         FALSE              FALSE  0.42857143      0.0006054490  0.04467448
## 5         FALSE              FALSE  0.42857143      0.0008072654  0.04467448
## 6         FALSE              FALSE  0.42857143      0.0012108981  0.04467448
## 7         FALSE               TRUE  0.71428571      1.0000000000  1.02751295
## 8         FALSE              FALSE  0.57142857      0.0004036327  0.53609371
## 9         FALSE              FALSE  0.07142857      0.0002018163 -1.18387361
## 10        FALSE              FALSE  1.00000000      0.0016145308  2.01035142
## 11        FALSE              FALSE  0.50000000      0.0008072654  0.29038409
##    pendapatan_z pendapatan_decimal jumlah_transaksi_final total_purchase_final
## 1    -0.3041235             0.0045                      5              1.5e+06
## 2    -0.3014440             0.0049                      3              9.0e+05
## 3    -0.2994343             0.0052                      7              2.7e+06
## 4    -0.3021138             0.0048                      2              6.0e+05
## 5    -0.3014440             0.0049                      6              2.1e+06
## 6    -0.3001042             0.0051                      4              1.3e+06
## 7     3.0151095             0.5000                     20              2.5e+07
## 8    -0.3027837             0.0047                      5              1.7e+06
## 9    -0.3034536             0.0046                      3              8.0e+05
## 10   -0.2987645             0.0053                      8              3.2e+06
## 11   -0.3014440             0.0049                      0              0.0e+00

15. Pemeriksaan Dataset Akhir

Setelah dataset akhir terbentuk, dilakukan pemeriksaan terakhir untuk melihat apakah seluruh proses preprocessing sudah berjalan dengan baik.

15.1 Struktur Dataset

str(
  data_final
)
## 'data.frame':    11 obs. of  16 variables:
##  $ customer_id           : chr  "C001" "C002" "C003" "C004" ...
##  $ nama                  : chr  "Ani" "Budi" "Citra" "Dodi" ...
##  $ usia                  : num  21 25 23 27 27 27 31 29 22 35 ...
##  $ kota                  : chr  "pekanbaru" "pekanbaru" "pekanbaru" "dumai" ...
##  $ status                : chr  "aktif" "aktif" "aktif" "aktif" ...
##  $ pendapatan            : num  4.5e+06 4.9e+06 5.2e+06 4.8e+06 4.9e+06 5.1e+06 5.0e+08 4.7e+06 4.6e+06 5.3e+06 ...
##  $ pendapatan_missing    : logi  FALSE TRUE FALSE FALSE FALSE FALSE ...
##  $ outlier_usia          : logi  FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ outlier_pendapatan    : logi  FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ usia_minmax           : num  0 0.286 0.143 0.429 0.429 ...
##  $ pendapatan_minmax     : num  0 0.000807 0.001413 0.000605 0.000807 ...
##  $ usia_z                : num  -1.4296 -0.4467 -0.9382 0.0447 0.0447 ...
##  $ pendapatan_z          : num  -0.304 -0.301 -0.299 -0.302 -0.301 ...
##  $ pendapatan_decimal    : num  0.0045 0.0049 0.0052 0.0048 0.0049 0.0051 0.5 0.0047 0.0046 0.0053 ...
##  $ jumlah_transaksi_final: num  5 3 7 2 6 4 20 5 3 8 ...
##  $ total_purchase_final  : 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 ...

Pemeriksaan ini digunakan untuk memastikan tipe data setiap variabel sudah sesuai.

15.2 Dimensi Dataset

dim(
  data_final
)
## [1] 11 16

Hasil tersebut menunjukkan jumlah baris dan kolom pada dataset akhir.

15.3 Ringkasan Dataset

summary(
  data_final
)
##  customer_id            nama                usia           kota          
##  Length:11          Length:11          Min.   :21.00   Length:11         
##  Class :character   Class :character   1st Qu.:24.00   Class :character  
##  Mode  :character   Mode  :character   Median :27.00   Mode  :character  
##                                        Mean   :26.82                     
##                                        3rd Qu.:28.50                     
##                                        Max.   :35.00                     
##     status            pendapatan       pendapatan_missing outlier_usia   
##  Length:11          Min.   :4.50e+06   Mode :logical      Mode :logical  
##  Class :character   1st Qu.:4.75e+06   FALSE:9            FALSE:11       
##  Mode  :character   Median :4.90e+06   TRUE :2                           
##                     Mean   :4.99e+07                                     
##                     3rd Qu.:5.15e+06                                     
##                     Max.   :5.00e+08                                     
##  outlier_pendapatan  usia_minmax     pendapatan_minmax       usia_z        
##  Mode :logical      Min.   :0.0000   Min.   :0.0000000   Min.   :-1.42958  
##  FALSE:10           1st Qu.:0.2143   1st Qu.:0.0005045   1st Qu.:-0.69245  
##  TRUE :1            Median :0.4286   Median :0.0008073   Median : 0.04467  
##                     Mean   :0.4156   Mean   :0.0916246   Mean   : 0.00000  
##                     3rd Qu.:0.5357   3rd Qu.:0.0013118   3rd Qu.: 0.41324  
##                     Max.   :1.0000   Max.   :1.0000000   Max.   : 2.01035  
##   pendapatan_z     pendapatan_decimal jumlah_transaksi_final
##  Min.   :-0.3041   Min.   :0.00450    Min.   : 0.000        
##  1st Qu.:-0.3024   1st Qu.:0.00475    1st Qu.: 3.000        
##  Median :-0.3014   Median :0.00490    Median : 5.000        
##  Mean   : 0.0000   Mean   :0.04990    Mean   : 5.727        
##  3rd Qu.:-0.2998   3rd Qu.:0.00515    3rd Qu.: 6.500        
##  Max.   : 3.0151   Max.   :0.50000    Max.   :20.000        
##  total_purchase_final
##  Min.   :       0    
##  1st Qu.:  850000    
##  Median : 1500000    
##  Mean   : 3618182    
##  3rd Qu.: 2400000    
##  Max.   :25000000

Ringkasan digunakan untuk melihat kondisi umum dataset setelah seluruh proses preprocessing dilakukan.

15.4 Audit Dataset Akhir

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           9
## 4                    kota character              0              0           3
## 5                  status character              0              0           2
## 6              pendapatan   numeric              0              0           9
## 7      pendapatan_missing   logical              0              0           2
## 8            outlier_usia   logical              0              0           1
## 9      outlier_pendapatan   logical              0              0           2
## 10            usia_minmax   numeric              0              0           9
## 11      pendapatan_minmax   numeric              0              0           9
## 12                 usia_z   numeric              0              0           9
## 13           pendapatan_z   numeric              0              0           9
## 14     pendapatan_decimal   numeric              0              0           9
## 15 jumlah_transaksi_final   numeric              0              0           9
## 16   total_purchase_final   numeric              0              0          11

Audit akhir digunakan untuk melihat jumlah missing value, persentase missing value, tipe data, dan jumlah nilai unik setelah preprocessing.

15.5 Pemeriksaan Duplikasi Akhir

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

Jika hasilnya 0, berarti tidak terdapat customer_id yang duplikat.

15.6 Pemeriksaan Missing Value Akhir

colSums(
  is.na(
    data_final
  )
)
##            customer_id                   nama                   usia 
##                      0                      0                      0 
##                   kota                 status             pendapatan 
##                      0                      0                      0 
##     pendapatan_missing           outlier_usia     outlier_pendapatan 
##                      0                      0                      0 
##            usia_minmax      pendapatan_minmax                 usia_z 
##                      0                      0                      0 
##           pendapatan_z     pendapatan_decimal jumlah_transaksi_final 
##                      0                      0                      0 
##   total_purchase_final 
##                      0

Pemeriksaan ini digunakan untuk mengetahui apakah masih terdapat nilai kosong pada dataset akhir.

16. Perbandingan Sebelum dan Sesudah Preprocessing

Untuk melihat perubahan kondisi data, beberapa indikator dibandingkan antara dataset awal dan dataset akhir.

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

perbandingan
##               indikator sebelum sesudah
## 1          Jumlah baris      12      11
## 2          Jumlah kolom       6      16
## 3 Duplikasi customer_id       1       0
## 4   Total missing value       4       0

Tabel tersebut memberikan gambaran perubahan kondisi data sebelum dan sesudah preprocessing. Jumlah duplikasi dan missing value dapat digunakan sebagai indikator sederhana untuk melihat hasil proses cleaning.

16.1 Menampilkan Dataset Final

data_final
##    customer_id   nama usia      kota      status pendapatan pendapatan_missing
## 1         C001    Ani   21 pekanbaru       aktif    4.5e+06              FALSE
## 2         C002   Budi   25 pekanbaru       aktif    4.9e+06               TRUE
## 3         C003  Citra   23 pekanbaru       aktif    5.2e+06              FALSE
## 4         C004   Dodi   27     dumai       aktif    4.8e+06              FALSE
## 5         C005    Eka   27 pekanbaru tidak aktif    4.9e+06              FALSE
## 6         C006   Fani   27     dumai tidak aktif    5.1e+06              FALSE
## 7         C007 Gilang   31 pekanbaru       aktif    5.0e+08              FALSE
## 8         C008   Hana   29      siak       aktif    4.7e+06              FALSE
## 9         C009  Indra   22 pekanbaru       aktif    4.6e+06              FALSE
## 10        C010   Joko   35     dumai tidak aktif    5.3e+06              FALSE
## 11        C011   Kiki   28 pekanbaru       aktif    4.9e+06               TRUE
##    outlier_usia outlier_pendapatan usia_minmax pendapatan_minmax      usia_z
## 1         FALSE              FALSE  0.00000000      0.0000000000 -1.42958323
## 2         FALSE              FALSE  0.28571429      0.0008072654 -0.44674476
## 3         FALSE              FALSE  0.14285714      0.0014127144 -0.93816399
## 4         FALSE              FALSE  0.42857143      0.0006054490  0.04467448
## 5         FALSE              FALSE  0.42857143      0.0008072654  0.04467448
## 6         FALSE              FALSE  0.42857143      0.0012108981  0.04467448
## 7         FALSE               TRUE  0.71428571      1.0000000000  1.02751295
## 8         FALSE              FALSE  0.57142857      0.0004036327  0.53609371
## 9         FALSE              FALSE  0.07142857      0.0002018163 -1.18387361
## 10        FALSE              FALSE  1.00000000      0.0016145308  2.01035142
## 11        FALSE              FALSE  0.50000000      0.0008072654  0.29038409
##    pendapatan_z pendapatan_decimal jumlah_transaksi_final total_purchase_final
## 1    -0.3041235             0.0045                      5              1.5e+06
## 2    -0.3014440             0.0049                      3              9.0e+05
## 3    -0.2994343             0.0052                      7              2.7e+06
## 4    -0.3021138             0.0048                      2              6.0e+05
## 5    -0.3014440             0.0049                      6              2.1e+06
## 6    -0.3001042             0.0051                      4              1.3e+06
## 7     3.0151095             0.5000                     20              2.5e+07
## 8    -0.3027837             0.0047                      5              1.7e+06
## 9    -0.3034536             0.0046                      3              8.0e+05
## 10   -0.2987645             0.0053                      8              3.2e+06
## 11   -0.3014440             0.0049                      0              0.0e+00

Dataset ini merupakan hasil akhir setelah dilakukan pemeriksaan data, cleaning, penanganan missing value, pemeriksaan outlier, transformasi, dan integrasi dengan data transaksi.

17. Kesimpulan

Berdasarkan proses yang telah dilakukan, dataset pelanggan dan dataset transaksi berhasil dipersiapkan melalui beberapa tahap preprocessing.

Pada pemeriksaan awal ditemukan beberapa masalah pada dataset pelanggan, yaitu missing value, duplikasi customer_id, perbedaan penulisan kategori, serta nilai usia yang tidak wajar. Masalah tersebut diperbaiki secara bertahap agar data menjadi lebih konsisten dan lebih mudah digunakan pada analisis berikutnya.

Data kategorik seperti kota dan status diseragamkan dengan menghilangkan spasi yang tidak diperlukan, menyamakan penggunaan huruf, dan menyatukan kategori yang memiliki arti sama. Duplikasi customer_id kemudian dihapus dengan mempertahankan data yang muncul pertama kali.

Nilai usia yang tidak wajar, yaitu 150 tahun, diubah menjadi NA karena nilainya tidak sesuai dengan kondisi data. Missing value pada variabel numerik kemudian ditangani menggunakan median, sedangkan missing value pada variabel kategorik ditangani menggunakan modus.

Selanjutnya dilakukan pemeriksaan outlier menggunakan boxplot dan metode IQR. Outlier pada pendapatan tidak langsung dihapus karena belum tentu merupakan kesalahan. Sebagai alternatif, dilakukan winsorizing untuk membatasi nilai yang terlalu ekstrem tanpa menghilangkan observasi.

Data numerik kemudian ditransformasikan menggunakan tiga metode, yaitu Min-Max, Z-Score, dan Decimal Scaling. Ketiga metode tersebut menghasilkan skala data yang berbeda dan dapat digunakan sesuai kebutuhan analisis.

Tahap berikutnya adalah integrasi antara data pelanggan dan data transaksi. Sebelum digabungkan, nama identifier disamakan menjadi customer_id. Penggabungan dilakukan menggunakan merge() dengan all.x = TRUE sehingga seluruh pelanggan pada dataset utama tetap dipertahankan.

Setelah semua proses selesai, dataset akhir kembali diperiksa melalui pemeriksaan struktur, dimensi, missing value, duplikasi, dan audit data. Hasil tersebut menunjukkan kondisi dataset setelah melalui seluruh proses preprocessing.

Dengan demikian, data yang awalnya masih memiliki beberapa masalah telah menjadi lebih rapi, konsisten, dan lebih siap digunakan untuk tahap analisis data mining selanjutnya.