Project Detail

Projek ini merupakan implementasi dari proposal E-Commerce Optimization Strategies yang sebelumnya telah dibuat. Proposal tersebut berisi tentang latar belakang projek hingga tujuan maupun luaran dari projek ini. Adapun projek ini terbagi menjadi beberapa bagian, yakni:

  1. Data Preparation and Exploratory Analysis
  2. Customer Segmentation with RFM method
  3. Personalized Product Recommendation
  4. Demand Forecasting

Pada bagian ini, kita akan berfokus pada Customer Segmentation with RFM method. Alangkah baiknya pembaca untuk membaca secara berurutan dari proposal hingga bagian terakhir, sehingga dapat memahami dengan sempurna.

Theory of RFM Method

Metode Recency, Frequency, Monetary Value (RFM) merupakan salah sartu metode yang sering digunakan untuk segmentasi pelanggan. Metode ini menggunakan pendekatan kebiasaan/perilaku pelanggan dalam bertransaksi melalui riwayat belanja pelanggan. Nilai atau definisi dari parameter metode analisis RFM ini sebagai berikut;

  • Recency : Seberapa baru pelanggan melakukan transaksi
  • Frequency : Seberapa sering pelanggan melakukan transaksi
  • Monetary : Seberapa besar transaksi yang sudah dilakukan pelanggan

Melalui parameter metode RFM, kita dapat mengetahui karakteristik pelanggan, sehingga memudahkan pelaku usaha dalam memberikan perlakuan yang spesial sesuai karakter pelanggan. Pelanggaan akan dikelompokkan berdasarkan pada kemiripan sifat-sifatnya berdasarkan parameter RFM tersebut.

Terdapat beberapa Bussines Question yang bisa terjawab melalui analisis RFM ini, yakni:

  1. Siapakah kelompok pelanggan yang paling loyal
  2. Siapakah kelompok pelanggan yang berpotensi untuk ditingkatkan nilai loyalitasnya
  3. Siapakah kelompok pelanggan yang berpotensi menanggapi kampanye pemasaran dari perusahaan
  4. Siapakah kelompok pelanggan yang berisiko berhenti membeli produk/churn
  5. Siapakah kelompok pelanggan yang telah berhenti membeli produk/churn

Data Preparation

Proses persiapan data telah dilakukan pada Part 1 dari projek ini, sehingga kita dapat langsung menggunakannya. Dataset kita merupakan riwayat transaksi dari E-Commerce di pakistan pada periode Maret 2016 hingga Agustus 2018.

# Kustomisasi Tema Visualisasi
# Kustomisasi Warna dan Visualisasi chart
my_color <-  c(
  col1="#fcf800",
  col2="#fce700",
  col3="#fcdb03",
  col4="#e3c502",
  col5="#fcbe03",
  col6="#fc9d03",
  col7="#fc5d00"
)

my_theme_fill  <- get_scale_fill(get_pal(my_color))
my_theme_color <- get_scale_color(get_pal(my_color))
my_theme_hex <- get_hex(my_color)


color_dark_text = "#222629"

# MY PLOT THEME
my_plot_theme <- function (base_size, base_family="Segoe UI Semibold"){ 
  dark_color="#222629"
  facet_header = "#78767647"
  dark_text = "#222629"
  
  half_line <- base_size/2
  theme_algoritma <- theme(
    
    plot.background = element_rect(fill= "#faf6e3", colour = "#faf6e3"), #background plot
    plot.title = element_text(size = rel(1.5), margin = margin(b = half_line * 1.2), 
                              color= dark_text, hjust = 0, family=base_family, face = "bold"),
    plot.subtitle = element_text(size = rel(1.0), margin = margin(b = half_line * 1.2), color= dark_text, hjust=0),
    plot.margin=unit(c(0.5,0.5,0.5,0.5),"cm"),
    #plot.margin=unit(c(0.5,r=5,1,0.5),"cm"),
    
    panel.background = element_rect(fill="#18181800",colour = "#e8e8e8"), #background chart
    panel.border = element_rect(fill=NA,color = NA),
    panel.grid.minor.x = element_blank(),
    panel.grid.major.x = element_blank(),
    panel.grid.major.y = element_line(color="#e8e8e8", linetype=2),
    panel.grid.minor.y = element_blank(),
    #panel.margin = unit(0.8*half_line, "mm"), 
    panel.margin.x = NULL, 
    panel.margin.y = NULL, 
    panel.ontop = FALSE,
    panel.spacing = unit(1.2,"lines"),
    
    legend.background = element_rect(fill="#18181800",colour = NA),
    legend.text = element_text(size = rel(0.7),color=dark_text),
    legend.title =  element_text(colour = dark_text, size = base_size, lineheight = 0.8),
    legend.box = NULL, 
    
    # text = element_text(colour = "white", size = base_size, lineheight = 0.9, 
    #                    angle = 0, margin = margin(), debug = FALSE),
    axis.text = element_text(size = rel(0.8), color=dark_text),
    axis.text.x = element_text(colour = dark_text, size = base_size, margin = margin(t = 0.8 * half_line/2)),
    axis.text.y = element_text(colour = dark_text, size = base_size, margin = margin(r = 0.8 * half_line/2)),
    axis.title.x = element_text(colour = dark_text, size = base_size, lineheight = 0.8,
                                margin = margin(t = 0.8 * half_line, b = 0.8 * half_line/2)), 
    axis.title.y = element_text(colour = dark_text, size = base_size, lineheight = 0.8,
                                angle = 90, margin = margin(r = 0.8 * half_line, l = 0.8 * half_line/2)),
    axis.ticks = element_blank(),
    
    strip.background = element_rect(fill=facet_header,colour = NA),
    strip.text = element_text(colour = dark_text, size = rel(0.8)), 
    strip.text.x = element_text(margin = margin(t = half_line*0.8, b = half_line*0.8)), 
    strip.text.y = element_text(angle = -90, margin = margin(l = half_line, r = half_line)),
    strip.switch.pad.grid = unit(0.1, "cm"), 
    strip.switch.pad.wrap = unit(0.1, "cm"),
    complete = TRUE
    
  )
}

