# clear-up the environment
rm(list = ls())
# chunk options
knitr::opts_chunk$set(
message = FALSE,
warning = FALSE,
fig.align = "center",
comment = "#>"
)
# scientific notation
options(scipen = 9999)
Materi ini diproduksi oleh tim dari Algoritma untuk DSS - Customer Segmentation Using PAM Algorithm. Materi berikut hanya ditujukan untuk kalangan terbatas, meliputi individu/personal yang menerima materi ini secara langsung dari lembaga pelatihan. Materi ini dilarang untuk direproduksi, didistribusikan, diterjemahkan, atau diadaptasikan dalam bentuk apapun di luar izin dari individu dan organisasi yang berkepentingan.
Algoritma adalah pusat pendidikan Data Science di Jakarta. Kami mengadakan workshop dan program pelatihan untuk membantu para profesional dan pelajar untuk mendapatkan keahlian dalam berbagai bidang dalam ruang lingkup Data Science: data visualization, machine learning, data modeling, statistical inference, dan lain-lainnya.
Sebelum masuk ke dalam materi dan menjalankan kode-kode di dalam materi ini, silakan anda melihat bagian Library and Setup untuk melihat dan memastikan semua persyaratan dasar untuk mengikuti materi ini sudah terpenuhi termasuk package-package yang diperlukan. Pada bagian Tujuan Pembelajaran anda dapat melihat secara umum apa saja yang akan dipelajari dalam modul materi ini. Kami harap materi ini akan bermanfaat bagi karir ataupun menambah keahlian peserta.
Clustering adalah salah satu teknik Machine Learning, yang memiliki kemampuan untuk mengelompokkan kumpulan data yang tidak berlabel. Setiap data yang tidak berlabel nantinya akan diklasifikasikan ke dalam kelompok tertentu dimana, titik data yang berada dalam kelompok yang sama akan memiliki sifat atau fitur yang serupa, sedangkan titik data dalam kelompok yang berbeda diharapkan memiliki sifat atau fitur yang sangat berbeda.
Dalam ilmu data, kita dapat menggunakan clustering untuk mendapatkan beberapa wawasan berharga dari data kita dengan melihat hasil pengelompokan yang terjadi. Informasi yang berharga tersebut bisa kita bawa untuk membantu kita dalam menentukan segmentasi market, social netwrok analysis, dan masih banyak lagi. Di luar semua manfaat yang bisa kita dapatkan dari metode clustering, masih ada sebuah stigma yang menempel terhadap metode clustering. Pada artikel ini nantinya akan membahas metode clustering yang dapat digunakan untuk mengatasi stigma yang menempel terhadap metode clustering.
Stigma yang menempel pada clustering adalah hanya bisa digunakan untuk data-data numerik. Hal tersebut terjadi karena banyak sekali implementasi atau contoh dari clustering yang hanya menggunakan data numerik.
Sesungguhnya clustering juga bisa digunakan terhadap data-data kategorikal, dan pada kesempatan kali ini kita akan mencoba menggunakan clustering untuk mengelompokan data kategorikal dan data numerik. Tipe algoritma yang akan kita gunakan nantinya bernama Partitioning Around Medoids dan metode perhitungan jarak yang akan digunakan adalah Gower Distance.
Tujuan utama dari workshop ini adalah untuk memberikan pengenalan yang komprehensif mengenai tools dan perangkat lunak yang digunakan untuk melakukan sekementasi kustomer dengan clustering, yakni sebuah open-source populer: R. Adapun materi ini akan mencakup:
Sebelum itu mari kita coba berkenalan dengan R Studio UI, dengan melihat gambar di bawah ini.
R merupakan bahasa pemrograman di mana seperangkat instruksi akan diterjemahkan ke dalam bahasa komputer, sedangkan RStudio merupakan aplikasi tambahan yang dapat membantu pengguna R melakukan pekerjaannya.
1. Dibangun oleh ahli statistik, untuk ahli statistik.
R adalah bahasa pemrograman statistik yang dibuat oleh Ross Ihaka dan Robert Gentleman di Departemen Statistik, di University of Auckland (Selandia Baru). R dibuat untuk analisis data, dan dengan demikian, berbeda dari bahasa pemrograman tradisional. R bukan hanya bahasa pemrograman statistik, R juga environment yang lengkap untuk analis data dan perangkat lunak analisis data yang paling banyak digunakan saat ini.
2. Memiliki banyak Library
R menyediakan banyak packages tambahan yang menambahkan fungsionalitas out-of-the-box untuk berbagai kegunaan: uji statistik, analisis deret waktu, visualisasi yang indah, dan berbagai tugas machine learning seperti algoritme regresi, algoritme klasifikasi, dan algoritme clustering. Komunitas R terkenal karena kontribusinya yang aktif dalam hal packages.
3. Sumber Terbuka
Bagian dari alasan komunitasnya yang aktif dan berkembang pesat adalah sifat sumber terbuka (open-source) dari R. Pengguna dapat berkontribusi dalam pembuatan packages, banyak tools statistik dan template kustomisasi untuk visualisasi yang tidak ditemukan dalam aplikasi statistik lain.
4. Digunakan oleh berbagai perusahaan perangkat lunak Terbesar di Dunia
R digunakan oleh Google untuk menghitung Return on Investment (ROI)
dari berbagai iklan, dan seringkali digunakan untuk mengestimasi
casual effect; seperti estimasi dampak dari sebuah fitur dari
suatu aplikasi terhadap jumlah download dari aplikasi tersebut,
ataupun peningkatan tingkat penjualan setelah mengeluarkan
AdWords. Bahkan, Google merilis package R yang dapat digunakan
oleh pengguna R lain untuk melakukan analisis serupa (lihat
CausalImpact
). Banyak pegawai di Google telah berkontribusi
aktif terhadap komunitas pengguna R: mereka seringkali aktif dalam
berbagai grup pengguna R; membuat interface untuk Google Prediction;
membuat coding style versi Google untuk R, dan telah berkontribusi
berbagai package untuk R.
Microsoft juga termasuk sebagai salah satu diantara perusahaan besar yang sangat bergantung pada R. Pada awalnya, Microsoft menggunakan R dalam: platform Azure–tepatnya sebagai capacity planning; sistem matchmaking pada Xbox’s TrueSkill; analisis churn untuk berbagai produk; dan beberapa internal services lain dalam Microsoft’s line of products. Langkah penting yang diambil oleh Microsoft dalam hal ini adalah akuisisi dari Revolution Analytics, yang terkenal atas berbagai produk perkembangan di R; yang sekarang lebih dikenal sebagai Microsoft R Server, Microsoft R Open, Microsoft Data Science Virtual Machine, dll.
5. Ready for Big Data
R dapat terintegrasi dengan tools lain dalam pengolahan big data, library seperti RHadoop, ParallelR, merupakan sebagian dari library yang mampu membantu data engineers untuk melakukan komputasi pararel di R.
# Pada R Studio kita juga bisa memasukan gambar dengan menggunakan code di bawah ini
knitr::include_graphics("assets/RStudio_UI.PNG")
Terdapat 4 panel utama yang harus Anda pahami yaitu :
1. Panel Source : Panel ini merupakan fitur utama dari RStudio, panel ini menampilkan file yang sedang dibuka pada RStudio.
2. Panel Console : Panel ini menampilkan console asli dari R yang digunakan untuk berkomunikasi dengan R session. Terdapat beberapa tab lain seperti Terminal yang dapat digunakan untuk mengakses komputer Anda melalui Command Line Interface (CLI).
3. Panel Environment / History : Bagian ini menampilkan seluruh object R yang sudah dibuat selama session yang sama. Terdapat tab History yang berfungsi untuk melihat history dari kode yang sudah dijalankan sebelumnya.
4. Panel Files/Plot/Packages/Help :
Library/Package adalah sekumpulan fungsi yang digunakan untuk pengolahan data tertentu. Untuk menggunakan fungsi-fungsi pada suatu package, harus dilakukan instalasi package ke komputer terlebih dahulu.
Untuk menginstal packages, klik tab panel Packages pada bagian kanan bawah RStudio, kemudian klik tombol install. Masukan list package berikut ke dalam kolom package yang ingin di-instal (ragam package yang digunakan pada Trial Class). Untuk mendapatkan ilustrasi yang lebih jelas bisa melihat gambar di bawah ini.
knitr::include_graphics("assets/packages_installation.PNG")
Nantinya setelah klik tombol install akan muncul sebuah pop-up baru. Dari pop-up tersebut, kita dapat mengisi library apa saja yang ingin kita isntall pada bagian Packages. Untuk mendapatkan ilustrasi yang lebih jelas bisa melihat gambar di bawah ini.
knitr::include_graphics("assets/packages_installation2.PNG")
Berikut adalah library yang akan kita gunakan dalam melakukan membangun segmentasi kustomer.
tidyverse
& Hmisc
cluster
&
factorextra
Setelah berhasil melakukan instalasi library yang kita butuhkan, kita
harus memanggil library tersebut terlebih dahulu. Untuk memanggil
library tersebut kita akan menggunakan fungsi
library()
.
library(tidyverse)
Pada materi ini, kita akan menggunakan file Rmarkdown (.Rmd). Rmarkdown merupakan package/tools yang digunakan untuk membuat report dengan kualitas tinggi. Pada folder materi ini terdapat file dengan ekstensi .html yang merupakan hasil knit dari Rmarkdown.
Untuk melakukan transformasi R Markdown menjadi format yang kita inginkan, kita bisa mengklik tombol knit dan memilih format file yang di-inginkan. Untuk ilustrasi yang lebih jelas, bisa melihat gambar di bawah ini.
Terdapat beberapa key shortcut yang akan memudahkan anda dalam menggunaan R. Beberapa diantaranya yaitu:
knitr::include_graphics("assets/OtherShortcut.PNG")
Kita akan menganalisis data retail.csv
yang terdapat
pada folder data
. Gunakan fungsi read.csv()
untuk membaca file CSV ke R, lalu simpanlah ke sebuah object dengan nama
retail
.
# Please type your code
retail <- read.csv("data/retail.csv")
Deskripsi kolom:
Order.ID
= Unique ID pemesananShip.Mode
= Jenis pengiriman yang dipilih customerSegment
= Segmentasi/kategori customerCategory
= Kateogri barangSub.Category
= Sub Kategori barangProduct.Name
= Nama produk barangSales
= Total sales dari barang yang dibeli oleh
customerQuantity
= Total barang yang dibeli oleh customerDiscount
= Total diskon yang diberikan kepada
customerProfit
= Total keuntungan yang didapatkan oleh
perusahaanDaripada melihat keseluruhan data, lebih baik kita “mengintip” sebagian baris yang dapat merepresentasikan bentuk keseluruhan data.
Fungsi head()
untuk melihat beberapa baris teratas pada
data (default 6)
# Please type your code
head(retail)
Fungsi tail()
untuk melihat beberapa data terakhir.
# Please type your code
tail(retail)
Setelah berhasil memanggil data yang akan diolah, kita harus memerika
tipe datanya terlebih dahulu. Tujuannya agar data tersebut bisa diolah
lebih lanjut. Untuk menglihat tipe data pada data kita, kita dapat
menggunakan fungsi glimpse()
.
# Please type your code
glimpse(retail)
#> Rows: 9,994
#> Columns: 10
#> $ Order.ID <chr> "CA-2016-152156", "CA-2016-152156", "CA-2016-138688", "US…
#> $ Ship.Mode <chr> "Second Class", "Second Class", "Second Class", "Standard…
#> $ Segment <chr> "Consumer", "Consumer", "Corporate", "Consumer", "Consume…
#> $ Category <chr> "Furniture", "Furniture", "Office Supplies", "Furniture",…
#> $ Sub.Category <chr> "Bookcases", "Chairs", "Labels", "Tables", "Storage", "Fu…
#> $ Product.Name <chr> "Bush Somerset Collection Bookcase", "Hon Deluxe Fabric U…
#> $ Sales <dbl> 261.9600, 731.9400, 14.6200, 957.5775, 22.3680, 48.8600, …
#> $ Quantity <int> 2, 3, 2, 5, 2, 7, 4, 6, 3, 5, 9, 4, 3, 3, 5, 3, 6, 2, 2, …
#> $ Discount <dbl> 0.00, 0.00, 0.00, 0.45, 0.20, 0.00, 0.00, 0.20, 0.20, 0.0…
#> $ Profit <dbl> 41.9136, 219.5820, 6.8714, -383.0310, 2.5164, 14.1694, 1.…
Terdapat berbagai macam tipe data di R, berikut intuisi dari setiap tipe data tersebut.
# character
a_char <- c("Algoritma", "Indonesia", "e-Commerce", "marketing")
# factor
a_factor <- factor(c("AB", "O", "B", "A", "B", "AB", "O"))
# numeric
a_num <- c(-1, 1, 2, 3/4, 0.5)
# integer
an_int <- c(1L, 2L)
# date
a_date <- c("24/Jan/2019", "10-12-1994")
# logical
a_log <- c(TRUE, TRUE, FALSE)
TRUE
atau FALSE
. Penulisan TRUE/FALSE dapat
disingkat menjadi T/F.Cara untuk mengetahui tipe data dari suatu objek, Anda dapat
menggunakan fungsi class()
class(a_char)
#> [1] "character"
Lalu, apa yang akan terjadi jika dalam satu data memiliki beberapa tipe data yang berbeda seperti chunk dibawah ini?
mix <- c("Algoritma", 2022, TRUE)
class(mix)
#> [1] "character"
Bila Anda perhatikan setiap nilai pada object mix
memiliki petik dua, artinya nilai tersebut merupakan
sebuah objek dengan tipe character. Proses perubahan paksa dari suatu
vector bisa disebut sebagai implicit coercion.
Ilustrasi terjadinya implicit coercion dapat dilihat pada gambar di
bawah ini:
knitr::include_graphics("assets/data_type.png")
Pada tahapan persiapan dan eksplorasi, kita akan memanfaatkan
library(tidyverse)
untuk memudahkan.
Persiapan yang akan kita lakukan pada data kita adalah mengubah tipe
data yang belum sesuai. Untuk mengubah tipe data, kita akan menggunakan
fungsi mutate()
Simbol %>%
digunakan untuk menyambungkan proses yang
sequential atau berurutan dari setiap fungsi yang kita
gunakan.
# Please type your code
retail_clean <- retail %>%
mutate_if(is.character, as.factor)
Untuk memastikan apakah tipe dataya sudah berhasil terubah, mari kita
coba cek sekali lagi dengan menggunakan fungsi
glimpse()
# Please type your code
glimpse(retail_clean)
#> Rows: 9,994
#> Columns: 10
#> $ Order.ID <fct> CA-2016-152156, CA-2016-152156, CA-2016-138688, US-2015-1…
#> $ Ship.Mode <fct> Second Class, Second Class, Second Class, Standard Class,…
#> $ Segment <fct> Consumer, Consumer, Corporate, Consumer, Consumer, Consum…
#> $ Category <fct> Furniture, Furniture, Office Supplies, Furniture, Office …
#> $ Sub.Category <fct> Bookcases, Chairs, Labels, Tables, Storage, Furnishings, …
#> $ Product.Name <fct> "Bush Somerset Collection Bookcase", "Hon Deluxe Fabric U…
#> $ Sales <dbl> 261.9600, 731.9400, 14.6200, 957.5775, 22.3680, 48.8600, …
#> $ Quantity <int> 2, 3, 2, 5, 2, 7, 4, 6, 3, 5, 9, 4, 3, 3, 5, 3, 6, 2, 2, …
#> $ Discount <dbl> 0.00, 0.00, 0.00, 0.45, 0.20, 0.00, 0.00, 0.20, 0.20, 0.0…
#> $ Profit <dbl> 41.9136, 219.5820, 6.8714, -383.0310, 2.5164, 14.1694, 1.…
Exploratory Data Analysis bertujuan untuk mendapatkan insight dari data sesuai pertanyaan bisnis yang diajukan. Dari data retail, kita akan coba menjawab pertanyaan bisnis berikut:
Q1: Bagaimanakah performa penjualan (Sales
) untuk setiap
category (Category
) barang yang dijual pada perusahaan
retail tersebut?
Berikut adalah beberapa fungsi dari library dplyr yang akan kita gunakan untuk menjawab pertanyaan bisnis tersebut.
group_by()
: Fungsi ini dapat kita manfaatkan untuk
mengelompokkan setiap segment barang pada data kita.summarise()
: Fungsi ini dapat kita manfaatkan untuk
melakukan perhitungan matematis, untuk melakukan penjumlahan hasil
penjualan untuk setiap segment barang yang dimiliki.arrange(desc())
: Fungsi ini dapat kita manfaatkan untuk
mengurutkan nilai yang ada# Please type your code
retail %>%
group_by(Category) %>%
summarise(Total_Sales = sum(Sales)) %>%
arrange(desc(Total_Sales))
Q2: Berapa jumlah kustomer yang menggunakan mode pengiriman barang
(Ship.Mode
) dengan metode First Class?
fitler()
: Fungsi ini digunakan untuk memberikan sebuah
kondisi tertentuunique(retail_clean$Ship.Mode)
#> [1] Second Class Standard Class First Class Same Day
#> Levels: First Class Same Day Second Class Standard Class
# Please type your code
retail_clean %>%
filter(Ship.Mode == "First Class") %>%
summarise(Total = n())
Dalam mempelajari algoritma PAM dan perhitungan jarak Gower Distance, kita akan membuat sebuah segmentasi kustomer berdasarkan data historis pengunjung Supermarket.
Background/Motivational Story:
Dalam mempelajari algoritma dan metode tersebut, kita akan mengangkat sebuah kasus bisnis yaitu membangun segemntasi kustomer. Segmentasi kustomer merupakan sebuah tahapan yang dilakukan oleh peruhsaan untuk mengelompokan dan melihat profile/karakteristik kustomer pada setiap kelompoknya.
Dari setiap informasi karakteristik kustomer pada setiap kelompoknya, akan membantu perusahaan tersebut dalam berkomunikasi lebih baik terhadap semua kustomer. Komunikasi di sini maksudnya adalah bagaimana perusahaan dapat memberikan promosi yang lebih sesuai dengan setiap karakteristik yang terdapat pada setiap kelompoknya.
Jika komunikasi dapat berlajalan dengan baik, perushaan akan meningkatkan kepuasan dari pelanggan, mempersingkat waktu yang dibutuhkan untuk closing penjualan, sampai meningkatkan retensi pelanggan.
# Data Wrangling
library(tidyverse)
library(Hmisc)
# Machine Learning - Clustering
library(cluster)
library(factoextra)
# Visualization
library(Rtsne)
Data yang akan kita gunakan adalah data historikal pembelian kustomer pada sebuah toko selama 6 bulan terakhir, dari data tersebut nantinya akan coba kita kelompokan untuk membuat beberapa segmentasi kustomer.
# Please run the code down below
cust_purchase <- read.csv("data/ifood_customer.csv")
head(cust_purchase)
Deskripsi kolom:
ID
: unique ID customerYear_Birth
: Tahun kelahiran customerEducation
: Pendidikan terakhir customer (Graduation,
PhD, Undergraduate, Master)Marital_Statuts
: Status pernikahan customer (Single,
Maried, Widow)Income
: Penghasilan customer dalam 1 tahunKidhome
: Jumlah anak kecil yang terdapat pada rumah
customerTeenhome
: Jumalah anak remaja yang terdapat pada rumah
customerMntWines
: Jumlah pengeluaran untuk produk wine dalam 6
bulan terakhirMntFruits
: Jumlah pengeluaran untuk produk buah-buahan
dalam 6 bulan terakhirMntMeatProducts
: Jumlah pengeluaran untuk product
daging merah dalam 6 bulan terakhirMntFishProducts
: Jumlah pengeluaran untuk product ikan
dalam 6 bulan terakhirNumDealsPurchases
: Jumlah transaksi yang dilakukan
customer ketika terdapat diskon yang ditawarkanNumWebPurchases
: Jumlah transaksi yang dilakukan
customer melalui websiteNumAppPurchases
: Jumlah transaksi yang dilakukan
customer melalui applikasiNumStorePurchases
: Jumlah transaksi yang dilakukan
customer secara offline atau data ke storeCountry
: Kebangsaan customer tersebutRole Play Bisnis Question
Kita selaku tim Data dari Supermarket, diminta tolong oleh tim marketing untuk membuat segmentasi customer dari keseluruhan customer yang terdaftar karena tim marketing merasa khawatir jika promo dibuat secara general atau sama rata antar setiap customer, promo tersebut menjadi sia-sia. Harapan dari tim marketing dengan adanya segmentasi kustomer, promo yang dipersipkan akan membantu meningkatkan penjualan dan awareness customer terhadap product ataupun plaform penjualan yang sudah tersedia.
Wrangling 1: Apakah kolom income perlu kita hilangkan simbol dolarnya, agar dapat kita olang sebagai tipe data numeric?
Jika kita harus mengubahnya maka kita coba manfaatkan fungsi
str_replace_all()
# Please run the code down below
cust_purchase$Income <- cust_purchase$Income %>%
str_replace_all(pattern = "\\$",
replacement = "") %>%
str_replace_all(pattern = ",",
replacement = "")
cust_purchase %>%
head()
Wrangling 2: Apakah kita perlu membuat kolom baru yang berisikan umur customer, agar lebih intuitif?
# Please run the code down below
cust_purchase <- cust_purchase %>%
mutate(age = 2022 - Year_Birth)
cust_purchase %>%
head()
Wrangling 3: Apakah kolom ID
dan Year_Birth
perlu kita buang?
ID
: ID perlu dibuang karena nantinya dapat mempengaruhi
perhitungan dan pembuatan kelompok yang adaYear_Birth
: Karena kita sudah memiliki kolom baru yaitu
age
yang lebih intuitif, maka kita bisa menghilangkan kolom
Year_Birth
agar tidak ada informasi yang berulang.Wrangling 4: Apakah terdapat kolom yang belum sesuai tipe datanya?
cust_purchase %>%
glimpse()
#> Rows: 1,000
#> Columns: 19
#> $ ID <int> 1826, 1, 10476, 1386, 5371, 7348, 4073, 1991, 4047, …
#> $ Year_Birth <int> 1970, 1961, 1958, 1967, 1989, 1958, 1954, 1967, 1954…
#> $ Education <chr> "Graduation", "Graduation", "Graduation", "Graduatio…
#> $ Marital_Status <chr> "Widow", "Single", "Married", "Married", "Single", "…
#> $ Income <chr> "84835.00 ", "57091.00 ", "67267.00 ", "32474.00 ", …
#> $ Kidhome <int> 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0…
#> $ Teenhome <int> 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1…
#> $ MntWines <int> 189, 464, 134, 10, 6, 336, 769, 78, 384, 384, 450, 1…
#> $ MntFruits <int> 104, 5, 11, 0, 16, 130, 80, 0, 0, 0, 26, 4, 82, 10, …
#> $ MntMeatProducts <int> 379, 64, 59, 1, 24, 411, 252, 11, 102, 102, 535, 61,…
#> $ MntFishProducts <int> 111, 7, 15, 0, 11, 240, 15, 0, 21, 21, 73, 0, 80, 3,…
#> $ MntSweetProducts <int> 189, 0, 2, 0, 0, 32, 34, 0, 32, 32, 98, 13, 20, 16, …
#> $ MntGoldProds <int> 218, 37, 30, 0, 34, 43, 65, 7, 5, 5, 26, 4, 102, 32,…
#> $ NumDealsPurchases <int> 1, 1, 1, 1, 2, 1, 1, 1, 3, 3, 1, 2, 1, 1, 0, 4, 4, 1…
#> $ NumWebPurchases <int> 4, 7, 3, 1, 3, 4, 10, 2, 6, 6, 5, 3, 3, 1, 25, 2, 2,…
#> $ NumAppPurchases <int> 4, 3, 2, 0, 1, 7, 10, 1, 2, 2, 6, 1, 6, 1, 0, 1, 1, …
#> $ NumStorePurchases <int> 6, 7, 5, 2, 2, 5, 7, 3, 9, 9, 10, 6, 6, 2, 0, 5, 5, …
#> $ Country <chr> "SP", "CA", "US", "AUS", "SP", "SP", "GER", "SP", "U…
#> $ age <dbl> 52, 61, 64, 55, 33, 64, 68, 55, 68, 68, 75, 43, 63, …
Marital_Status
-> FactorCountry
-> FactorEducation
-> FactorIncome
-> Integer# Please run the code down below
cust_purchase_clean <- cust_purchase %>%
select(-ID, -Year_Birth) %>%
mutate(Marital_Status = as.factor(Marital_Status),
Country = as.factor(Country),
Education = as.factor(Education),
Income = as.integer(Income))
glimpse(cust_purchase_clean)
#> Rows: 1,000
#> Columns: 17
#> $ Education <fct> Graduation, Graduation, Graduation, Graduation, Grad…
#> $ Marital_Status <fct> Widow, Single, Married, Married, Single, Single, Mar…
#> $ Income <int> 84835, 57091, 67267, 32474, 21474, 71691, 63564, 449…
#> $ Kidhome <int> 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0…
#> $ Teenhome <int> 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1…
#> $ MntWines <int> 189, 464, 134, 10, 6, 336, 769, 78, 384, 384, 450, 1…
#> $ MntFruits <int> 104, 5, 11, 0, 16, 130, 80, 0, 0, 0, 26, 4, 82, 10, …
#> $ MntMeatProducts <int> 379, 64, 59, 1, 24, 411, 252, 11, 102, 102, 535, 61,…
#> $ MntFishProducts <int> 111, 7, 15, 0, 11, 240, 15, 0, 21, 21, 73, 0, 80, 3,…
#> $ MntSweetProducts <int> 189, 0, 2, 0, 0, 32, 34, 0, 32, 32, 98, 13, 20, 16, …
#> $ MntGoldProds <int> 218, 37, 30, 0, 34, 43, 65, 7, 5, 5, 26, 4, 102, 32,…
#> $ NumDealsPurchases <int> 1, 1, 1, 1, 2, 1, 1, 1, 3, 3, 1, 2, 1, 1, 0, 4, 4, 1…
#> $ NumWebPurchases <int> 4, 7, 3, 1, 3, 4, 10, 2, 6, 6, 5, 3, 3, 1, 25, 2, 2,…
#> $ NumAppPurchases <int> 4, 3, 2, 0, 1, 7, 10, 1, 2, 2, 6, 1, 6, 1, 0, 1, 1, …
#> $ NumStorePurchases <int> 6, 7, 5, 2, 2, 5, 7, 3, 9, 9, 10, 6, 6, 2, 0, 5, 5, …
#> $ Country <fct> SP, CA, US, AUS, SP, SP, GER, SP, US, IND, US, SP, I…
#> $ age <dbl> 52, 61, 64, 55, 33, 64, 68, 55, 68, 68, 75, 43, 63, …
Pada tahapan eksplorasi data, kita akan mencoba untuk lebih mengenali data yang kita miliki.
EDA 1: Melihat apakah ada missing value
# Please run the code down below
cust_purchase_clean %>%
anyNA()
#> [1] FALSE
cust_purchase_clean %>%
is.na() %>%
colSums()
#> Education Marital_Status Income Kidhome
#> 0 0 0 0
#> Teenhome MntWines MntFruits MntMeatProducts
#> 0 0 0 0
#> MntFishProducts MntSweetProducts MntGoldProds NumDealsPurchases
#> 0 0 0 0
#> NumWebPurchases NumAppPurchases NumStorePurchases Country
#> 0 0 0 0
#> age
#> 0
EDA 2: Melakukan 5 number summary
# Please run the code down below
cust_purchase_clean %>%
summary()
#> Education Marital_Status Income Kidhome
#> Graduation :488 Married:647 Min. : 2447 Min. :0.000
#> Master :168 Single :214 1st Qu.: 34476 1st Qu.:0.000
#> PhD :219 Widow :139 Median : 50442 Median :0.000
#> Undergraduate:125 Mean : 52405 Mean :0.439
#> 3rd Qu.: 69109 3rd Qu.:1.000
#> Max. :666666 Max. :2.000
#>
#> Teenhome MntWines MntFruits MntMeatProducts
#> Min. :0.000 Min. : 0.0 Min. : 0.00 Min. : 0.0
#> 1st Qu.:0.000 1st Qu.: 22.0 1st Qu.: 1.00 1st Qu.: 14.0
#> Median :0.000 Median : 167.0 Median : 7.00 Median : 64.0
#> Mean :0.489 Mean : 296.5 Mean : 26.78 Mean : 165.2
#> 3rd Qu.:1.000 3rd Qu.: 488.0 3rd Qu.: 32.00 3rd Qu.: 223.0
#> Max. :2.000 Max. :1478.0 Max. :199.00 Max. :1725.0
#>
#> MntFishProducts MntSweetProducts MntGoldProds NumDealsPurchases
#> Min. : 0.00 Min. : 0.00 Min. : 0.00 Min. : 0.000
#> 1st Qu.: 2.75 1st Qu.: 1.00 1st Qu.: 9.00 1st Qu.: 1.000
#> Median : 12.00 Median : 8.00 Median : 23.00 Median : 2.000
#> Mean : 37.37 Mean : 25.49 Mean : 43.00 Mean : 2.287
#> 3rd Qu.: 49.25 3rd Qu.: 29.25 3rd Qu.: 51.25 3rd Qu.: 3.000
#> Max. :259.00 Max. :262.00 Max. :321.00 Max. :15.000
#>
#> NumWebPurchases NumAppPurchases NumStorePurchases Country
#> Min. : 0.000 Min. : 0.000 Min. : 0.000 SP :479
#> 1st Qu.: 2.000 1st Qu.: 0.000 1st Qu.: 3.000 SA :145
#> Median : 3.000 Median : 1.000 Median : 5.000 CA :131
#> Mean : 4.092 Mean : 2.592 Mean : 5.791 AUS : 78
#> 3rd Qu.: 6.000 3rd Qu.: 4.000 3rd Qu.: 8.000 IND : 63
#> Max. :27.000 Max. :28.000 Max. :13.000 US : 52
#> (Other): 52
#> age
#> Min. : 26.00
#> 1st Qu.: 44.00
#> Median : 51.00
#> Mean : 52.65
#> 3rd Qu.: 62.00
#> Max. :129.00
#>
Insight:
Year_Birth
. Kita akan mencoba untuk menganalisa lebih
medalam lagi pada bagian ini.Further EDA:
boxplot_age <- boxplot(cust_purchase_clean$age)
boxplot_age$out
#> [1] 129 123
Dari hasil boxplot, kita dapat melihat bahwa terdapat 2 outlier pada data customer kita. Dikarenakan 2 umur tersebut dianggap sebagai outlier dan dirasa kurang bijak jika kita memanipulasi ketiga data tersebut, salah satu approach yang dapat kita lakukan adalah menghilangkan ketiga data tersebut. Sehinga ketiga data tersebut tidak menjadi noise pada pembuatan cluster nantinya.
boxplot_income <- boxplot(cust_purchase_clean$Income)
boxplot_income$out
#> [1] 157146 160803 666666 162397 157733
Kita akan melihat karakteristik dari customer yang memiliki income sebesar 666,666 USD
cust_purchase_clean %>%
filter(Income == 666666)
Furthen Data Wrangling:
cust_purchase_cleaner <- cust_purchase_clean %>%
filter(Income < 666666, age < 122)
Dari hasil analisa outliers kita dapat melihat bahwa ada sebuah customers yang memiliki gaji yang sangat tinggi, bahkan diantara data outliers customer tersebut memiliki nilai income yang lebih dari 500rb USD. Pada data customer tersebut, kita juga akan menghilangkan data tersebut, karena bisa menjadi noise ketika kita ingin melakukan clustering.
Sebagai tambahan untuk data dengan tipe numerik kita bisa melakukan
visualiasi dengan plot histogram untuk melihat jumlah observasinya.
Untuk melelihatnya dengan visualisasi histogram, kita tidak perlu
membuatnya satu per satu, melainkan kita bisa menggunakan fungsi
hist.data.frame()
dari library(Hmisc)
.
# Please run the code down below
cust_purchase_cleaner %>%
select_if(is.numeric) %>%
hist.data.frame()
cust_purchase_cleaner %>%
select_if(is.factor) %>%
hist.data.frame()
Additional Insight:
Algoritma Partitioning Around Medoids(PAM) atau bisa disebut K-Medoids adalah sebuah metode pengelompokan non-hierarki yang masih menjadi keluarga dekat dari metode K-Means. Metode PAM atau K-Medoids ini akan mengelompokan sekumpulan n objek menjadi ke beberapa k cluster. Jika metode pengelompokannya seperti itu, apa bedanya dengan metode K-Means kalau begitu? Perbedaanya terdapat pada bagaimana melakukan pengelompokannya.
Pada metode K-Means, penentuan sebuah objek masuk ke sebuah cluster tertentu berdasarkan perhitungan rata-rata jarak ecluidean. Sedangkan cara kerja metode K-Medoids akan diawali dengan penentuan Medoids (sebuah objek yang letaknya terpusat di dalam suatu cluster). Dari gambar di bawah, kita dapat melihat bagaimana perbedaan antara metode K-Means & K-Medoids dalam menentukan sebuah objek lebih sesuai untuk masuk ke sebuah cluster tertentu.
knitr::include_graphics("assets/K-Medoids_Clustering.gif")
Penentuan Medoids itu tidak dilakukan hanya sekali, melainkan berulang sampai Medoids itu tidak bisa bergerak lagi. Mengapa tidak hanya sekali, dikarenakan peletakan Medoids belum tentu posisi paling optimal. Untuk mendapatkan posisi yang paling optimal nantinya posisi Medoids awal akan dihitung ulang total simpangannya dengan menggunakan rumus berikut di bawah ini.
\[ S = b - a \] Dimana:
a
adalah cost jarak terdekat antara objek ke
medoid awalb
adalah cost jarak terdekat antara objek ke
medoid baruJika S < 0, maka tukar obyek dengan data untuk membentuk sekumpulan k baru sebagai Medoid
Langkah tersebut akan terus diulang sampai nantinya S > 0, yang berarti tidak adanya pergerakan lagi dari Medoid yang dipilih sebagai titik tengah. Dari titik Medoids yang paling optimum itu, akan dicari lagi objek yang menyerupai dari karakteristik Medoids tersebut. Supaya lebih terbayang dengan cara kerja dari metode PAM, kita bisa melihat contoh penentuan manual di bawah ini
Contoh penentuan dan perhitungan:
Supaya lebih terbayang bagaimana hasil dari metode PAM menentukan medoidsnya, mari kita coba lakukan perhitungan secara manual terlebih dahulu untuk 2 kelompok
df <- data.frame(row = c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L),
X = c(8L, 3L, 4L, 9L, 8L, 5L, 7L, 8L, 7L, 4L),
Y = c(7L, 7L, 9L, 6L, 5L, 8L, 3L, 4L, 5L, 5L))
df
Step 1: Menentukan medoids secara random
Karena ada 2 kelompok yang akan dibuat, maka akan ada 2 random medoids
Step 2: Menghitung jarak antara setiap observasi data terhadap titik medoidsnya
\[ Jarak = |Xi - Xm| + |Yi - Ym| \]
Dimana:
Xi
, Yi
: Titik observasi data untuk titik X
& YXm
, Ym
: Titik medoids yang ditentukan
untuk titik X & Y\[ JarakMedoids1= |8-4| + |7-5|\\ JarakMedoids1= 4 + 2\\ JarakMedoids1= 6 \]
df <- data.frame(row = c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L),
X = c(8L, 3L, 4L, 9L, 8L, 5L, 7L, 8L, 7L, 4L),
Y = c(7L, 7L, 9L, 6L, 5L, 8L, 3L, 4L, 5L, 5L),
Jarak_Medoids_K1 = c(6L, 3L, 4L, 6L, NA, 4L, 5L, 5L, 3L, NA),
Jarak_Medoids_K2 = c(2L, 7L, 8L, 2L, NA, 6L, 3L, 1L, 1L, NA))
df
Step 2.1: Menentukan observasi data masuk ke kelompok berapa
Setelah mendapatkan perhitungan jarak, setiap observasi data akan
dimasukan ke sebuah kelompok berdasarkan jarak yang paling dekat.
Penentuan jarak yang paling dekat, berdasarkan nilai perbandingan dari
kolom Jarak_Medoids_K1
dengan
Jarak_Medoids_K2
.
Dari penentuan setiap observasi data masuk ke kelompok berapa, kita dapat menghitung nilai costnya
\[ Cost Awal: Kelompok 1 + Kelompok 2\\ Cost Awal: (3 + 4 + 4) + (3 + 1 + 1 + 2 + 2)\\ Cost Awal: 20 \]
Step 3: Memilih random medoids kembali
Setelah mendapatkan hasil perhitungan jarak dengan medoids pertama, akan ditentukan medoids lainnya secara random untuk menjadi pembanding.
df <- data.frame(row = c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L),
X = c(8L, 3L, 4L, 9L, 8L, 5L, 7L, 8L, 7L, 4L),
Y = c(7L, 7L, 9L, 6L, 5L, 8L, 3L, 4L, 5L, 5L),
Jarak_Medoids_K1 = c(6L, 3L, 4L, 6L, 4L, 4L, 5L, NA, 3L, NA),
Jarak_Medoids_K2 = c(3L, 8L, 9L, 3L, 1L, 7L, 2L, NA, 2L, NA))
df
\[ Cost Baru: (3 + 4 + 4) + (2 + 2 + 1 + 3 + 3)\\ Cost Baru: 22 \]
Step 4: Bandingkan hasil cost antara medoids yang sudah ditentukan
Pada tahapan ini kita sudah memiliki 2 hasil perhitungan, untuk medoids yang pertama kali ditentukan dan medoids yang kedua.
\[ S = Cost Baru - Cost Lama\\ S = 22 - 20\\ S = 2 \]
Berdasarkan asumsi yang ada, jika S>0. Maka tidak ada perubahan medoids.
Setelah berkenalan dengan data yang kita gunakan, mari kita coba implementasikan metode PAM untuk membuat segmentasi kustomer. Secara garis besar akan ada 3 langkah yang nantinya akan dilakukan, yaitu:
Dari hasil eksplorasi data, kita mengetahui bahwa total observasi data kita adalah lebih dari 2.000 baris dan setiap observasi data pastinya memiliki nilai yang berbeda. Agar nantinya hasil dari setiap kelompok terdiri dari data-data yang identik, kita harus mengetahui jarak antara satu observasi dengan observasi lainnya berdekatan atau tidak
Pilihan paling populer untuk menghitung jarak adalah Euclidean, namun metode tersebut hanya berlaku untuk data numerik saja, oleh karena itu metode Euclidean tidak berlaku di sini.
Rumus Euclidean:
\[ Euclidean Distance = {\sqrt{(p - q)^2}} \]
Dimana:
p
: titik observasi 1q
: titik obervasi 2Ada satu metode yang dapat kita gunakan untuk kasus yang memiliki data campuran (data numerik dan data kategorikal), metode tersebut dinamakan Gower Distance.
Metode Gower Distance nantinya akan melakukan perbandingan pada setiap observasi data yang ada terhadap data-data yang lainnya, dengan cara melakukan perhitungan skala antara kedua observasi yang dibandingkan dengan rentan 0 sampai 1.
Rumus Gower Distance:
\[ Gower Distance = \frac{1}{p}\sum\limits^p_{i=1}(Xnumeric, Xcateogrical) \]
Dimana:
p
= jumlah kolomXnumeric
: kondisi ketika kolom yang dibandingkan adalah
numeric\[
Xnumeric = \frac{|X_i - {Xj}|}{r}
\] * Xi
= Data observasi 1 * Xj
= Data
observasi 2 * r
= Range dari kolom observasi tersebut
Xcategorical
: Nilai yang akan diberikan ketika kolom
yang dibandingkan adalah categorical
Contoh perhitungan:
Supaya lebih terbayang bagaimana hasil dari metode Gower Distance, mari kita coba lakukan perhitungan secara manual terlebih dahulu:
df2 <- data.frame(Age = c(22L, 33L, 52L, 46L),
Gender = c("M", "M", "F", "M") %>% as.factor(),
IQ = c(111L, 96L, 102L, 100L),
Politics = c("Liberal", "Moderate", "Liberal", "Moderate") %>% as.factor())
df2
Menghitung nilai range, untuk kolom numerik
\[ Range Age: 52 - 22 = 30\\ Range IQ: 111 - 96 = 15 \]
Perhitungan jarak untuk observasi 1 dan 2:
df[1:2,]
\[ Gower Distance: \frac{Age + Gender + IQ + Politics}{JumlahKolom}\\ \]
\[ Gower Distance: \frac{\frac{|22 - 30|}{30} + 0 + \frac{|111 - 96|}{15} + 1}4\\ Gower Distance: \frac{0.267 + 0 + 1 + 1}4\\ Gower Distance:0.567 \]
Setelah lebih memahami dari perhitungan manual, mari kita coba implementasikan ke data kita. Di R, metode Gower Distance tersimpan pada library(cluster) dan fungsi yang bisa digunakan adalah daisy(). Pada fungsi tersebut nantinya akan ada 2 parameter yang bisa diisi, yaitu:
x
: Data frame yang ingin digunakanmetric
: Metode apa yang ingin digunakan, karena kita
akan menggunakan metode Gower Distance, kita bisa isi dengan
“gower”.# Please type your code
cust_purchase_gd <- daisy(x = cust_purchase_cleaner,
metric = "gower")
summary(cust_purchase_gd)
#> 496506 dissimilarities, summarized :
#> Min. 1st Qu. Median Mean 3rd Qu. Max.
#> 0.0000 0.2060 0.2644 0.2648 0.3233 0.6515
#> Metric : mixed ; Types = N, N, I, I, I, I, I, I, I, I, I, I, I, I, I, N, I
#> Number of objects : 997
Sebagai pembuktian apakah metode Gower Distance memang bisa menempatkan data-data kita berdasarkan kemiripannya, kita bisa mencetak pasangan yang paling mirip dan berbeda dalam data kita dengan menggunakan fungsi di bawah ini.
# Please run the code down below
example <- as.matrix(cust_purchase_gd)
cust_purchase[which(example == min(example[example != min(example)]),
arr.ind = TRUE)[1, ], ]
# Please run the code down below
cust_purchase[which(example == max(example[example != max(example)]),
arr.ind = TRUE)[1, ], ]
Seperti yang sudah disampaikan pada bagian pendahuluan, tujuan dari melakukan clustering adalah menempatkan setiap observasi data yang ada ke beberapa kelompok yang sesuai dengan karakteristiknya atau bedasarkan kedekatan jarak antar setiap observasi. Pada langkah pertama kita sudah memiliki informasi jarak antar setiap observasi, kita akan memanfaatkan informasi tersebut untuk menentukan berapakah kelompok yang paling optimal. Hasil dari jumlah kelompok nantinya akan digunakan untuk menentukan berapa banyak segmentasi kustomer yang bisa dibuat berdasarkan data historis pembelian kustomer.
Dalam menentukan jumlah kelompok yang paling optimum, kita data
memanfaatkan metode Elbow Method. Metode tersebut dapat kita
gunakan dengan fungsi fviz_nbclust()
dari
library(factoextra)
. Pada fungsi tersebut nantinya akan ada
3 parameter yang bisa diisi, yaitu:
Dengan metode pertama ini kita akan memvariasikan jumlah kelompok dengan menghitung Within Cluster Sum of Square (WSS). WSS adalah akan menghasilkan jumlah kuadrat jarak antara setiap observasi terhadap titik Medoids untuk setiap kemungkinan jumlah kelompok.
\[ WCSS = \sum\limits^N_{i=1}d(X_i - Xc)^2 \]
Dimana:
N
= clusterXi
= Data observationXc
= Titik medoidsd(Xi - Xc)
: Jarak antara setiap observasi data terhadap
titik medoidsFungsi fviz_nbclust()
secara otomatis akan menghitung
WSS sampai dengan 10 kelompok (jumlah kelompok yang ingin dicoba hitung
bisa diatur secara manual sesuai dengan kebutuhan).
Dengan bertambahnya jumlah kelompok, nilai WCSS akan mulai berkurang (nilai WCSS terbesar ketika K = 1). Ketika kita menganalisis grafik kita dapat melihat bahwa grafik akan berubah dengan cepat pada suatu titik dan dengan demikian menciptakan bentuk siku. Dari titik ini, grafik mulai bergerak hampir sejajar dengan sumbu X. Nilai K yang sesuai dengan titik ini adalah nilai K optimal atau jumlah kelompok yang optimal.
Additional: Sampling Data
Fungsi sample()
digunakan untuk mengambil beberapa baris
secara acak pada data. Biasanya digunakan pada proses machine
learning.
# contoh sampling sederhana menggunakan vector
student <- c("A", "B", "C", "D")
sample(student, 3)
#> [1] "D" "C" "A"
Fungsi set.seed()
digunakan untuk mengunci random number
generator sehingga hasil sampling tidak berubah setiap kali run code.
Nilai seed yang digunakan bebas, maksimal 10 digit.
# Please run the code down below
set.seed(100)
sample(student, 3)
#> [1] "B" "C" "D"
Penentual Nilai K
# Please type your code
set.seed(123)
elbow_method <- fviz_nbclust(x = as.matrix(cust_purchase_gd),
FUNcluster = pam,
method = "wss",
k.max = 5) +
labs(subtitle = "Elbow Method")
Selain menggunakan metode Elbow, terdapat dua metode lagi yang dapat kita manfaatkan yaitu Metode Silhouette & Gap Statistic.
Metode kedua yang akan dicoba untuk menentukan jumlah kelompok yang optimal adalah Silhouette Method. Metode ini akan menghitung seberapa mirip sebuah observasi dengan kelompoknya sendiri jika dibandingkan dengan nilai kelompok lainnya.
Hasil dari perhitungannya akan memiliki rentan koefisien dari -1 sampai 1. Jika nanti hasilnya makin mendekati 1 maka observasi tersebut cocok dengan kelompoknya dan kurang cocok dengan kelompok tetangga, begitu juga sebaliknya, jika hasilnya makin mendekati -1 maka observasi tersebut tidak cocok dengan kelompoknya akan tetapi lebih cocok dengan kelompok tetangganya.
Berbeda dengan elbow method, makin bertambahnya jumlah kelompok, nilai hasil perhitungan metode silhouette method tidak pasti akan berkurang. Penentuan nilai kelompok yang optimal akan ditentukan berdasarkan nilai koefisien paling tinggi pada saat membagi keseluruhan observasi ke berapa banyak kelompok.
# PLEASE DO NOT RUN THE CODE
# set.seed(123)
#
# fviz_nbclust(x = as.matrix(cust_purchase_gd),
# FUNcluster = pam,
# method = "silhouette",
# k.max = 5) +
# labs(subtitle = "Silhouette Method")
knitr::include_graphics("assets/sm_result.PNG")
Metode terakhir yang akan digunakan adalah Gap Statistic Method, metode ini akan menghitung seberapa berbeda total variansi antara setiap observasi pada sebuah kelompok terhadap observasi yang terdapat pada kelompok lainnya.
# PLEASE DO NOT RUN THE CODE
# set.seed(123)
#
# fviz_nbclust(x = as.matrix(cust_purchase_gd),
# FUNcluster = pam,
# method = "gap_stat",
# k.max = 5,) +
# labs(subtitle = "Gap Statistic Method")
knitr::include_graphics("assets/gs_result.PNG")
2 dari 3 metode menunjukan bahwa K=3 adahlah nilai yang optimum, kita dapat memanfaatkan K=3 untuk mengsegmentasi kustomer kita.
Dislaimer: Penentuan jumlah kelompok tidak wajib menggunakan 3 metode pengujian di atas, penentuan kelompok juga dapat ditentukan berdasarkan pertanyaan bisnis atau kesepakatan bersama.
Sekarang kita bisa memulai tahapan terakhir yaitu mengelompokan semua
data customer ke kelompok yang sudah ditentukan dengan menggunakan
fungsi pam()
. Pada fungsi tersebut nantinya akan ada 2
parameter yang bisa diisi, yaitu:
x
= Data frame yang ingin digunakank
= Jumlah kelompok# Please type your code
pam_fit <- pam(x = cust_purchase_gd,
k = 3)
Fungsi di atas akan membantu kita untuk mengelompokan keseluruhan observasi data ke beberapa kelompok berdasarkan kemiripan setiap observasi terhadap titik pusat atau medoids. Supaya kita bisa mendapatkan intuisi awal bagaimana karakteristik customer untuk setiap kelompoknya, kita bisa melihat dari tabel di bawah ini.
# Please type your code
cust_purchase_cleaner[pam_fit$medoids, ]
Seperti yang sudah disampaikan, dengan melihat tabel di atas kita hanya bisa mendapatkan intuisi awal bagaimana karakteristik dari masing-masing kelompok yang dibuat. Supaya kita dapat melakukan interpretasi lebih detail dan melihat apakah pengelompokan yang kita lakukan sudah dapat memisahkan setiap observasi data dengan baik, kita bisa memanfaatkan metode statistik deskriptif dan visualisasi.
Jika dengan menggunakan metode statistik deskriptif kita bisa memahami karakteristik dari masing-masing kelompok, metode visualisasi dapat membantu kita untuk menilai bagaimana hasil pengelompokan. Metode visualisasi yang akan digunakan adalah metode t-SNE, metode ini merupakan salah satu cara untuk memvisualisasikan data yang tidak hanya memiliki nilai numerik saja melainkan nilai kategorikal juga.
# Please type your code
set.seed(123)
tsne_obj <- Rtsne(X = cust_purchase_gd,
is_distance = TRUE)
tsne_data <- tsne_obj$Y %>%
data.frame() %>%
setNames(c("X", "Y")) %>%
mutate(cluster = factor(pam_fit$clustering))
ggplot(aes(x = X, y = Y), data = tsne_data) +
geom_point(aes(color = cluster)) +
labs(title = "Visualisasi Clustering 2D") +
theme_bw() +
theme(plot.title = element_text(hjust = 0.5),
axis.title = element_blank())
Dari hasil plot di atas, kita bisa melihat bahwa setiap observasi sudah berhasil terbagi menjadi beberapa kelompok walaupun memang masih ada beberapa observasi yang tumpang tindih atau berdekatan pada sebuah kelompok yang didominasi oleh kelompok yang berlawanan.
Tujuan melakukan statistik deskriptif adalah untuk memahami karakteristik masing-masing kelompok, dan dalam kasus ini untuk mengetahui karakteristik untuk setiap segmentasi kustomer.
# Please type your code
pam_results <- cust_purchase_cleaner %>%
mutate(cluster = pam_fit$clustering) %>%
group_by(cluster) %>%
do(the_summary = summary(.))
pam_results$the_summary[[1]]
#> Education Marital_Status Income Kidhome
#> Graduation :186 Married:186 Min. : 27421 Min. :0.00000
#> Master : 42 Single : 60 1st Qu.: 65541 1st Qu.:0.00000
#> PhD : 25 Widow : 40 Median : 73309 Median :0.00000
#> Undergraduate: 33 Mean : 73011 Mean :0.05594
#> 3rd Qu.: 80526 3rd Qu.:0.00000
#> Max. :105471 Max. :2.00000
#>
#> Teenhome MntWines MntFruits MntMeatProducts
#> Min. :0.0000 Min. : 34.0 Min. : 0.0 Min. : 38.0
#> 1st Qu.:0.0000 1st Qu.: 298.2 1st Qu.: 26.0 1st Qu.:204.5
#> Median :0.0000 Median : 516.5 Median : 53.5 Median :365.5
#> Mean :0.2692 Mean : 550.3 Mean : 69.8 Mean :403.2
#> 3rd Qu.:1.0000 3rd Qu.: 769.8 3rd Qu.:107.0 3rd Qu.:557.2
#> Max. :2.0000 Max. :1302.0 Max. :199.0 Max. :981.0
#>
#> MntFishProducts MntSweetProducts MntGoldProds NumDealsPurchases
#> Min. : 0.00 Min. : 0.00 Min. : 0.0 Min. :0.000
#> 1st Qu.: 43.50 1st Qu.: 24.00 1st Qu.: 33.0 1st Qu.:1.000
#> Median : 87.50 Median : 47.50 Median : 56.0 Median :1.000
#> Mean : 98.96 Mean : 63.64 Mean : 77.8 Mean :1.563
#> 3rd Qu.:141.75 3rd Qu.: 97.75 3rd Qu.:110.5 3rd Qu.:2.000
#> Max. :259.00 Max. :198.00 Max. :248.0 Max. :7.000
#>
#> NumWebPurchases NumAppPurchases NumStorePurchases Country
#> Min. : 1.000 Min. : 1.000 Min. : 4.000 SP :130
#> 1st Qu.: 4.000 1st Qu.: 3.000 1st Qu.: 6.000 SA : 39
#> Median : 5.000 Median : 5.000 Median : 8.000 CA : 36
#> Mean : 5.524 Mean : 5.294 Mean : 8.566 IND : 22
#> 3rd Qu.: 7.000 3rd Qu.: 7.000 3rd Qu.:11.000 AUS : 20
#> Max. :11.000 Max. :11.000 Max. :13.000 GER : 19
#> (Other): 20
#> age cluster
#> Min. :27.00 Min. :1
#> 1st Qu.:43.00 1st Qu.:1
#> Median :52.00 Median :1
#> Mean :53.24 Mean :1
#> 3rd Qu.:63.00 3rd Qu.:1
#> Max. :78.00 Max. :1
#>
pam_results$the_summary[[2]]
#> Education Marital_Status Income Kidhome
#> Graduation : 55 Married:183 Min. : 4023 Min. :0.0000
#> Master : 52 Single : 53 1st Qu.: 46344 1st Qu.:0.0000
#> PhD :156 Widow : 49 Median : 54998 Median :0.0000
#> Undergraduate: 22 Mean : 56257 Mean :0.2421
#> 3rd Qu.: 65104 3rd Qu.:0.0000
#> Max. :162397 Max. :2.0000
#>
#> Teenhome MntWines MntFruits MntMeatProducts
#> Min. :0.0000 Min. : 5.0 Min. : 0.00 Min. : 1.0
#> 1st Qu.:1.0000 1st Qu.: 123.0 1st Qu.: 0.00 1st Qu.: 30.0
#> Median :1.0000 Median : 313.0 Median : 6.00 Median : 81.0
#> Mean :0.8912 Mean : 396.6 Mean : 14.49 Mean : 116.5
#> 3rd Qu.:1.0000 3rd Qu.: 580.0 3rd Qu.: 17.00 3rd Qu.: 145.0
#> Max. :2.0000 Max. :1478.0 Max. :162.00 Max. :1622.0
#>
#> MntFishProducts MntSweetProducts MntGoldProds NumDealsPurchases
#> Min. : 0.00 Min. : 0.00 Min. : 0.00 Min. : 0.000
#> 1st Qu.: 0.00 1st Qu.: 0.00 1st Qu.: 10.00 1st Qu.: 2.000
#> Median : 7.00 Median : 6.00 Median : 24.00 Median : 2.000
#> Mean : 19.24 Mean : 16.13 Mean : 41.48 Mean : 3.098
#> 3rd Qu.: 24.00 3rd Qu.: 19.00 3rd Qu.: 50.00 3rd Qu.: 4.000
#> Max. :168.00 Max. :262.00 Max. :205.00 Max. :15.000
#>
#> NumWebPurchases NumAppPurchases NumStorePurchases Country
#> Min. : 0.000 Min. : 0.000 Min. : 0.000 SP :136
#> 1st Qu.: 3.000 1st Qu.: 1.000 1st Qu.: 4.000 SA : 50
#> Median : 5.000 Median : 2.000 Median : 6.000 CA : 43
#> Mean : 5.172 Mean : 2.604 Mean : 6.667 AUS : 18
#> 3rd Qu.: 7.000 3rd Qu.: 4.000 3rd Qu.: 9.000 IND : 16
#> Max. :27.000 Max. :28.000 Max. :13.000 US : 13
#> (Other): 9
#> age cluster
#> Min. :31.00 Min. :2
#> 1st Qu.:51.00 1st Qu.:2
#> Median :59.00 Median :2
#> Mean :58.87 Mean :2
#> 3rd Qu.:67.00 3rd Qu.:2
#> Max. :78.00 Max. :2
#>
pam_results$the_summary[[3]]
#> Education Marital_Status Income Kidhome
#> Graduation :246 Married:276 Min. : 2447 Min. :0.0000
#> Master : 74 Single :100 1st Qu.: 25154 1st Qu.:1.0000
#> PhD : 37 Widow : 50 Median : 33316 Median :1.0000
#> Undergraduate: 69 Mean : 34461 Mean :0.8286
#> 3rd Qu.: 42012 3rd Qu.:1.0000
#> Max. :157733 Max. :2.0000
#>
#> Teenhome MntWines MntFruits MntMeatProducts
#> Min. :0.0000 Min. : 0.00 Min. : 0.000 Min. : 0.0
#> 1st Qu.:0.0000 1st Qu.: 7.00 1st Qu.: 1.000 1st Qu.: 7.0
#> Median :0.0000 Median : 19.00 Median : 3.000 Median : 14.5
#> Mean :0.3685 Mean : 59.55 Mean : 5.939 Mean : 37.9
#> 3rd Qu.:1.0000 3rd Qu.: 63.00 3rd Qu.: 7.000 3rd Qu.: 34.5
#> Max. :2.0000 Max. :1126.00 Max. :77.000 Max. :1725.0
#>
#> MntFishProducts MntSweetProducts MntGoldProds NumDealsPurchases
#> Min. : 0.000 Min. : 0.000 Min. : 0.00 Min. : 0.000
#> 1st Qu.: 2.000 1st Qu.: 1.000 1st Qu.: 5.00 1st Qu.: 1.000
#> Median : 4.000 Median : 3.000 Median : 11.00 Median : 2.000
#> Mean : 8.131 Mean : 6.169 Mean : 20.40 Mean : 2.232
#> 3rd Qu.:12.000 3rd Qu.: 8.000 3rd Qu.: 21.75 3rd Qu.: 3.000
#> Max. :73.000 Max. :126.000 Max. :321.00 Max. :15.000
#>
#> NumWebPurchases NumAppPurchases NumStorePurchases Country
#> Min. : 0.000 Min. : 0.0000 Min. : 0.000 SP :212
#> 1st Qu.: 1.000 1st Qu.: 0.0000 1st Qu.: 3.000 SA : 54
#> Median : 2.000 Median : 0.0000 Median : 3.000 CA : 52
#> Mean : 2.418 Mean : 0.7723 Mean : 3.362 AUS : 40
#> 3rd Qu.: 3.000 3rd Qu.: 1.0000 3rd Qu.: 4.000 IND : 25
#> Max. :25.000 Max. :28.0000 Max. :12.000 GER : 23
#> (Other): 20
#> age cluster
#> Min. :26.00 Min. :3
#> 1st Qu.:41.00 1st Qu.:3
#> Median :47.00 Median :3
#> Mean :47.77 Mean :3
#> 3rd Qu.:52.00 3rd Qu.:3
#> Max. :76.00 Max. :3
#>
Referensi