Pada praktikum ini digunakan data pelanggan dari sebuah perusahaan e-commerce. Data yang digunakan berjumlah 100 observasi. Sebelum data digunakan untuk analisis, dilakukan beberapa tahapan preprocessing untuk memastikan data berada dalam kondisi yang lebih baik.
Tahapan preprocessing yang dilakukan meliputi pemeriksaan struktur data, pengecekan kualitas data, pembersihan data, penanganan missing value, identifikasi outlier, transformasi data, integrasi data, dan validasi akhir.
Pada tahap awal dibuat data pelanggan sebanyak 100 observasi. Data dibuat secara simulasi menggunakan set.seed() agar hasil yang diperoleh tetap sama ketika kode dijalankan kembali.
set.seed(2026)
n <- 100
pelanggan_raw <- data.frame(
customer_id = sprintf("C%03d", 1:n),
nama = paste("Pelanggan", sprintf("%03d", 1:n)),
usia = sample(18:60, n, replace = TRUE),
pendapatan = round(
rnorm(n, mean = 5000000, sd = 900000),
-4
),
kota = sample(
c("Pekanbaru", "Dumai", "Siak", "Bengkalis"),
n,
replace = TRUE
),
status = sample(
c("Aktif", "Tidak Aktif"),
n,
replace = TRUE,
prob = c(0.75, 0.25)
),
stringsAsFactors = FALSE
)
pelanggan_raw$usia[c(8, 37, 74)] <- NA
pelanggan_raw$pendapatan[c(12, 45, 88, 96)] <- NA
pelanggan_raw$kota[c(21, 63, 91)] <- NA
pelanggan_raw$kota[c(2, 15, 34)] <-
c(" PKU", "PEKANBARU", "pekanbaru")
pelanggan_raw$kota[c(6, 27)] <-
c("DUMAI", "dumai")
pelanggan_raw$status[c(5, 19, 41)] <-
c("aktif", "ACTIVE", "A")
pelanggan_raw$status[c(23, 58)] <-
c("nonaktif", "tidak aktif")
# Membuat nilai yang tidak wajar
pelanggan_raw$usia[55] <- 150
pelanggan_raw$pendapatan[72] <- 500000000
# Membuat duplikasi customer_id
pelanggan_raw$customer_id[100] <-
pelanggan_raw$customer_id[99]
pelanggan_raw$nama[100] <-
pelanggan_raw$nama[99]
pelanggan_raw$usia[100] <-
pelanggan_raw$usia[99]
pelanggan_raw$pendapatan[100] <-
pelanggan_raw$pendapatan[99]
pelanggan_raw$kota[100] <-
pelanggan_raw$kota[99]
pelanggan_raw$status[100] <-
pelanggan_raw$status[99]
head(pelanggan_raw)
## customer_id nama usia pendapatan kota status
## 1 C001 Pelanggan 001 46 3510000 Bengkalis Aktif
## 2 C002 Pelanggan 002 50 5080000 PKU Aktif
## 3 C003 Pelanggan 003 55 5580000 Bengkalis Aktif
## 4 C004 Pelanggan 004 44 5460000 Bengkalis Aktif
## 5 C005 Pelanggan 005 53 3260000 Dumai aktif
## 6 C006 Pelanggan 006 22 5010000 DUMAI Aktif
Output:
Data awal berhasil dibuat dengan jumlah 100 observasi. Pada tahap ini dataset masih sengaja dibuat memiliki beberapa permasalahan, seperti nilai kosong, penulisan kategori yang berbeda, data duplikat, serta nilai yang terlalu ekstrem. Kondisi tersebut nantinya akan diperbaiki pada tahap preprocessing.
Sebelum melakukan pembersihan, kondisi awal data perlu diperiksa terlebih dahulu. Pemeriksaan ini bertujuan untuk mengetahui ukuran data, nama variabel, tipe data, serta gambaran nilai pada setiap variabel.
dim(pelanggan_raw)
## [1] 100 6
names(pelanggan_raw)
## [1] "customer_id" "nama" "usia" "pendapatan" "kota"
## [6] "status"
str(pelanggan_raw)
## 'data.frame': 100 obs. of 6 variables:
## $ customer_id: chr "C001" "C002" "C003" "C004" ...
## $ nama : chr "Pelanggan 001" "Pelanggan 002" "Pelanggan 003" "Pelanggan 004" ...
## $ usia : num 46 50 55 44 53 22 48 NA 41 36 ...
## $ pendapatan : num 3510000 5080000 5580000 5460000 3260000 5010000 3910000 4720000 4880000 3840000 ...
## $ kota : chr "Bengkalis" " PKU" "Bengkalis" "Bengkalis" ...
## $ status : chr "Aktif" "Aktif" "Aktif" "Aktif" ...
head(pelanggan_raw)
## customer_id nama usia pendapatan kota status
## 1 C001 Pelanggan 001 46 3510000 Bengkalis Aktif
## 2 C002 Pelanggan 002 50 5080000 PKU Aktif
## 3 C003 Pelanggan 003 55 5580000 Bengkalis Aktif
## 4 C004 Pelanggan 004 44 5460000 Bengkalis Aktif
## 5 C005 Pelanggan 005 53 3260000 Dumai aktif
## 6 C006 Pelanggan 006 22 5010000 DUMAI Aktif
summary(pelanggan_raw)
## customer_id nama usia pendapatan
## Length:100 Length:100 Min. : 18.00 Min. : 3260000
## Class :character Class :character 1st Qu.: 32.00 1st Qu.: 4425000
## Mode :character Mode :character Median : 42.00 Median : 5080000
## Mean : 41.49 Mean : 10116562
## 3rd Qu.: 51.00 3rd Qu.: 5532500
## Max. :150.00 Max. :500000000
## NA's :3 NA's :4
## kota status
## Length:100 Length:100
## Class :character Class :character
## Mode :character Mode :character
##
##
##
##
Output:
Hasil pemeriksaan menunjukkan jumlah baris dan kolom pada dataset serta tipe data dari setiap variabel. Dari head() dapat dilihat beberapa data awal, sedangkan summary() memberikan gambaran statistik secara umum.
Interpretasi:
Berdasarkan hasil tersebut, dataset sudah berhasil terbentuk dan dapat dilanjutkan ke tahap pemeriksaan kualitas data. Namun, masih perlu dilakukan pengecekan lebih lanjut karena pada data awal terdapat beberapa kondisi yang belum sesuai.
Setelah struktur data diketahui, langkah berikutnya adalah mencari nilai yang kosong. Pemeriksaan ini penting karena data yang kosong dapat memengaruhi hasil analisis apabila tidak ditangani dengan baik.
colSums(is.na(pelanggan_raw))
## customer_id nama usia pendapatan kota status
## 0 0 3 4 3 0
round(
colMeans(is.na(pelanggan_raw)) * 100,
2
)
## customer_id nama usia pendapatan kota status
## 0 0 3 4 3 0
Output:
Output menunjukkan jumlah dan persentase nilai NA pada setiap variabel. Dengan hasil tersebut dapat diketahui variabel mana yang memiliki data kosong.
Interpretasi:
Dari hasil pemeriksaan terlihat bahwa terdapat beberapa nilai yang belum tersedia pada variabel tertentu. Oleh karena itu, data kosong tersebut perlu ditangani sebelum dataset digunakan untuk analisis selanjutnya.
Data duplikat perlu diperiksa karena satu pelanggan seharusnya mempunyai satu customer_id. Jika ID yang sama muncul lebih dari satu kali, maka jumlah pelanggan dapat menjadi tidak sesuai.
sum(duplicated(pelanggan_raw))
## [1] 1
sum(
duplicated(
pelanggan_raw$customer_id
)
)
## [1] 1
pelanggan_raw[
duplicated(
pelanggan_raw$customer_id
) |
duplicated(
pelanggan_raw$customer_id,
fromLast = TRUE
),
]
## customer_id nama usia pendapatan kota status
## 99 C099 Pelanggan 099 42 4550000 Siak Aktif
## 100 C099 Pelanggan 099 42 4550000 Siak Aktif
Output:
Hasil pemeriksaan menunjukkan adanya customer_id yang muncul lebih dari satu kali.
Interpretasi:
Data yang mempunyai ID sama perlu diperiksa dan dibersihkan. Pada tahap ini duplikasi dianggap sebagai data yang tidak diperlukan sehingga hanya satu data untuk setiap pelanggan yang akan dipertahankan.
Pada dataset terdapat beberapa kategori yang ditulis dengan format berbeda. Contohnya terdapat penggunaan huruf besar, huruf kecil, serta spasi yang tidak diperlukan. Kondisi ini dapat membuat kategori yang sebenarnya sama dibaca sebagai kategori yang berbeda.
pelanggan <- pelanggan_raw
pelanggan$kota <-
trimws(
pelanggan$kota
)
pelanggan$status <-
trimws(
pelanggan$status
)
pelanggan$kota <-
tolower(
pelanggan$kota
)
pelanggan$status <-
tolower(
pelanggan$status
)
sort(
unique(
pelanggan$kota
)
)
## [1] "bengkalis" "dumai" "pekanbaru" "pku" "siak"
sort(
unique(
pelanggan$status
)
)
## [1] "a" "active" "aktif" "nonaktif" "tidak aktif"
Output:
Setelah dilakukan trimws() dan tolower(), penulisan kategori menjadi lebih seragam karena spasi tambahan dan perbedaan huruf besar-kecil sudah dihilangkan.
Interpretasi:
Standardisasi ini dilakukan sebagai langkah awal sebelum kategori disamakan sepenuhnya. Dengan format teks yang sudah seragam, proses pengelompokan kategori menjadi lebih mudah.
Kategori yang mempunyai arti sama kemudian disatukan. Tujuannya agar satu informasi tidak dianggap sebagai beberapa kategori yang berbeda.
pelanggan$kota[
pelanggan$kota %in% c(
"pku",
"pekanbaru"
)
] <- "Pekanbaru"
pelanggan$kota[
pelanggan$kota == "dumai"
] <- "Dumai"
pelanggan$kota[
pelanggan$kota == "siak"
] <- "Siak"
pelanggan$kota[
pelanggan$kota == "bengkalis"
] <- "Bengkalis"
pelanggan$status[
pelanggan$status %in% c(
"aktif",
"active",
"a"
)
] <- "Aktif"
pelanggan$status[
pelanggan$status %in% c(
"tidak aktif",
"nonaktif"
)
] <- "Tidak Aktif"
sort(
unique(
pelanggan$kota
)
)
## [1] "Bengkalis" "Dumai" "Pekanbaru" "Siak"
sort(
unique(
pelanggan$status
)
)
## [1] "Aktif" "Tidak Aktif"
Output:
Kategori kota dan status yang sebelumnya memiliki beberapa variasi sekarang sudah diseragamkan menjadi kategori yang lebih konsisten.
Interpretasi:
Hasil tersebut menunjukkan bahwa kategori yang memiliki makna sama sudah digabungkan. Langkah ini penting agar proses analisis kategorik nantinya tidak menghasilkan kategori yang sebenarnya merupakan informasi yang sama.
Setelah data diperiksa, baris yang memiliki customer_id sama dihapus. Penghapusan dilakukan dengan mempertahankan kemunculan pertama.
pelanggan <-
pelanggan[
!duplicated(
pelanggan$customer_id
),
]
rownames(pelanggan) <- NULL
dim(pelanggan)
## [1] 99 6
sum(
duplicated(
pelanggan$customer_id
)
)
## [1] 0
Output:
Jumlah duplikasi setelah proses pembersihan menjadi 0.
Interpretasi:
Hal tersebut menunjukkan bahwa setiap pelanggan sekarang memiliki customer_id yang unik. Data juga sudah lebih aman digunakan karena satu pelanggan tidak dihitung lebih dari satu kali.
Nilai numerik perlu diperiksa untuk memastikan tidak terdapat angka yang berada di luar batas yang masuk akal. Pada variabel usia, misalnya, nilai yang terlalu tinggi dapat menunjukkan adanya kesalahan input.
pelanggan[
pelanggan$usia < 15 |
pelanggan$usia > 100,
]
## customer_id nama usia pendapatan kota status
## NA <NA> <NA> NA NA <NA> <NA>
## NA.1 <NA> <NA> NA NA <NA> <NA>
## 55 C055 Pelanggan 055 150 5340000 Dumai Aktif
## NA.2 <NA> <NA> NA NA <NA> <NA>
pelanggan[
pelanggan$pendapatan < 0,
]
## customer_id nama usia pendapatan kota status
## NA <NA> <NA> NA NA <NA> <NA>
## NA.1 <NA> <NA> NA NA <NA> <NA>
## NA.2 <NA> <NA> NA NA <NA> <NA>
## NA.3 <NA> <NA> NA NA <NA> <NA>
Output:
Terdapat nilai usia yang berada di luar batas yang ditentukan. Sementara itu, pemeriksaan pendapatan digunakan untuk memastikan tidak terdapat nilai pendapatan negatif.
Interpretasi:
Nilai usia yang terlalu tinggi perlu diperiksa karena kemungkinan merupakan kesalahan pengisian data. Pada dataset ini nilai tersebut akan diperbaiki agar sesuai dengan kondisi yang masuk akal.
Nilai usia yang tidak masuk akal diperbaiki berdasarkan data simulasi yang digunakan dalam praktikum.
pelanggan$usia[
pelanggan$customer_id == "C055"
] <- 50
pelanggan[
pelanggan$customer_id == "C055",
c(
"customer_id",
"usia"
)
]
## customer_id usia
## 55 C055 50
Output:
Nilai usia pelanggan dengan ID C055 sudah berubah menjadi 50.
Interpretasi:
Setelah diperbaiki, nilai usia tersebut sudah berada pada rentang yang lebih wajar sehingga dapat digunakan pada tahap analisis berikutnya.
Setelah proses cleaning dasar selesai, nilai kosong kembali diperiksa untuk menentukan metode penanganan yang sesuai.
colSums(
is.na(pelanggan)
)
## customer_id nama usia pendapatan kota status
## 0 0 3 4 3 0
pelanggan[
!complete.cases(pelanggan),
]
## customer_id nama usia pendapatan kota status
## 8 C008 Pelanggan 008 NA 4720000 Pekanbaru Tidak Aktif
## 12 C012 Pelanggan 012 46 NA Pekanbaru Aktif
## 21 C021 Pelanggan 021 29 3850000 <NA> Aktif
## 37 C037 Pelanggan 037 NA 5590000 Bengkalis Aktif
## 45 C045 Pelanggan 045 20 NA Dumai Aktif
## 63 C063 Pelanggan 063 40 5200000 <NA> Aktif
## 74 C074 Pelanggan 074 NA 5020000 Bengkalis Aktif
## 88 C088 Pelanggan 088 59 NA Bengkalis Aktif
## 91 C091 Pelanggan 091 51 5480000 <NA> Tidak Aktif
## 96 C096 Pelanggan 096 34 NA Dumai Tidak Aktif
Output:
Masih terdapat beberapa nilai kosong pada variabel numerik dan kategorik.
Interpretasi:
Karena jumlah data tidak terlalu besar, nilai kosong tidak langsung dihapus. Sebagai gantinya digunakan metode imputasi agar jumlah observasi tetap dapat dipertahankan.
Untuk variabel numerik digunakan median sebagai nilai pengganti. Median dipilih karena lebih tahan terhadap pengaruh nilai ekstrem dibandingkan mean.
median_usia <-
median(
pelanggan$usia,
na.rm = TRUE
)
median_pendapatan <-
median(
pelanggan$pendapatan,
na.rm = TRUE
)
pelanggan$usia_imputasi <-
pelanggan$usia
pelanggan$pendapatan_imputasi <-
pelanggan$pendapatan
pelanggan$usia_imputasi[
is.na(
pelanggan$usia_imputasi
)
] <- median_usia
pelanggan$pendapatan_imputasi[
is.na(
pelanggan$pendapatan_imputasi
)
] <- median_pendapatan
summary(
pelanggan[
,
c(
"usia_imputasi",
"pendapatan_imputasi"
)
]
)
## usia_imputasi pendapatan_imputasi
## Min. :18.00 Min. : 3260000
## 1st Qu.:32.00 1st Qu.: 4440000
## Median :42.00 Median : 5080000
## Mean :40.49 Mean : 9969293
## 3rd Qu.:50.50 3rd Qu.: 5510000
## Max. :60.00 Max. :500000000
Output:
Setelah imputasi dilakukan, nilai NA pada variabel usia dan pendapatan digantikan menggunakan nilai median masing-masing variabel.
Interpretasi:
Penggunaan median membantu mempertahankan jumlah observasi tanpa terlalu dipengaruhi oleh nilai pendapatan yang ekstrem. Kolom baru juga dibuat agar nilai asli tetap dapat dibandingkan dengan nilai setelah imputasi.
Untuk variabel kota, data yang kosong diberikan kategori khusus Tidak diketahui.
pelanggan$kota_imputasi <-
pelanggan$kota
pelanggan$kota_imputasi[
is.na(
pelanggan$kota_imputasi
)
] <- "Tidak diketahui"
table(
pelanggan$kota_imputasi,
useNA = "ifany"
)
##
## Bengkalis Dumai Pekanbaru Siak Tidak diketahui
## 21 29 26 20 3
Output:
Nilai NA pada variabel kota sudah diganti menjadi kategori Tidak diketahui.
Interpretasi:
Cara ini digunakan agar data yang tidak memiliki informasi kota tetap dipertahankan tanpa memasukkannya secara paksa ke salah satu kota yang tersedia.
Selain melakukan imputasi, dibuat variabel indikator untuk mencatat apakah suatu data sebelumnya memiliki nilai kosong.
pelanggan$pendapatan_missing <-
as.integer(
is.na(
pelanggan$pendapatan
)
)
table(
pelanggan$pendapatan_missing
)
##
## 0 1
## 95 4
Output:
Nilai 1 menunjukkan bahwa data pendapatan awalnya kosong, sedangkan 0 menunjukkan bahwa data tersedia.
Interpretasi:
Variabel indikator ini berguna karena informasi mengenai keberadaan missing value tetap dapat disimpan walaupun nilai aslinya sudah diimputasi.
Outlier merupakan nilai yang letaknya jauh dari sebagian besar data. Pada variabel pendapatan, kondisi ini diperiksa menggunakan boxplot.
boxplot(
pelanggan$pendapatan_imputasi,
horizontal = TRUE,
main = "Boxplot Pendapatan Pelanggan",
xlab = "Pendapatan",
col = "mediumpurple"
)
Output:
Boxplot memperlihatkan sebaran pendapatan serta beberapa titik yang berada jauh dari bagian utama data.
Interpretasi:
Titik yang berada jauh dari sebaran utama merupakan kandidat outlier. Nilai tersebut tidak langsung dihapus karena perlu dilihat apakah memang merupakan kesalahan atau merupakan kondisi yang benar-benar terjadi.
Untuk memperoleh batas yang lebih jelas, digunakan metode IQR. Nilai yang berada di luar batas Q1 - 1.5(IQR) dan Q3 + 1.5(IQR) dianggap sebagai kandidat outlier.
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%
## 4440000 5510000 1070000 2835000 7115000
Output:
Output memberikan nilai Q1, Q3, IQR, batas bawah, dan batas atas.
Interpretasi:
Nilai pendapatan yang berada di luar batas tersebut akan dikategorikan sebagai kandidat outlier. Metode IQR digunakan karena cukup sederhana dan tidak terlalu dipengaruhi oleh nilai ekstrem.
Nilai ekstrem tidak langsung dihapus dari dataset. Sebagai alternatif, dibuat variabel baru dengan metode winsorization.
pelanggan$pendapatan_winsor <-
pmin(
pmax(
pelanggan$pendapatan_imputasi,
batas_bawah
),
batas_atas
)
summary(
pelanggan$pendapatan_winsor
)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 3260000 4440000 5080000 4990657 5510000 7115000
Output:
Nilai pendapatan yang berada di luar batas IQR dibatasi pada batas bawah atau batas atas yang telah ditentukan.
Interpretasi:
Winsorization digunakan untuk mengurangi pengaruh nilai ekstrem tanpa langsung membuang observasi. Data pendapatan asli tetap dipertahankan sehingga hasil sebelum dan sesudah perlakuan dapat dibandingkan.
Transformasi Min-Max digunakan untuk mengubah nilai pendapatan ke rentang 0 sampai 1. Cara ini berguna ketika skala antarvariabel terlalu berbeda.
Rumus Min-Max:
\[ x' = \frac{x-\min(x)}{\max(x)-\min(x)} \]
minmax <- function(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
}
pelanggan$pendapatan_minmax <-
minmax(
pelanggan$pendapatan_winsor
)
summary(
pelanggan$pendapatan_minmax
)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.0000 0.3061 0.4721 0.4489 0.5837 1.0000
Output:
Nilai pendapatan setelah transformasi berada pada rentang 0 sampai 1.
Interpretasi:
Transformasi ini membuat skala pendapatan menjadi lebih seragam sehingga dapat lebih mudah digunakan pada metode analisis yang membutuhkan skala variabel yang relatif sama.
Transformasi logaritmik digunakan sebagai alternatif untuk mengurangi rentang nilai pendapatan yang terlalu besar.
pelanggan$pendapatan_log <-
log1p(
pelanggan$pendapatan_winsor
)
summary(
pelanggan$pendapatan_log
)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 15.00 15.31 15.44 15.41 15.52 15.78
Output:
Variabel baru pendapatan_log memiliki skala yang lebih terkompresi dibandingkan pendapatan awal.
Interpretasi:
Transformasi log membantu mengurangi pengaruh nilai pendapatan yang sangat besar sehingga distribusi data dapat menjadi lebih mudah dianalisis.
Selain data pelanggan, digunakan data transaksi yang memiliki identifier berbeda. Data transaksi dibuat sebagai sumber data kedua.
set.seed(2026)
id_transaksi <- c(
sprintf("C%03d", 1:95),
"C101",
"C102",
"C103"
)
transaksi_raw <- data.frame(
cust_id = id_transaksi,
jumlah_transaksi = sample(
1:20,
length(id_transaksi),
replace = TRUE
),
total_purchase = sample(
seq(
250000,
25000000,
by = 250000
),
length(id_transaksi),
replace = TRUE
),
stringsAsFactors = FALSE
)
head(transaksi_raw)
## cust_id jumlah_transaksi total_purchase
## 1 C001 1 20250000
## 2 C002 6 18250000
## 3 C003 13 22000000
## 4 C004 15 22250000
## 5 C005 12 3250000
## 6 C006 4 12750000
Output:
Data transaksi mempunyai kolom cust_id, jumlah transaksi, dan total pembelian. Identifier pada tabel ini menggunakan nama cust_id, sedangkan dataset pelanggan menggunakan customer_id.
Interpretasi:
Karena nama identifier berbeda, perlu dilakukan penyesuaian sebelum kedua dataset digabungkan.
Nama identifier pada data transaksi diubah menjadi customer_id supaya sama dengan data pelanggan.
transaksi <- transaksi_raw
names(transaksi)[
names(transaksi) == "cust_id"
] <- "customer_id"
names(transaksi)
## [1] "customer_id" "jumlah_transaksi" "total_purchase"
Output:
Nama kolom cust_id sudah berubah menjadi customer_id.
Interpretasi:
Dengan identifier yang sama, kedua dataset sudah siap untuk digabungkan menggunakan kolom customer_id.
Penggabungan dilakukan menggunakan merge(). Data pelanggan tetap dipertahankan walaupun tidak semua pelanggan mempunyai data transaksi.
data_terintegrasi <-
merge(
pelanggan,
transaksi,
by = "customer_id",
all.x = TRUE
)
head(
data_terintegrasi[
,
c(
"customer_id",
"nama",
"jumlah_transaksi",
"total_purchase"
)
],
10
)
## customer_id nama jumlah_transaksi total_purchase
## 1 C001 Pelanggan 001 1 20250000
## 2 C002 Pelanggan 002 6 18250000
## 3 C003 Pelanggan 003 13 22000000
## 4 C004 Pelanggan 004 15 22250000
## 5 C005 Pelanggan 005 12 3250000
## 6 C006 Pelanggan 006 4 12750000
## 7 C007 Pelanggan 007 16 5250000
## 8 C008 Pelanggan 008 5 4500000
## 9 C009 Pelanggan 009 12 11000000
## 10 C010 Pelanggan 010 2 7000000
Output:
Data pelanggan sudah bergabung dengan informasi transaksi berdasarkan customer_id.
Interpretasi:
Penggunaan all.x = TRUE membuat seluruh pelanggan tetap berada dalam data hasil penggabungan. Jika seorang pelanggan tidak mempunyai transaksi, maka informasi transaksi untuk pelanggan tersebut akan bernilai NA.
Setelah dua tabel digabungkan, hasilnya perlu diperiksa kembali. Pemeriksaan ini dilakukan untuk memastikan tidak muncul duplikasi baru dan mengetahui apakah masih ada data transaksi yang kosong.
nrow(pelanggan)
## [1] 99
nrow(data_terintegrasi)
## [1] 99
sum(
duplicated(
data_terintegrasi$customer_id
)
)
## [1] 0
colSums(
is.na(
data_terintegrasi[
,
c(
"jumlah_transaksi",
"total_purchase"
)
]
)
)
## jumlah_transaksi total_purchase
## 4 4
Output:
Output memberikan jumlah observasi sebelum dan sesudah penggabungan, jumlah duplikasi customer_id, serta jumlah nilai kosong pada variabel transaksi.
Interpretasi:
Pemeriksaan ini dilakukan untuk memastikan proses integrasi tidak membuat masalah baru. Jika terdapat NA pada variabel transaksi, hal tersebut dapat menunjukkan adanya pelanggan yang tidak mempunyai pasangan data transaksi.
Tahap terakhir adalah melakukan pengecekan ulang terhadap dataset yang sudah diproses. Tujuannya untuk memastikan masalah utama yang ditemukan di awal sudah ditangani.
hasil_akhir <- data.frame(
pemeriksaan = c(
"Jumlah observasi",
"Duplikasi customer_id",
"Total missing value",
"Usia di luar batas",
"Jumlah kandidat outlier"
),
hasil = c(
nrow(pelanggan),
sum(
duplicated(
pelanggan$customer_id
)
),
sum(
is.na(
pelanggan
)
),
sum(
pelanggan$usia < 15 |
pelanggan$usia > 100,
na.rm = TRUE
),
sum(
pelanggan$pendapatan_imputasi <
batas_bawah |
pelanggan$pendapatan_imputasi >
batas_atas
)
)
)
hasil_akhir
## pemeriksaan hasil
## 1 Jumlah observasi 99
## 2 Duplikasi customer_id 0
## 3 Total missing value 10
## 4 Usia di luar batas 0
## 5 Jumlah kandidat outlier 1
Output:
Tabel hasil akhir memberikan ringkasan kondisi dataset setelah seluruh proses preprocessing dilakukan.
Interpretasi:
Dari hasil validasi dapat dilihat kondisi data setelah melalui tahapan pembersihan. Data sudah diperiksa dari sisi duplikasi, missing value, batas nilai usia, serta outlier pada pendapatan.
Berdasarkan tahapan preprocessing yang telah dilakukan, data pelanggan yang pada awalnya masih memiliki beberapa permasalahan telah melalui proses pembersihan dan penyesuaian. Permasalahan yang ditemukan meliputi nilai kosong, kategori yang tidak konsisten, data duplikat, nilai yang tidak wajar, serta nilai pendapatan yang terlalu ekstrem.
Data kosong ditangani menggunakan metode imputasi, sedangkan kategori diseragamkan agar tidak terdapat beberapa label yang sebenarnya mempunyai arti yang sama. Data duplikat pada customer_id juga dihapus sehingga setiap pelanggan memiliki identifier yang unik.
Selanjutnya dilakukan pemeriksaan outlier menggunakan boxplot dan metode IQR. Nilai ekstrem tidak langsung dihapus, tetapi dibuat versi winsorized sebagai alternatif. Pendapatan juga ditransformasikan menggunakan Min-Max dan logaritmik.
Pada tahap akhir, data pelanggan digabungkan dengan data transaksi menggunakan customer_id. Setelah proses tersebut selesai, dilakukan validasi kembali untuk memastikan dataset berada dalam kondisi yang lebih rapi dan siap digunakan untuk tahap analisis atau proses data mining berikutnya.