Deskiripsi kolom:

  • Order_Status : Status dari pembelian (Completed, Cancelled, Refund)

  • Date_of_Order : Tanggal pemesanan produk

  • SKU : Barcode, kode, atau nama unik yang mewakili produk tertentu

  • Price : Harga produk

  • Quantity : Jumlah dari produk yang dibeli

  • Grand_Total : Total pembayaran yang diberikan oleh pelanggan dalam satu Invoice

  • invoice_ID : Id dari invoice

  • Category : Kategori atau jenis E-Commerce

  • Discount_Amount : Nilai diskon yang didapatkan pelanggan pada tiap produk

  • Payment_Method : Metode pembayaran

  • BI.Status : Representasi kolom Order_Status

    • BI.Status = “Gross” ====> Order_Status = “canceled”
    • BI.Status = “Net” ====> Order_Status = “complete”
    • BI.Status = “Valid” ====> Order_Status = “refund”.
  • Revenue : hasil perkalian antara kolom Price dengan Quantity

  • Year : Tahun, nilai ini didapat dari Date_of_Order

  • Month : Bulan, nilai ini didapat dari Date_of_Order

  • Customer.Since : Umur pelanggan, didapat dari riwayat belanja pertama kali yang dilakukan oleh pelanggan

  • M.Y : Bulan-Tahun, nilai ini didapat dari Date_of_Order yang merupakan gabungan dari kolom Year dan Month

  • Customer_ID : ID dari pelanggan

RFM Analysis

Pada analisis RFM, kita harus melakukan Feature Engineering terlebih dahulu. Kita akan melakukan perhitungan nilai Recency, Frequency, dan Monetary dari setiap pelanggan. Nilai Recency dapat diketahui dengan menghitung jarak antara hari melakukan analisis dengan riwayat terakhir belanja setiap pelanggan. Kemudian, nilai Frequency dari pelanggan akan kita dapatkan dengan menghitung jumlah transaksi yang telah dilakukan oleh pelanggan. Selanjutnya, nilai Monetary didapatkan dengan menjumlahkan semua uang yang telah dibayarkan oleh pelanggan.

Pada kesempatan ini, Feature Engineering akan dibantu dengan package rfm untuk mempermudah pekerjaan. Package ini telah menyediakan Feature Engineering untuk perhitungan tiap parameter RFM.

Deskripsi kolom:

  • customer_id: ID unik pelanggan
  • date_most_recent: Periode terakhir pelanggan melakukan transaksi
  • recency_days: nilai recency pelanggan
  • transaction_count: nilai frequency pelanggan
  • amount: nilai monetary pelanggan
  • recency_score: skor dari recency pelanggan
  • frequency_score: skor dari frequency pelanggan
  • monetary_score: skor dari monetary pelanggan
  • rfm_score: total skor dari nilai RFM pelanggan

Pada data frame diatas kita menemukan indeks skor dari parameter RFM pelanggan. Nilai skor tiap parameter pelanggan didapat dengan teknik quantile dengan ketentuan sebagai berikut:

Pada persebaran data frequency pelanggan, melalui nilai quantile dapat kita lihat bersama bahwa lebih dari 60% data memiliki nilai frequency adalah satu. Hal itu bermakna bahwa lebih dari 60% pelanggan hanya pernah melakukan sekali transaksi saja.

Kemudian, nilai RFM Score didapat dengan rumus sebagai berikut:

RFM Score = recency_score x 100 + frequency_score x 10 + monetary_score

Jika kita melihat ketentuan penetapan skor dari parameter rfm, dengan auto quantile, menunjukkan hasil yang kurang baik, karena persebaran data kita. Sehingga kita akan membuat batasan quantile tersendiri untuk parameter recency dan frequency. Adapun pada recency, kita akan menggunakan ketetapan quantile sebagai berikut:

  • recency <= 30 hari -> skor 5
  • 30 hari < recency <= 90 hari -> skor 4
  • 90 hari < recency <= 180 hari -> skor 3
  • 180 hari < recency <= 270 hari -> skor 2
  • recency > 270 hari -> skor 1

Selanjutnya, pada nilai frequency, kita akan membagi nilai tertinggi dengan 5 dan menetapkan ketepan skor frequency dengan tiap kelipatan hasil bagi lima dari nilai max frequency.

#> [1] 314

Okey, jadi ketetapan skor quantile dari frequency adalah sebagai berikut:

  • freq <= 314 -> skor 1
  • 314 < freq <= 628 -> skor 2
  • 628 < freq <= 942 -> skor 3
  • 942 < freq <= 1256 -> skor 4
  • freq > 1256 -> skor 5

baiklah, mari kita buat kembali dengan melakukan custom pada penetapan skor parameter frequency dan recency-nya.

Ingat!. Tujuan melakukan kustom adalah menyesuakan persebaran dari data kita agar nilai skor atau pengelompokan pelanggan pada tahap selanjutnya lebih merepresentasikan karakteristik sebenarnya.

Selanjutnya, mari kita lihat hubungan antara tiap parameter dari metode RFM.

Recency vs Frequency

Dari visualisasi hubungan antara nilai recency dengan frequency, kita lihat bersama bahwa antara dua parameter tersebut tidak terdapat hubungan yang kentara. Yah, hal tersebut dapat diterima karena nilai kebaharuan pelanggan melakukan transaksi memang tidak dapat merepsentasikan nilai tingkat frekuensi belanja pelanggan tersebut.

Recency vs Monetary

Selanjutnya, coba kita lihat pada hubungan nilai recency dengan monetary pelanggan. Mari kita buat dugaan bersama bahwa kedua nilai tersebut tidak memiliki hubungan.

Yups, benar sebagaimana yang kita duga bersama. Visualisasi hubungan antara nilai recency dengan monetary melalui scatter plot menunjukkan bahwa antara dua parameter tersebut juga tidak terdapat hubungan yang kentara. Memang benar, nilai yang merepresentasikan periode hari kapan terkahir kali belanja tidak dapat menunjukkan seberapa besar pelanggan telah membelanjakan uangnya di perusahaan tersebut.

Mari kita coba renungkan, jika kita sebagai pelanggan baru yang masih sekitar satu minggu melakukan belanja namun telah membelanjakan uang dalam jumlah yang signifikan atau ada pelanggan yang telah lama tidak melakukan belanja dan hanya melakukan belanja dalam jumlah kecil, Bagaimana kita dapat menemukan hubungan antara keduanya? Jelas secara rasional kita dapat menyimpulkan bahwa memang seharusnya tidak ada hubungan antara kedua parameter tersebut.

Frequency vs Monetary

Mari kita lanjutkan pada bagian parameter frequency dengan monetary. Jika kita renungkan, seharusnya terdapat hubungan antara keduanya. Semakin sering seseorang belanja maka semakin banyak juga uang yang telah dibelanjakan dalam suatu tempat belanja tersebut. Sekarang coba kita buktikan renungan kita bersama.

Yups, antara parameter frequency dengan monetary, terlihat hubungan positif yang cukup kentara. Akan tetapi kita dapat melihat bahwasannya terdapat beberapa outlier, yang nantinya jika kita lihat persebarannya pasti hasilnya ialah persebaran yang skewed. Persebaran yang skewed ini cukup dapat membuat bias pada hasil segmentasi pelanggan kedepannya. Sehingga, harus ada manipulasi data agar jarak atau simpangan antara data tidak terlalu jauh dan memberikan hasil segmentasi pelanggan yang baik.

Correlation RFM Value

Okey, untuk memperkuat pemahaman yang kita dapatkan dari scatter plot, mari kita tinjau nilai korelasi antar parameter RFM.

Sebagaimana hasil visualisasi scatter, nilai recency bisa dikatakan tidak berhubungan dengan parameter frequency maupun monetary. Sedangkan parameter frequency berhubungan positif dengan parameter monetary. Hasil ini memperkuat pemahaman kita dari analisis melalui visualisasi scatter plot sebelumnya.

Primary Insight

Ada pemahaman penting yang kita dapatkan melalui Scatter Plot dan Correlation RFM Value. Keputusan kita untuk membuat segmentasi berdasarkan recency secara terpisah, sebagaimana disebutkan pada proposal E-Commerce Optimization Strategies adalah keputusan yang tepat. Tidak adanya hubungan antara parameter recency dengan frequency maupun monetary adalah alasannya. Sedangkan, adanya hubungan parameter frequency dan monetary menjadi alasan yang baik untuk melakukan segmentasi pelanggan dengan kombinasi dua parameter tersebut secara bersamaan. Hasil segmentasi pelanggan yang bias hingga membuat segmen pelanggan tidak memiliki karakter yang terlihat jelas dapat terhindarkan.

Distribution of RFM Value

Penting bagi kita untuk mengetahui distribusi dari tiap parameter RFM. Tentu, tujuannya untuk menghindari hasil segmentasi yang tidak mampu membedakan segmen pelanggan dengan baik. Mari kita coba lihat bersama.

Pada parameter recency, data kita memiliki distribusi yang cukup baik, namun sangat berbeda dengan persebaran data untuk parameter frequency dan monetary. Data dari dua parameter tersebut sangat tersebar secara skewed positif. Kedepannya, kita perlu melakukan scalling pada data kita ketika melukakan segmentasi dengan algoritma k-means pada dua parameter tersebut.

Customer Segmentation

Pada segmentasi pelanggan, kita akan mencoba pengelompokan dengan menggunakan algoritma unsupevised learning k-means dan juga teknik quantile. Dengan memanfaatkan karakter pelanggan yang didapatkan dari metode RFM, kita akan mencoba membandingkan antara hasil segmentasi yang murni dengan metode quantile dengan hasil segmentasi dari kombinasi k-means dan metode quantile. Kita akan memanfaan nilai RFM score yang kita dapatkan untuk segmentasi pelanggan dengan metode quantile secara keseluruhan. Sedangkan, segmentasi kombinasi ialah algoritma k-means untuk parameter frequency dan monetary, dan teknik quantile untuk parameter recency.

Combination Segmentaion

1. Customer Value Segmentation (k-means)

Pada k-means kita akan mengelompokkan berdasarkan nilai customer dari frequency dan monetary. Hal ini dilakukan karena dua parameter ini meliki korelasi, harapannya, dapat memberikan hasil yang baik.

Ingat! kita perlu melakukan scalling pada data kita karena persebarannya yang sangat skewed sedangkan algoritma pengelompokkan dengan k-means sangat sensitif terhadap jarak.

Kita akan mencoba dua metode, yakni dengan teknik scale dan menggunakan nilai minimal serta maksimal data untuk melakukan scalling.

Walaupun telah dilakukan scalling, dapat kita lihat bersama bahwa persebaran datanya masih sangat terlalu buruk. Hal tersebut mungkin didasari oleh adanya nilai-nilai outlier yang tersebar sangat jauh dari dimana data berpusat. Kita dapat mencoba mendeteksi nilai-nilai outlier tersebut dan menjadikan segmen tersendiri. Adapun data sisanya akan kita lakukan scalling dan segmentasi dengan k-means.

Alhamdulillah. Setelah kita menyeleksi 92% dari data, persebaran data menjadi lebih baik.

Dari visualisasi histogram, kita tidak mendapatkan distibusi yang baik, karena memang data sebenarnya lebih tersebar ke skala yang kecil. Namun plot histogram diatas lebih baik daripada sebelum dilakukan penyeleksian.

Selanjutnya, kita akan mencoba menggunakan kedua teknik normalisasi data kita untuk melakukan segmentasi dan kita evaluasi karakter dari tiap segmen. Kemudian, kita akan memilih segmen yang mampu membedakan karakter pelanggan dengan baik.

Sebelumnya, kita akan melihat/mengevaluasi jumlah cluster paling maksimal dalam mengkarakterisasi tiap segmen pelanggan yang akan kita gunakan dengan menggunakan elbow method.

Dari dua teknik normalisasi data yang kita gunakan, keduanya memberikan nilai cluster maksimal diantara 3 dan 4.

#> [1] 48444  7790  3714
#> [1]  2796  5119  8657 43376
#> [1] 50153  2696  7099
#> [1]  1297  6508  5626 46517
#> [1] 89.9
#> [1] 94.2
#> [1] 69.1
#> [1] 77.8
k3_mm_profile <- k3_k4_mm_sc %>% group_by(k3_mm_segment) %>%
  summarise(
    min_recency = min(recency_days),
    max_recency = max(recency_days),
    avg_recency = round(mean(recency_days),2),
    min_frequency = min(transaction_count),
    max_frequency = max(transaction_count),
    avg_frequency = round(mean(transaction_count),2),
    med_frequency = round(median(transaction_count),2),
    min_monetary = min(amount),
    max_monetary = max(amount),
    avg_monetary = round(mean(amount),2),
    med_monetary = round(median(amount),2),
    total_monetary = sum(amount),
    total_customer = n()
  ) %>% ungroup()

k4_mm_profile <- k3_k4_mm_sc %>% group_by(k4_mm_segment) %>%
  summarise(
    min_recency = min(recency_days),
    max_recency = max(recency_days),
    avg_recency = round(mean(recency_days),2),
    min_frequency = min(transaction_count),
    max_frequency = max(transaction_count),
    avg_frequency = round(mean(transaction_count),2),
    med_frequency = round(median(transaction_count),2),
    min_monetary = min(amount),
    max_monetary = max(amount),
    avg_monetary = round(mean(amount),2),
    med_monetary = round(median(amount),2),
    total_monetary = sum(amount),
    total_customer = n()
  ) %>% ungroup()

k3_sc_profile <- k3_k4_mm_sc %>% group_by(k3_sc_segment) %>%
  summarise(
    min_recency = min(recency_days),
    max_recency = max(recency_days),
    avg_recency = round(mean(recency_days),2),
    min_frequency = min(transaction_count),
    max_frequency = max(transaction_count),
    avg_frequency = round(mean(transaction_count),2),
    med_frequency = round(median(transaction_count),2),
    min_monetary = min(amount),
    max_monetary = max(amount),
    avg_monetary = round(mean(amount),2),
    med_monetary = round(median(amount),2),
    total_monetary = sum(amount),
    total_customer = n()
  ) %>% ungroup()

k4_sc_profile <- k3_k4_mm_sc %>% group_by(k4_sc_segment) %>%
  summarise(
    min_recency = min(recency_days),
    max_recency = max(recency_days),
    avg_recency = round(mean(recency_days),2),
    min_frequency = min(transaction_count),
    max_frequency = max(transaction_count),
    avg_frequency = round(mean(transaction_count),2),
    med_frequency = round(median(transaction_count),2),
    min_monetary = min(amount),
    max_monetary = max(amount),
    avg_monetary = round(mean(amount),2),
    med_monetary = round(median(amount),2),
    total_monetary = sum(amount),
    total_customer = n()
  ) %>% ungroup()
k3_mm_perform <- round((kmeans_k3_mm$betweenss/kmeans_k3_mm$totss)*100,1)
k4_mm_perform <- round((kmeans_k4_mm$betweenss/kmeans_k4_mm$totss)*100,1)
k3_sc_perform <- round((kmeans_k3_sc$betweenss/kmeans_k3_sc$totss)*100,1)
k4_sc_perform <- round((kmeans_k4_sc$betweenss/kmeans_k4_sc$totss)*100,1)

plot_k3_mm_profile <- k3_mm_profile %>% 
  gather("features","values",max_frequency,min_frequency,avg_frequency,med_frequency,
         min_monetary,max_monetary,avg_monetary,med_monetary) %>% 
  ggplot(aes(x = k3_mm_segment, y = features)) +
  #scale_x_continuous(breaks = seq(min(cluster), max(cluster), by = 1)) +
  geom_tile(aes(fill = values), show.legend = FALSE) +
  geom_text(aes(label=round(values,2)), size=4, color="black")+
  coord_equal() +
  labs(
    title = "K-Means Clustering for 3 Segment",
    subtitle = paste("betweenss/totts:",k3_mm_perform,"% (normalized by min max value)"),
    x = "Cluster",
    y = NULL
  )+
  scale_fill_gradient(low=my_theme_hex("col3") ,na.value = "#C0C0C0", high=my_theme_hex("col6"))+
    theme(text = element_text(size=14, color = "black"),
          plot.title =element_text(size=16),
          legend.position = "bottom",
          axis.text.y = element_text(size=14),
          axis.title.x = element_text(size=14))

plot_k4_mm_profile <- k4_mm_profile %>% 
  gather("features","values",max_frequency,min_frequency,avg_frequency,med_frequency,
         min_monetary,max_monetary,avg_monetary,med_monetary) %>% 
  ggplot(aes(x = k4_mm_segment, y = features)) +
  #scale_x_continuous(breaks = seq(min(cluster), max(cluster), by = 1)) +
  geom_tile(aes(fill = values), show.legend = FALSE) +
  geom_text(aes(label=round(values,2)), size=4, color="black")+
  coord_equal() +
  labs(
    title = "K-Means Clustering for 4 Segment",
    subtitle = paste("betweenss/totts:",k4_mm_perform,"% (normalized by min max value)"),
    x = "Cluster",
    y = NULL
  )+
  scale_fill_gradient(low=my_theme_hex("col3") ,na.value = "#C0C0C0", high=my_theme_hex("col6"))+
    theme(text = element_text(size=14, color = "black"),
          plot.title =element_text(size=16),
          legend.position = "bottom",
          axis.text.y = element_text(size=14),
          axis.title.x = element_text(size=14))

plot_k3_sc_profile <- k3_sc_profile %>% 
  gather("features","values",max_frequency,min_frequency,avg_frequency,med_frequency,
         min_monetary,max_monetary,avg_monetary,med_monetary) %>% 
  ggplot(aes(x = k3_sc_segment, y = features)) +
  #scale_x_continuous(breaks = seq(min(cluster), max(cluster), by = 1)) +
  geom_tile(aes(fill = values), show.legend = FALSE) +
  geom_text(aes(label=round(values,2)), size=4, color="black")+
  coord_equal() +
  labs(
    title = "K-Means Clustering for 3 Segment",
    subtitle = paste("betweenss/totts:",k3_sc_perform,"% (normalized by scale method)"),
    x = "Cluster",
    y = NULL
  )+
  scale_fill_gradient(low=my_theme_hex("col3") ,na.value = "#C0C0C0", high=my_theme_hex("col6"))+
    theme(text = element_text(size=14, color = "black"),
          plot.title =element_text(size=16),
          legend.position = "bottom",
          axis.text.y = element_text(size=14),
          axis.title.x = element_text(size=14))

plot_k4_sc_profile <- k4_sc_profile %>% 
  gather("features","values",max_frequency,min_frequency,avg_frequency,med_frequency,
         min_monetary,max_monetary,avg_monetary,med_monetary) %>% 
  ggplot(aes(x = k4_sc_segment, y = features)) +
  #scale_x_continuous(breaks = seq(min(cluster), max(cluster), by = 1)) +
  geom_tile(aes(fill = values), show.legend = FALSE) +
  geom_text(aes(label=round(values,2)), size=4, color="black")+
  coord_equal() +
  labs(
    title = "K-Means Clustering for 4 Segment",
    subtitle = paste("betweenss/totts:",k4_sc_perform,"% (normalized by scale method)"),
    x = "Cluster",
    y = NULL
  )+
  scale_fill_gradient(low=my_theme_hex("col3") ,na.value = "#C0C0C0", high=my_theme_hex("col6"))+
    theme(text = element_text(size=14, color = "black"),
          plot.title =element_text(size=16),
          legend.position = "bottom",
          axis.text.y = element_text(size=14),
          axis.title.x = element_text(size=14))

Dapat kita lihat bersama bahwasanya teknik normalisasi dengan nilai minimal dan maksimal dari data mampu memberikan hasil segmentasi yang lebih baik daripada menggunakan teknik scale() method. Hasil segmentasi dengan nilai minimal maksimal mampu memberikan kelompok pelanggan dengan karakter yang sama dengan lebih baik. Adapun jumlah klaster 3 sudah mampu mengelompokkan pelanggan sesuai karakter sama dengan baik. Sehingga, kita akan menggunakan hasli klaster dari data yang ternormalisasi dengan teknik min max value dan banyak klaster yang digunakan ialah 3.

Selanjutnya, mari kita gabungkan 8% data yang kita eliminasi sebelumnya.

Kemudian, mari kita lihat profil karakter dari tiap klaster yang dihasilkan dan kemudian kita beri nama terhadap tiap klaster.

Berdasarkan profiling yang kita lakukan, kita dapat mengetahui bahwa secara umum hasil clustering yang kita lakukan lebih mengarah pada karakter monetary pelanggan. Adapun karakter frequency pelanggan tidak terlalu kentara. Adapun klaster 1 memiliki anggota sekitar 76% dari total pelanggan perusahaan e-commerce ini.

Baiklah, mari kita beri nama terhadap semua klaster yang kita dapatkan dari algoritma kmeans.

Cluster 1 : Very low Frequency - Very Low Monetary. Kita sebut segmen Low Value Customer.

Cluster 2 : Very low Frequency - Medium Monetary. Kita sebut segmen Medium Value Customer.

Cluster 3 : Low Frequency - High Monetary. Kita sebut segmen High Value Customer.

Cluster 4 : Medium Frequency - Very High Monetary. Kita sebut segmen Special Value Customer.

2. Recency Segmentation (Quantile) Pada segmentasi nilai recency, nilai yang menunjukkan jarak hari dari waktu terakhir belanja pelanggan dengan waktu dilakukan analisis, kita akan membaginya dengan teknik quantile. Periode data kita memiliki periode dua tahun, sehingga akan membaginya sebagai berikut:

  1. New Customer : Recency <= 30
  2. Active : 30 < Recency <= 90
  3. Warm : 90 < Recency <= 180
  4. Cold : 180 < Recency <= 270
  5. Inactive : Recency > 270
recency_segmentation <- df_cust_segment %>% 
  group_by(recency_days) %>% 
  summarise(freq=n()) %>% ungroup() %>% 
  mutate(popup=glue("Recency: {recency_days}
                    Total Customer: {freq}"))

plot_recency_segmentation <- ggplot(recency_segmentation,aes(recency_days, freq))+
            geom_area(fill = my_color[5])+
            geom_point(aes(text = popup), size=0.2, alpha=0.05)+
              geom_vline(xintercept = recency_adjust$new.customer,linetype="dotted",color = "black", size=1,alpha=0.2)+
  geom_vline(xintercept = recency_adjust$active,linetype="dotted",color = "black", size=1,alpha=0.2)+
            geom_vline(xintercept = recency_adjust$warm,linetype="dotted",color = "black", size=1,alpha=0.2)+
            geom_vline(xintercept = recency_adjust$cold,linetype="dotted",color = "black", size=1, alpha=0.2)+
            
            geom_point(aes(x=recency_adjust$new.customer, y=10+50), colour="black", size=1)+
            annotate("text", x = recency_adjust$new.customer, y = 10+120, 
                     color = "black", size=3, label=paste0(recency_adjust$new.customer," days"))+
            geom_point(aes(x=recency_adjust$active, y=370), colour="black", size=1)+
            annotate("text", x = recency_adjust$active, y = 440, 
                     color = "black", size=3, label=paste0(recency_adjust$active," days"))+
            geom_point(aes(x=recency_adjust$warm, y=470), colour="black", size=1)+
            annotate("text", x = recency_adjust$warm, y = 540, 
                     color = "black", size=3, label=paste0(recency_adjust$warm," days"))+
            geom_point(aes(x=recency_adjust$cold, y=1670), colour="black", size=1)+
            annotate("text", x = recency_adjust$cold, y = 1740, 
                     color = "black", size=3, label=paste0(recency_adjust$cold," days"))+

            annotate("text", x = (0+recency_adjust$new.customer)/2, y = max(recency_segmentation$freq), 
                     color = "black", size=3, label="New")+
            annotate("text", x = (0+recency_adjust$new.customer)/2, y = max(recency_segmentation$freq)+140, 
                     color = "black", size=3.2, label=prettyNum(recency_count %>% filter(Var1=="new.customer") %>% .$Freq, big.mark=","))+
            annotate("text", x = (0+recency_adjust$new.customer)/2, y = max(recency_segmentation$freq)-140, 
                   color = "#676767", size=2.2, label=paste0(round(((recency_count %>% filter(Var1=="new.customer") %>%
                                                                       .$Freq)/sum(recency_count$Freq))*100,1),"%"))+
          
            annotate("text", x = median(recency_adjust$new.customer:recency_adjust$active), y = max(recency_segmentation$freq), 
                     color = "black", size=3, label="Active")+
            annotate("text", x = median(recency_adjust$new.customer:recency_adjust$active), y = max(recency_segmentation$freq)+140, 
                     color = "black", size=3.2, label=prettyNum(recency_count %>% filter(Var1=="active") %>% .$Freq, big.mark=","))+
            annotate("text", x = median(recency_adjust$new.customer:recency_adjust$active), y = max(recency_segmentation$freq)-140, 
                   color = "#676767", size=2.2, label=paste0(round(((recency_count %>% filter(Var1=="active") %>%
                                                                       .$Freq)/sum(recency_count$Freq))*100,1),"%"))+
          
            annotate("text", x = median(recency_adjust$active:recency_adjust$warm), y = max(recency_segmentation$freq), 
                     color = "black", size=3, label="Warm")+
            annotate("text", x = median(recency_adjust$active:recency_adjust$warm), y = max(recency_segmentation$freq)+140, 
                     color = "black", size=3.2, label=prettyNum(recency_count %>% filter(Var1=="warm") %>% .$Freq, big.mark=","))+
            annotate("text", x = median(recency_adjust$active:recency_adjust$warm), y = max(recency_segmentation$freq)-140, 
                     color = "#676767", size=2.2, label=paste0(round(((recency_count %>% filter(Var1=="warm") %>%
                                                                         .$Freq)/sum(recency_count$Freq))*100,1),"%"))+
            
            annotate("text", x = median(recency_adjust$warm:recency_adjust$cold), y = max(recency_segmentation$freq), 
                     color = "black", size=3, label="Cold")+
            annotate("text", x = median(recency_adjust$warm:recency_adjust$cold), y = max(recency_segmentation$freq)+140, 
                     color = "black", size=3.2, label=prettyNum(recency_count %>% filter(Var1=="cold") %>% .$Freq, big.mark=","))+
            annotate("text", x = median(recency_adjust$warm:recency_adjust$cold), y = max(recency_segmentation$freq)-140, 
                      color = "#676767", size=2.2, label=paste0(round(((recency_count %>% filter(Var1=="cold") %>%
                                                                          .$Freq)/sum(recency_count$Freq))*100,1),"%"))+
          
            annotate("text", x = median(recency_adjust$cold:max(recency_segmentation$recency_days)), y = max(recency_segmentation$freq), 
                     color = "black", size=3, label="Inactive")+
            annotate("text", x = median(recency_adjust$cold:max(recency_segmentation$recency_days)), y = max(recency_segmentation$freq)+140, 
                     color = "black", size=3.2, label=prettyNum(recency_count %>% filter(Var1=="inactive") %>% .$Freq, big.mark=","))+
            annotate("text", x = median(recency_adjust$cold:max(recency_segmentation$recency_days)), y = max(recency_segmentation$freq)-140, 
                     color = "#676767", size=2.2, label=paste0(round(((recency_count %>% filter(Var1=="inactive") %>%
                                                                         .$Freq)/sum(recency_count$Freq))*100,1),"%"))+
            labs(
                #title= "Order Value by Recency",
                title = "Recency Segmentation using Quantile Method",
                x = "Recency (days since last transaction)",
                y = "Total Customer"
            )+
            my_plot_theme(10)
        
ggplotly(plot_recency_segmentation, tooltip = NULL)%>% 
    layout(showlegend=FALSE) %>%  
    config(displayModeBar = F)

Sebanyak 60% dari pelanggan e-commerce berstatus inactive alias sudah lebih dari 9 bulan tidak melakukan belanja. Sedangkan pelanggan baru hanya berjumlah sekitar 30 orang.

RFM Score Segmentation

Sekarang mari kita lakukan segmentasi menggunakan nilai skor dari tiap parameter RFM. Adapun kategori pengelompokan sebagai berikut.

segment description recency frequency monetary
Champions Bought recently, buy often and spend the most 4-5 4-5 4-5
Loyal Customers Spend good money. Responsive to promotions 2-5 3-5 3-5
Potential Loyalist Recent customers, spent good amount, bought more than once 3-5 1-3 1-3
New Customers Bought more recently, but not often 4-5 1 1
Promising Recent shoppers, but haven’t spent much 3-4 1 1
Need Attention Above average recency, frequency & monetary values 2-3 2-3 2-3
About To Sleep Below average recency, frequency & monetary values 2-3 1-2 1-2
At Risk Spent big money, purchased often but long time ago 1-2 2-5 2-5
Can’t Lose Them Made big purchases and often, but long time ago 1 4-5 4-5
Hibernating Low spenders, low frequency, purchased long time ago 2-3 2-3 2-3
Lost Lowest recency, frequency & monetary scores 1-2 1-2 1-2

Dapat kita lihat bersama, bahwasannya data histori belanja pelanggan kita hanya memiliki 6 segmen dengan segment Others merupakan kategori pelanggan yang tidak memenuhi semua kategori yang telah kita definisikan. Adapun anggota segmen terbanyak ialah Others. Hanya terdapat 4 pelanggan yang terdeteksi sebagai Loyal Customer dan sebanyak 4.721 pelanggan terdeteksi sebagai Potential Loyalist. Adapun banyaknya pelanggan yang terdeteksi churn atau Lost sejumlah 18.563.

Selanjutnya, mari kita coba lihat karakter RFM dari tiap segmen pelanggan.

Dapat kita lihat bersama bahwa profiling dari karakter segmen tiap pelanggan yang dihasilkan melalui RFM score masih belum mampu membedakan karakter pelanggan dengan baik. Kemudian, kebanyakan pelanggan tidak memasuki semua segmen yang kita kategorikan.

RFM Segmentation Result

Selanjutnya, mari kita bandingkan hasil segmentasi dari kombinasi k-means dan quantile dengan segmentasi RFM score.

nb: nilai persen menyatakan persentase pelaggan anggota klaster dari total pelanggan

Secara pasti, kita dapat melihat bahwa untuk data histori belanja e-commerce pakistan ini, metode segmentasi dengan RFM score kurang relevan. Hampir 60% pelanggan tidak terdeteksi atau memenuhi kriteria dari 11 segmen yang telah dibuat sebelumnya. Adapun segmentasi dengan kombinasi k-means dan quantile memberikan kelompok pelanggan sebanyak 5 berdasarkan nilai recency dan 4 berdasarkan nilai frequency dan monetary. Segmentasi kombinasi k-means dan quantile menghasilkan sebanyak 20 kelompok pelanggan. Sehingga, pada kesempatan ini kita akan menggunakan segmentasi dari kombinasi k-means dan quantile.

Selanjutnya mari kita coba ketahui total monetary yang telah diberikan oleh tiap segmen, baik dari segmen recency maupun segmen customer value.

Secara recency segmen, kita dapatkan pemahaman bahwasannya sebanyak 40,5% dari total monetary yang telah didapatkan selama dua tahun ialah berasal dari segmen warm. Adapun segmen active, yang mana meiliki nilai recency di rentang 30-90 hari, masih belum berpartisipasi aktif dalam menyumbangkan kenaikan pendapatan bagi perusahaan, begitu juga dengan segmen new.customer. Namun hal itu dapat diterima mengingat nilai frequency-nya yang masih kecil. Selain itu, jumlah anggota segmen active dan new.customer sangat sedikit, sekitar 0,2% dari total pelanggan.

Terdapat hal menarik dari hasil visualisasi di atas, yakni walaupun segmen warm memiliki persentase jumlah anggota sekitar 15%, namun mampu menyumbangkan 40,5% dari total pendapatan yang diterima perusahaan. Segmen warm ini menjadi segmen yang potensial, namun perlu hati-hati karena telah tiga bulan lebih tidak melakukan belanja. Perusahaan dapat menerapkan strategi untuk menarik pelanggan warm ini agar melakukan transaksi lebih sering.

Pada segmen new.customer dan active, perusahaan perlu menreapkan strategi yang berfokus kepada peningkatan frekuensi berbelanja dari pelanggan. Sehingga, pendapatan perusahaan dapat meningkat.

Wow,.. walaupun anggota segmen special value hanya 7,7%, namun hampir 68% total monetary perusahaan berasal dari segmen ini. Adapun presentase pelanggan tertinggi berada di segmen low value yang mana hampir 75%. Walupun demikian, antara semua segmen, selain special value, memberikan kontribusi total monetary yang hampir sama.

Selanjunya, mari kita coba lihat dari segi nilai frequency-nya.

Jika kita melihat visualisasi terkait jumlah total transaksi yang dilakukan berdasarkan customer value segmen, kita dapatkan kembali hal menarik dimana meskipun total pelanggan segmen special value hanya 7,7% namun menyumbangkan 37,9% dari total transaksi di perusahaan. Kita juga perlu memperhatikan segmen Low Value, meskipun nilai dari anggota segmen ini rendah tetapi jumlah persentase total transaksi yang dilakukan oleh pelanggan segmen ini hampir 50%. Hal itu berkaitan juga dengan banyaknya pelanggan yang tergolong sebagai Low Value, yakni hampir 75% daritotal pelanggan perusahaan.

Begitu juga pada total transaksi persegmen pelanggan dari Recency Segmentation. Perbandingan persentase dari total transaksi tiap segmen selaras dengan jumlah total pelanggan yang termasuk dalam segmen tersebut, sehingga tidak terdapat fakta menarik yang bisa ditekankan. Lebih dari itu, kita perlu memprhatikan hal yang sangat fundamental yakni mengembalikan segmen pelanggan inactive menjadi active kembali, mengingat banyaknya pelangga perusahaan ini yang telah tergolong Inactive. Selain itu, sebanyak 48,7% total transaksi di perusahaan ini adalah berasal dari segmen inactive.

Summary

Sekarang mari kita ringkas dari semua kegiatan yang kita lakukan pada topik Customer Segmentation di perusahaan E-commperce Pakistan ini.

  1. Pelanggan Perusahaan: E-commerce Pakistan ini memiliki total jumlah pelanggan dari Maret 2016 hingga Agustus 2018 sebanyak 98.576 pelanggan.

  2. Segmentasi Pelanggan: Hasil segmentasi pelanggan menggunakan metode RFM dibagi menjadi segmentasi berdasarkan nilai Recency (Recency Segmentation) dengan metode Quantile dan berdasarkan kombinasi nilai Frequency-Monetary (Customer Value Segmentation) dengan k-means algorithm. Hasil Recency Segmentation menghasilkan 5 segmen yakni new customer, active, warm, cold dan inactive. Sedangkan Customer Value Segmentation menghasilkan 4 segmen, yakni Special Value, High Value, Medium Value, dan Low Value.

  3. Profil Segmen Pelanggan: Berikut adakah ringkasan karakter dari tiap segmen pelanggan yang telah dibuat serta distribusi dari total anggota segmennya.

Strategy Recommendation

Kita bersama telah berhasil menganalisis pelanggan dari perusahaan e-commerce Pakistan dan telah menghasilkan beberapa segmen pelanggan. Sekarang mari kita berikan beberapa rekomendasi strategi bisnis yang dapat diterapkan terhadap tiap segmen pelanggan dan sesuai dengan karakter segmen tersebut.

Strategi Bisnis Berdasarkan Recency Segmentation:

  1. New Customer
  • Kampanye Selamat Datang: Kirimkan pesan selamat datang yang menawarkan diskon pertama atau insentif khusus untuk transaksi pertama mereka.

  • Program Loyalitas: Tarik mereka ke dalam program loyalitas dengan insentif berkelanjutan untuk berbelanja lebih sering.

  1. Active (31-90 Hari) dan Warm (91-180 Hari):
  • Kampanye Promosi Berkala: Kirimkan penawaran eksklusif atau diskon berkala untuk menjaga mereka terlibat.

  • Cross-Selling: Tawarkan produk terkait yang sesuai dengan pembelian sebelumnya.

  1. Cold (181-270 Hari) dan Inactive (> 270 Hari):
  • Kampanye Reaktivasi: Kirimkan pesan persuasif yang menawarkan insentif besar untuk mengembalikan mereka.

  • Survei Pelanggan: Tanyakan alasannya mengapa mereka tidak aktif dan perbaiki layanan Anda berdasarkan umpan balik mereka.

Strategi Bisnis Berdasarkan Customer Value Segmentation

  1. Low Value (Super Low Frequency, Low Monetary)
  • Kampanye Upselling: Tawarkan produk atau layanan tambahan dengan harga terjangkau untuk meningkatkan nilai transaksi mereka.

  • Promosi Cross-Selling: Dorong pembelian produk tambahan yang sesuai dengan pembelian mereka.

  1. Medium Value (Super Low Frequency, Medium Monetary)
  • Diskon untuk Frekuensi: Berikan insentif untuk pembelian berulang, seperti diskon untuk setiap pembelian berikutnya.

  • Penawaran Bundel: Tawarkan bundel produk dengan harga yang menarik untuk meningkatkan nilai transaksi.

  1. High Value (Medium Frequency, High Monetary)
  • Program VIP: Ini adalah pelanggan berharga, jadi tawarkan program VIP eksklusif dengan layanan prioritas, diskon eksklusif, atau akses ke produk terbatas.

  • Program Referral: Ajak mereka untuk merujuk teman dan keluarga untuk meningkatkan frekuensi pembelian.

  1. Special Value (Super High Frequency, Super High Monetary)
  • Penghargaan Berkelanjutan: Berikan penghargaan berkelanjutan, hadiah eksklusif, atau pengiriman gratis untuk menjaga loyalitas mereka.

  • Program Eksklusif: Berikan akses eksklusif ke produk atau layanan tertentu yang hanya tersedia untuk segmen ini.

Dengan strategi yang sesuai untuk masing-masing segmen ini, Perusahaan dapat meningkatkan performa bisnis dalam hal Recency dan Frequency-Monetary, menjaga pelanggan yang ada dan menarik pelanggan baru.

Whats next?

Kita telah menyelesaikan part Customer Segmentation ini, dengan ditutup strategi bisnis yang dijamin Top Markotop :). Selanjutnya, mari kita coba me-remind kembali tentang strategi kita dalam mengurangi masalah pembatalan pesanan dan meningkatan pendapatan perusahaan ini. Benar, yakni Personalisasi Produk Rekomendasi. Kita akan menganalisis terkait produk manakah yang kemungkinan besar disukai dan akan dibeli oleh pelanggan. Nantinya, setelah kita bersama mendapatkan hasilnya, penerapan berbagai strategi bisnis yang telah kita tentukan sebelumnya dapat diterapkan pada produk barang-barang tersebut. Misalkan diambil contoh, kita aplikasikan terhadap strategi Promosi Cross-Selling: Dorong pembelian produk tambahan yang sesuai dengan pembelian mereka pada segmen Low Value. Kita gunakan hasil analisis Personalisasi Produk Rekomendasi untuk promosi cross-selling.

Tau ngak sih? Tidak cukup disitu, terdapat beberapa keuntungan yang lain dengan menggunakan strategi Personalisasi Produk Rekomendasi yang akan kita terapkan nanti. Pertama, pemasaran atau kampanye yang dilakukan oleh perusahaan akan lebih akurat. Kedua, meningkatkan engagement dengan pelanggan. Pelanggan akan merasa perusahaan dapat memenuhi kebutuhan dengan kasus unik mereka sehingga membentuk pandangan yang baik terhadap perusahaan. Ketiga, optimasi nilai Return of Investment. Dan yang Terakhir ialah dapat meningkatkan nilai penjualan.

Kata pepatah “Sekali Tepuk, Dua lalat kena”. Yups, pepatah tersebut mengambarkan manfaat strategi yang akan kita gunakan. Yuks…. Cap Cuss…..