About Data

Pada projek Study Case ini, digunakan data dari UCI Machine Learning yang berupa dataset transaksi yang terjadi pada periode 01/12/2010 hingga 09/12/2011. Dataset ini merupakan transaksi yang terjadi pada online retail yang berbasis di UK.

Read Data

Berdasarkan informasi dari UCI Machine Learning, dataset Online Retail, dataset ini tidak memiliki NA Value, terdiri dari 541.909 baris dengan 8 kolom, serta berikut informasi setiap atributnya:

Variable Description
InvoiceNo a 6-digit integral number uniquely assigned to each transaction. If this code starts with letter ‘c’, it indicates a cancellation
StockCode a 5-digit integral number uniquely assigned to each distinct product
Description Product (item) name
Quantity the quantities of each product (item) per transaction
InvoiceDate the day and time when each transaction was generated
UnitPrice product price per unit
CustomerID a 5-digit integral number uniquely assigned to each customer
Country the name of the country where each customer resides

Jumlah baris serta kolom pada dataset telah sesuai dengan yang termuat pada sumber data. Selanjutnya, mari kita coba eksplor secara sekilas dataset ini terlebih dahulu.

#> Rows: 541,909
#> Columns: 8
#> $ InvoiceNo   <chr> "536365", "536365", "536365", "536365", "536365", "536365"~
#> $ StockCode   <chr> "85123A", "71053", "84406B", "84029G", "84029E", "22752", ~
#> $ Description <chr> "WHITE HANGING HEART T-LIGHT HOLDER", "WHITE METAL LANTERN~
#> $ Quantity    <dbl> 6, 6, 8, 6, 6, 2, 6, 6, 6, 32, 6, 6, 8, 6, 6, 3, 2, 3, 3, ~
#> $ InvoiceDate <dttm> 2010-12-01 08:26:00, 2010-12-01 08:26:00, 2010-12-01 08:2~
#> $ UnitPrice   <dbl> 2.55, 3.39, 2.75, 3.39, 3.39, 7.65, 4.25, 1.85, 1.85, 1.69~
#> $ CustomerID  <dbl> 17850, 17850, 17850, 17850, 17850, 17850, 17850, 17850, 17~
#> $ Country     <chr> "United Kingdom", "United Kingdom", "United Kingdom", "Uni~

Tiap kolom dari dataset telah memiliki tipe data yang tepat, namun, nanti saya akan melakukan pengecekan pada kolom dengan tipe data karakter. Tujuannya, saya akan menentukan terkait konversi tipe data kolom ke factor.

#>   InvoiceNo          StockCode         Description           Quantity        
#>  Length:541909      Length:541909      Length:541909      Min.   :-80995.00  
#>  Class :character   Class :character   Class :character   1st Qu.:     1.00  
#>  Mode  :character   Mode  :character   Mode  :character   Median :     3.00  
#>                                                           Mean   :     9.55  
#>                                                           3rd Qu.:    10.00  
#>                                                           Max.   : 80995.00  
#>                                                                              
#>   InvoiceDate                       UnitPrice           CustomerID    
#>  Min.   :2010-12-01 08:26:00.00   Min.   :-11062.06   Min.   :12346   
#>  1st Qu.:2011-03-28 11:34:00.00   1st Qu.:     1.25   1st Qu.:13953   
#>  Median :2011-07-19 17:17:00.00   Median :     2.08   Median :15152   
#>  Mean   :2011-07-04 13:34:57.16   Mean   :     4.61   Mean   :15288   
#>  3rd Qu.:2011-10-19 11:27:00.00   3rd Qu.:     4.13   3rd Qu.:16791   
#>  Max.   :2011-12-09 12:50:00.00   Max.   : 38970.00   Max.   :18287   
#>                                                       NA's   :135080  
#>    Country         
#>  Length:541909     
#>  Class :character  
#>  Mode  :character  
#>                    
#>                    
#>                    
#> 

Pada ringkasan dari dataset secara kesuluruhan, NA Value ditemukan ada, tepatnya pada kolom CustomerID. Hal ini berarti kondisi dataset tidak sesuai dengan deskripsi dari sumber data. Kemudian, nilai negatif ditemukan pada kolom Quantity, adapun kolom ini menunjukkan jumlah item yang dibeli. Sehingga, temuan ini cukup aneh dan perlu inpeksi secara mendetail pada dataset ini. Adapun deskripsi terkait rentang periode dataset ini telah sesuai dengan kondisi sebenarnya.

EDA & Data Preparation

Langkah berikutnya, saya akan melakukan Exploratory Data Analysis (EDA) dan preparasi data.

Data Type Conv.

Mari kita cek jumlah nilai unik pada tiap kolom data yang bertipe character.

#> kolom InvoiceNo memiliki nilai unik: 25900 ( 4.78 % dari total data ) 
#> kolom StockCode memiliki nilai unik: 4070 ( 0.75 % dari total data ) 
#> kolom Description memiliki nilai unik: 4212 ( 0.78 % dari total data ) 
#> kolom Country memiliki nilai unik: 38 ( 0.01 % dari total data )

Dari hasil inspeksi, saya memilih kolom Country dirubah menjadi tipe data factor karena memiliki jumlah nilai unik Country sedikit.

Na Value Checking

#>   InvoiceNo   StockCode Description    Quantity InvoiceDate   UnitPrice 
#>           0           0        1454           0           0           0 
#>  CustomerID     Country 
#>      135080           0

Dataset ini ternyata memiliki NA Value pada kolom Description dan CustomerID. Saya akan mencoba mencari tahu lebih mendalam pada dua kolom tersebut, yang mana dengan baris berupa NA Value.

Customer ID

Sebanyak 135.080 baris pada dataset ini memiliki nilai NA Value pada kolon CustomerID. Saya tidak dapat membuang data ini secara langusung karena saya berasumsi bisa jadi ini adalah pembelian tanpa mendaftar akun terlebih dahulu atau sebagianya. Hal yang pasti ialah online retail tetap mendapatkan pendapatan. Sehingga, baris pada dataset dengan nilai NA Value tetap dapat memberikan pemahaman akan berbagai hal, misal total pendapatan yang didapat perusahaan, kesedian stok barang, dan lain-lain.

Description

Secara sekilas, kita melihat bahwa semua kolom Description yang berupa NA Value memiliki kolom CustomerID juga berupa NA Value.

Ternyata memang benar, semua kolom Description yang berupa NA Value memiliki kolom CustomerID juga berupa NA Value.

Begitu juga dengan kolom UnitPrice, di mana semua kolom Description yang berupa NA Value memiliki nilai UnitPrice bernilai 0.

Imputasi NA Value

Pada sesi imputasi NA Value, hal ini hanya dapat dilakukan pada kolom Description, dan itu pun kita harus meninjaunya terlebih dahulu. Kolom Description dapat dilakukan imputasi karena adakalanya NA Value terjadi pada item dengan StockCode yang sama dengan salah satu baris namun memliki nilai Description yang tidak berupa NA Value.

Sebagaimana dugaan saya sebelumnya, bahwa besar kemungkinan StockCode dengan Description berupa NA Value sebenarnya memiliki Description pada baris lain. Namun, dari inspeksi di atas, kita dapat melihat bahwa terdapat beberapa item yang memiliki Description lebih dari satu.

Ternyata memang benar bahwa cukup banyak StockCode yang memiliki Description lebih dari satu.

Selanjutnya, mari kita pilih Description yang paling sering muncul untuk tiap satu StockCode yang digunakan imputasi. Kemudian, dilanjutkan dengan imputasi pada kolom Description.

Columns Checking

Selanjutnya, mari kita lakukan eksplorasi secara mendalam pada tiap kolomnya dan lakukan pembersihan data yang tidak relevan.

InvoiceNo

Cancel Order Sebagaimana yang disebutkan dalam deskripsi dari kolom dataset, transaksi diawali huruf C maka artinya transaksi tersebut dicancel.

#> [1] 1947

Terdapat 1.947 transaksi yang dibatalkan atau cancel.

Semua cancel transaction memiliki Quantity bernilai negatif. Hal ini cukup susah dipahami karena tidak terdapat petunjuk lain dari data ini terkait nilai Quantity yang negatif. Begitu juga adanya keterkaitan antara transaksi yang dibatalkan dengan nilai Quantity yang negatif, masih belum bisa didefinisikan dengan baik.

Invalid Berdasarkan deskripsi tiap kolom, InvoiceNo terdiri dari 6 digit angka yang bersifat unik setiap transaksi, maka kita perlu mempertimbangkan InvoiceNo yang tidak sesuai dengan kriteria tersebut.

Pada dataset ini, hanya ada tiga InvoiceNo yang tidak valid dan akan dibuang.

StockCode

Deskripsi kolom menyatakan bahwa StockCode ini merupakan kode produk yang terdiri dari 5 digit angka yang bersifat unik. Namun, pada beberapa eksplorasi yang saya lakukan sebelumnya, beberapa nilai StockCode tidak sesuai dengan kriteria tersebut.

Ternyata, banyak nilai StockCode yang tidak tersusun dari 5 digit angka. Mari kita lakukan cek dan pembersihan.

StockCode yang memiliki 1 sampai 4 karakter

Dapat dipastikan bahwa data StockCode yang tersusun atas 1 hingga 4 karakter adalah InvoiceNo yang tidak valid.

StockCode yang memiliki 5 karakter

Data StockCode yang tersusun atas 5 digit angka adalah data yang valid.

StockCode yang memiliki 6 karakter

StockCode yang terdiri dari 6 karakter itu tersusun atas 5 angka dan 1 huruf. Berdasarkan data di atas, huruf pada stock code terlihat seperti menunjukan karakter masing-masing produk. Sebagaimana contohnya pada StockCode 84997B dan 84997C itu adalah produk yang sama namun memiliki warna yang berbeda. sehingga, seluruh data di atas dapat dianggap sebagai produk yang berbeda dan valid.

StockCode yang memiliki lebih dari 6 karakter

Pada data yang memiliki StockCode lebih dari 6 karakter, berdasarkan nilai Description-nya, terdapat beberapa data yang menunjukkan bahwa produk tersebut valid. Namun, banyak data yang menunjukkan produk tidak valid

Pembersihan Data

Quantity

Berdasarkan pengecekan cancel transaction sebelumnya, kita dapatkan bahwa semua cancel transaction memiliki nilai Quantity negatif. Sehingga, mari kita lihat pada transaksi yang tidak dibatalkan namun memiliki nilai Quantity negatif.

#> [1] 1331

Sebanyak 1.331 baris dan 1.331 transaksi pada data ini memiliki nilai Quantity negatif, artinya Quantity bernilai negatif itu terdapat dalam satu InvoiceNo atau transaksi.

Kemudian, secara sekilas data di atas menunjukkan bahwa semunya memiliki UnitPrice 0 dan CustomerID berupa NA Value.

Adakalanya nilai Quantity negatif dan bukan cancel trans. adalah bukan transaksi sebenarnya, namun bisa jadi semacam pendataan stock atau yang lainnya. Hal ini hanya praduga saja. Akan tetapi, jika itu benar maka pada dataset ini akan dapat ditemukan baris dengan nilai UnitPrice == 0, Customer ID == NA dan hanya pada satu InvoiceNo == satu baris itu memiliki nilai Quantity yang positif. Mari kita coba saja.

Sebelumnya, kita buang data yang memiliki nilai Quantity negatif dan bukan termasuk cancel trans. karena memang tidak ditemukan makna sebenarnya dari pemilik dataset ini.

UnitPrice

Mari kita coba lihat baris dengan UnitPrice ==0 dan CustomerID == NA.

dan kita lanjutkan dengan pengecekan keunikan nilai InvoiceNo-nya pada tiap transaksinya.

Ternyata pada UnitPrice == 0 dan CustomerID == NA itu juga terjadi dalam satu InvoiceNo dalam beberapa baris, sehingga masih belum ditemukan apa makna sebenarnya dari Quantity < 0. Namun, kita dapat membuang baris dengan UnitPrice == 0 dan CustomerID == NAkarena alasan mempertahankan baris dengan CustomerID == NA sebelumnya, tepatnya pada eksplorasi data bagian Na Value Checking, adalah untuk memperhitungkan adanya kemungkinan pendapatan dari baris dengan CustomerID == NA. Hal itu dimaksudkan agar tahu pendapatan sebenarnya Online Retail ini.

Description

Mari kita identifikasi deskripsi yang tidak valid berdasarkan penelitian yang dilakukan oleh Diego Usai pada tanggal 14 Maret 2019 terkait Analisis Berbasis Pasar menggunakan data penjualan ritel online ini serta beberapa deskripsi tidak valid yang kita temukan bersama sebelumnya.

Ternyata setelah beberapa pengolahan atau preparasi data yang kita lakukan sebelumnya, data kita telah memiliki deskripsi yang valid.

Sekarang mari kita coba cek kembali pada data yand memiliki nilai Description == NA

Ternyata data kita yand memiliki nilai Description == NA telah bersih.

Selanjutnya, kita masih perlu memastikan apakah tiap stock code telah memiliki deskripsi yang unik alias setiap StockCode merepsentasikan satu jenis item atau produk.

Data ditas mengindikasikan ada beberapa StockCode yang memiliki deskripsi lebih dari satu, karena seharusnya jumlah unik dari StockCode = Description = stock_code_description, maka kita perlu membersihkannya. Adapun dalam prosedur pembersihan dilakukan dengan menggunakan deskripsi yang paling akhi dari satu StockCode yang memiliki beberapa Deskription, dengan asumsi bahwa adanya pembaruan deskripsi.

Ada 210 produk yang memiliki deskripsi lebih dari satu.

Tiap produk pada online ritel ini telah memiliki satu deskripsi yang unik.

CustomerID

Berdasarkan deskripsi atribut, dinyatakan bahwa kolom CustomerID tersusun atas 5 digit dengan tipe data integer.

#> [1] 0

Pada data kita tidak terdapat baris dengan nilai CustomerID yang tidak valid atau sesuai dengan deskripsi, alias semua datanya valid berdasarkan kolom CustomerID.

Country

Atribut data menyatakan bahwa kolom Country merupakan nama negara tempat tinggal setiap pelanggan, maka ada kalanya seorang pelanggan yang sama dalam riwayat transaksi ini berada dibeberapa negara. Coba kita cek.

Ternyata terdapat pelanggan yang pernah melakukan transaksi dibeberapa negara.

Data Periodical Cut-Off

Data transaksi yang tersedia mencakup periode dari 1 Desember 2010 hingga 9 Desember 2011. Karena data transaksi Desember 2011 tidak lengkap, saya memutuskan untuk menghilangkan data tersebut dari analisis ini. Dengan demikian, kita memiliki data transaksi lengkap selama satu tahun, mulai dari Desember 2010 hingga November 2011.

Duplicate Value

Saya di sini akan melakukan pengecekan terkait adanya nilai duplikat dan membuangnya.

#> [1] TRUE
#> [1] 4954

Ternyata, terdapat 4.954 data yang merupakan duplikat. Mari kita buang nilai duplikat tersebut.

Feature Extraction

Sekarang mari kita lakukan beberapa feature extraction.

Beriku deskripsi beberapa feature yang saya buat.

Feature Description
FirstOrder Pertama kali customer melakukan transaksi
LastOrder Terakhir kali customer melakukan transaksi
AvgAmountOrder Rata-rata biaya yang dikeluarkan customer per-transaksi
AvgBaskets Rata-rata jumlah produk yang dibeli customer per-transaksi
AgeCustomer Umur Pelanggan

Explanatory Data Analysis

Monthly Total Revenue

Berdasarkan tren pendapatan bulanan, ritel online UK ini memiliki tren yang positif di 4 bulan terakhir dan fluktuatif di periode awal. Pendapatan terendah terjadi pada bulan Februari 2011 dengan nilai sekitar £ 442.290. Sedangkan pendapatan tertinggi terjadi di bulan Desember 2012 dengan nilai sekitar £ 1.134.010.

Selanjutnya, mari kita coba lihat Month-over-Month Growth atau MoM Growth dari pendapatan yang diperoleh ritel online UK.

Sebagaimana hasil tren yang didapatkan sebelumnya, pertumbuhan pendapatan terjadi secara berturut-turut di empat bulan terakhir, dan di periode awal cenderung fluktuatif alias naik turun. Adapun pertumbuhan paling tinggi terjadi di bulan september 2011 dan penurunan pendapatan paling signifikan terjadi di bulan April 2011.

Monthly Total Transactions

Tren total transaksi bulanan yang terjadi di ritel online UK ini juga fluktuatif di periode-periode awal, dan secara stabil terjadi kenaikan di tiga bulan terakhir. Bulan Januari 2011, total transaksi yang terjadi paling sedikit daripada bulan-bulan yang lainnya, sedangkan November 2011 menjadi bulan dengan transaksi yang paling banyak.

Sebagaimana hasil tren yang didapatkan sebelumnya, pertumbuhan total transaksi terjadi di tiga bulan terakhir, dan di lima bulan awal cenderung fluktuatif. Selain itu, terjadi penurunan secara berturut-turut dari Juni hingga Agustus 2011. Adapun pertumbuhan paling tinggi terjadi di bulan November 2011 dan penurunan pendapatan paling signifikan terjadi di bulan Januari 2011.

Monthly Total Customers

Tren total pelanggan bulanan yang melakukan transaksi di ritel online UK ini juga fluktuatif di periode-periode awal, dan secara stabil terjadi kenaikan di tiga bulan terakhir. Bulan Januari 2011, total transaksi yang terjadi paling sedikit daripada bulan-bulan yang lainnya, sedangkan November 2011 menjadi bulan dengan transaksi yang paling banyak.

Tren MoM Growth dari total pelanggan bulanan yang melakukan transaksi di ritel online UK ini mirip seperti tren MoM Growth dari total transaksi yang terjadi. Perbedaannya adalah pada pertumbuhan paling tinggi yang terjadi di bulan September 2011.

Monthly New Customers

Kita lihat bersama bahwa hampir selalu terjadi penurunan secara brturut-turut pada jumlah pelanggan baru tiap bulannya. Kenaikan jumlah pelanggan baru hanya terjadi pada bulan Maret, September, dan November 2011. Untuk lebih jelasnya, mari kita coba lihat secara langsung dari MoM Growth.

old_customer_monthly <-  df_ready %>% mutate(Month_Year = as.yearmon(InvoiceDate)) %>%  
  select(Month_Year, CustomerID) %>% 
  distinct() %>% 
  select(CustomerID) %>% 
  duplicated() %>% 
  which()

calculate_mom_growth <- function(data) {
  data$Month_Year <- as.yearmon(data$Month_Year)
  data <- data[order(data$Month_Year), ]
  data$MoM_Growth <- c(NA, (data$TotalCustomer[-1] - data$TotalCustomer[-nrow(data)]) / data$TotalCustomer[-nrow(data)] * 100)
  # data$MoM_Growth <- sprintf("%.2f%%", data$MoM_Growth)
  data$MoM_Growth <- round(data$MoM_Growth,2)
  return(data)
}

df_MoM_NewCustomer <- df_ready %>% mutate(Month_Year = as.yearmon(InvoiceDate)) %>% 
  select(Month_Year, CustomerID) %>% 
  distinct() %>% 
  filter(!row_number() %in% c(old_customer_monthly)) %>% 
  group_by(Month_Year) %>% 
  summarise(TotalCustomer = length(unique(CustomerID)))

df_MoM_NewCustomer<- calculate_mom_growth(df_MoM_NewCustomer)
df_MoM_NewCustomer <- df_MoM_NewCustomer %>% filter(!MoM_Growth == "NA%")

plot_MoM_newcustomer <- df_MoM_NewCustomer %>% 
  mutate(popup = glue("{Month_Year}
                       MoM Growth: {MoM_Growth}%")) %>% 
  ggplot()+
  geom_col(data = . %>% filter(MoM_Growth > 0),aes(x = Month_Year, 
                                                   y = MoM_Growth, text = popup), fill = "darkblue")+
  geom_col(data = . %>% filter(MoM_Growth < 0),aes(x = Month_Year, y = MoM_Growth,
                                                   text = popup), fill = "darkred")+
  labs(title = "MoM New Customer Growth Online Retail",
       x = NULL,
       y = NULL) +
  theme_minimal()+
  theme(plot.title = element_text(size = 15))

ggplotly(plot_MoM_newcustomer, tooltip="text") %>% 
  config(displayModeBar = F, scrollzoom = F)

Yups, kita lihat bersama memang hampir selalu terjadi penurunan jumlah pelanggan baru untuk tiap bulannya. Menariknya, meskipun terjadi penurunan jumlah pelanggan baru tiap bulannya, tetapi pendapatan, total transaksi, dan total pelanggan yang melakukan transaksi tetap memiliki tren yang positif. Hal ini bermakna positif di mana banyak pelanggan yang sering melakukan pembelian kembali. Selain itu, fakta ini bermakna bahwa meningkatkan retensi pelanggan adalah salah satu upaya yang perlu dan harus dilakukan. Tujuannya, mejaga pendapatan dari ritel online UK ini tetap meningkat meskipun pada kondisi jumlah pelanggan baru mengalami penurunan seiring berjalannya waktu.

Age Customer

Pelanggan pada ritel online UK ini banyak yang telah bergabung selama setahun. Lebih dari 50 persen pelanggan ritel online UK telah bergabung selama 6 bulan. Hasil distribusi umur atau lama pelanggan telah bergabung juga sejalan dengan kondisi pertumbuhan pelanggan baru. Distribusi umur pelanggan juga menunjukkan bahwa pelanggan baru yang bergabung jumlahnya sedikit.

Order Habit

df_monthly_habbit <- df_ready %>% select(InvoiceDate, InvoiceNo) %>% 
  distinct() %>%
  mutate(Month = month(InvoiceDate),
         Day = day(InvoiceDate)) %>% 
  group_by(Month,Day) %>% 
  summarise(Total = n()) %>% 
  ungroup() %>% 
  group_by(Day) %>% 
  summarise(AvgMonthlyTrans = as.integer(median(Total))) %>% 
  ungroup() %>% 
  mutate(popup = glue("Date : {Day}
                       Total Transaction: {AvgMonthlyTrans}")) 

df_monthly_habbit %>% 
  ggplot(aes(x=as.factor(Day), y=AvgMonthlyTrans)) +
  geom_bar(stat="identity", aes(fill=AvgMonthlyTrans),show.legend = FALSE)+
  labs(title = "Monthly Order Habbit",
    x = "Date", 
    y = NULL)+
  theme_minimal()+
  theme(axis.title = element_blank(),
        legend.position = "none",
        plot.title = element_text(hjust = 0.5,size=12, face="bold"),
        plot.subtitle = element_text(hjust = 0.5,size=10),
        axis.text.y = element_blank(),
        axis.text.x=element_text(size=11, face="bold"))+
  scale_fill_gradient()+
  #my_theme_fill()+
  coord_polar() -> polar1


# Daily
df_wday_habbit <- df_ready %>% select(InvoiceDate, InvoiceNo) %>% 
  distinct() %>% 
  mutate(Month = month(InvoiceDate),
        wday = wday(InvoiceDate)) %>% 
  group_by(Month,wday) %>% 
  summarise(Total = n()) %>% 
  ungroup() %>% 
  group_by(wday) %>% 
  summarise(AvgWdayTrans = as.integer(median(Total))) %>% 
  ungroup() %>% 
  mutate(popup = glue("wday : {wday}
                     Total Transaction: {AvgWdayTrans}")) 


df_wday_habbit %>% 
    ggplot(aes(wday,AvgWdayTrans))+
    geom_bar(width=1, stat="identity", show.legend = FALSE, aes(fill=AvgWdayTrans))+
    labs(
      title = "Daily Order Habbit",
      x = "Day", 
      y = NULL)+
    scale_x_continuous(breaks = c(1,2,3,4,5,6,7),
                       labels = c("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"))+
    theme_minimal()+
    theme(axis.title = element_blank(),
          legend.position = "none",
          plot.title = element_text(hjust = 0.5,size=12, face="bold"),
          plot.subtitle = element_text(hjust = 0.5,size=10),
          axis.text.y = element_blank(),
          axis.text.x=element_text(size=11, face="bold"))+
    scale_fill_gradient()+
    coord_polar() -> polar2



#Hourly
 
df_hourly_habbit <- df_ready %>% select(InvoiceDate, InvoiceNo) %>% 
  distinct() %>%
  mutate(Day = day(InvoiceDate),
         Hour = hour(InvoiceDate)) %>% 
  group_by(Day,Hour) %>% 
  summarise(Total = n()) %>% 
  ungroup() %>% 
  group_by(Hour) %>% 
  summarise(AvgHourlyTrans = as.integer(median(Total))) %>% 
  ungroup() %>% 
  mutate(popup = glue("Hour of Day : {Hour}
                       Total Transaction: {AvgHourlyTrans}")) 

time_range = data_frame(hour = c(0:23))

data_frame(Hour = c(0:23)) %>% 
  left_join(
    df_hourly_habbit ,by= "Hour") %>%
  mutate(Hour = as.factor(Hour)) %>% 
  ggplot(aes(x=Hour,y=AvgHourlyTrans))+
  geom_bar(stat="identity",show.legend = FALSE, aes(fill=AvgHourlyTrans))+
  labs(title = "Hourly Order Habbit",
    x = "Hour of Day", 
    y = NULL)+
  theme_minimal()+
  theme(axis.title = element_blank(),
        legend.position = "none",
        plot.title = element_text(hjust = 0.5,size=12, face="bold"),
        plot.subtitle = element_text(hjust = 0.5,size=10),
        axis.text.y = element_blank(),
        axis.text.x=element_text(size=11, face="bold"))+
  scale_fill_gradient()+
  coord_polar() -> polar3


grid.arrange(polar1,polar2,polar3, ncol = 3)

Semakin intens warna pada grafik di atas mencerminkan tingkat aktivitas transaksi yang lebih tinggi. Dengan merinci pola waktu ketika pelanggan cenderung berbelanja lebih banyak, kita dapat mengoptimalkan strategi kampanye untuk menyesuaikan dengan kebiasaan pembelian pelanggan. Berikut beberapa periode kebiasan pelanggan melakukan transaksi.

  1. Dalam 24 jam, transaksi hanya terjadi di jam 7 pagi hingga 6 malam. Pukul 12 siang menjadi waktu yang paling banyak pelanggan melakukan transaksi. Rata-rata transaksi ramai terjadi di jam 10 pagi hingga 3 sore.
  2. Dalam satu minggu, hari jumat menjadi hari yang paling banyak pelanggan melakukan transaksi.
  3. Dalam satu bulan, jumlah transaksi yang terjadi hampir sama di setiap waktu, yang paling banyak terjadi adalah di tanggal 5, 14, dan 30.

Unique Item Purhcased per Customer

Ini sangat menarik, hanya 2,14% dari total pelanggan di ritel online UK ini yang hanya pernah membeli satu jenis produk di ritel ini, sisanya membeli lebih dari satu jenis produk. Kondisi ini menjadi pendukung dalam analisis market basket untuk meningkatkan loyalitas pelanggan ke depannya. Selanjutnya, mari kita coba lihat rata-rata basket size dari pelanggan ritel online UK ini.

Basket Size

Ternyata, modus rata-rata basket size pelanggan ialah 72. ini kondisi yang sangat baik, kita bisa melakukan analisis market basket bahkan hingga personalisasi produk rekomendasi bagi pelanggan. Strategi ini dapat meningkatkan kepuasan pelanggan karena pelanggan merasa kebutuhan ataupun keinginannya dipenuhi oleh ritel ini, sehingga meningkatkan kemampuan perusahaan dalam mempertahankan pelanggan.

Best Country

Negara asal dari ritel online ini menjadi primadona dari negara pelanggan dalam melakukan transaksi, meskipun demikian beberapa negara eropa tentangga juga menjadi negara yang cukup banyak memberikan intensitas dalam bertransaksi. Menariknya adalah negara Australia, di mana negara yang berada di selatan benua asia, cukup memberikan porsi jumlah transaksi dari total transaksi yang terjadi selama satu tahun.

Business Strategy Analysis

RFM Analysis

Metode Recency, Frequency, Monetary Value (RFM) merupakan salah satu 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

Pada analisis RFM di R, telah tersedia package RFM untuk mempermudah analisis yang dilakukan.

Adapun deskripsi kolom, sebagai berikut:

Feature Description
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 di atas, terdapat indeks skor dari parameter RFM pelanggan. Secara default, nilai skor tiap parameter pelanggan dari data online retail UK ini didapat dengan teknik quantile dengan ketentuan sebagai berikut:

Menurut saya, pembagian dari hasil teknik Quantile pada dataset ini sudah cukup baik untuk digunakan scoring parameter RFM. Nilai score sudah merepresentasikan nilai dari RFM pelanggan. Contohnya, pada pelaggan dengan recency 1 sampai 12 hari, memiliki score recency 5 dan sebagainya. Sehingga, saya tidak melakukan manipulasi pembagian quantile secara manual. Akan tetapi, Penentuan scoring bisa disesuaikan dengan kebutuhan bisnis dan dapat menggunakan Unsupervised Machine Learning.

Kemudian, nilai RFM Score didapat dengan rumus sebagai berikut:

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

Selanjutnya, mari kita lihat hubungan antar parameter RFM.

Correlation on RFM Value

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

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 kapan terkahir kali belanja tidak dapat menunjukkan seberapa besar pelanggan telah membelanjakan uangnya di ritel online ini.

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 korelasi positif yang cukup kentara.

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 berkorelasi dengan parameter frequency maupun monetary. Sedangkan parameter frequency cukup berkorelasi positif dengan parameter monetary. Hasil ini memperkuat pemahaman kita dari analisis melalui visualisasi scatter plot sebelumnya.

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 meskipun skewed positif dibandingkan dengan persebaran data untuk parameter frequency dan monetary. Data dari dua parameter tersebut sangat tersebar secara skewed positif.

Jika kita lihat distribusi di atas dan meninjau teknik scoring RFM dengan metode quantile, maka kemungkinan besar pelanggan dari ritel online ini mayoritas memiliki score frequency dan monetary yang kecil, sedangkan score recency akan banyak tersebar dinilai yang tinggi.

Customer Segmentation

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

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

Dapat kita lihat bersama, bahwasannya data histori belanja pelanggan ritel online ini hanya memiliki 8 segmen dengan segmen Others merupakan kategori pelanggan yang tidak memenuhi semua kategori yang telah didefinisikan. Adapun anggota segmen terbanyak ialah Loyal Customer. Sedangkan banyaknya pelanggan yang terdeteksi churn atau Lost sejumlah 389.

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

Customer Segment’s Profile

segment <- segment %>%
  mutate(
  segment = factor(segment, levels = c("Others", "Lost", "At Risk", "About To Sleep", "Need Attention", "Potential Loyalist", "Loyal Customers", "Champions")))  %>% 
  select(customer_id, segment, rfm_score, transaction_count, recency_days, amount) 

df_profile <- segment %>%
  group_by(segment) %>% 
  summarise(
    total_customer = n(),
    total_monetary = sum(amount),
    total_frequency = sum(transaction_count),
    min_frequency = min(transaction_count),
    max_frequency = max(transaction_count),
    avg_frequency = as.integer(median(transaction_count)),
    min_monetary = min(amount),
    max_monetary = max(amount),
    avg_monetary = median(amount),    
    min_recency = min(recency_days),
    max_recency = max(recency_days),
    avg_recency = median(recency_days)
  ) %>% 
  mutate(
    persen_customer = round(total_customer/sum(total_customer)*100,2)
  )

df_profile %>% 
  mutate(popup = glue("Segment: {segment}
                      Total Customer: {total_customer}
                      Med. Recency: {round(avg_recency)}
                      Med. Frequency: {avg_frequency}
                      Med. Monetary: £ {comma(avg_monetary)}"),
         popup = str_replace_all(popup, pattern = "\n", replacement = "<br>")) %>%
  hchart(
    "treemap",
    hcaes(x = segment, 
          value = persen_customer,
          color = persen_customer,
          text = popup),
    dataLabels = list(enabled = TRUE, format='{point.segment}<br/>{point.persen_customer}%<br/>'),
    tooltip = list(pointFormat = "{point.popup}")
      ) %>%
  hc_title(text = "RFM Segmentation Result by RFM Score: Customer Distribution") %>%
  # hc_colorAxis(stops = color_stops(colors = my_color)) %>% 
  hc_legend(enabled = F)

Kondisi ritel online UK ini dalam keadaan yang cukup baik. Hampir 65% pelanggan tersebar dalam kategori pelanggan yang sering berbelanja, loyal dalam mengeluarkan uang dengan jumlah yang besar, dan responsif terhadap promo. Pelanggan-pelanggan tersebut masuk dalam segmen Champions, Loyal Customers, dan Potential Loyalist. Meskipun demikian terdapat 9% dari total pelanggan, tepatnya 389 pelanggan tergolong telah berhenti berbelanja (Lost) dan 5% pelanggan beresiko berhenti belanja (About to Sleep). Lebih dari itu, cukup disayangkan teradapat 10% pelanggan yang suka menghabiskan uang dalam jumlah besar, akan tetapi sudah lama tidak berbelanja dan beresiko churn (At Risk). Oleh karena itu, ritel online UK ini harus mengatasi sekitar 40% pelanggan yang dalam kondisi kurang baik dalam tanda kutip menguntungkan perusahaan, sembari tetap menjaga pelanggan-pelanggan yang sangat menguntungkan.

Adanya analisis perbedaan karakter dari berbagai segmen pelanggan ini dapat menjadi referensi untuk digunakan penentuan strategi yang diterapkan, istilahnya personalisasi kampanye pemasaran. Strategi pemasaran yang disesuaikan dengan karakter suatu segmen dirasa dapat meningkatkan gairah belanja pelanggan. Sebagaimana, diri kita ketika diberi makanan yang kita suka. Bayangkan saja ketika kita diberi makanan yang kita tidak suka atau bahkan alergi, maka kita akan menolaknya. Dengan demikian, mari kita tinjau lebih mendetail terkait profil segmen pelanggan dari ritel online UK ini.

Wow, hampir 60% dari semua transaksi yang terjadi di ritel online UK ini berasal dari pelanggan segmen Champions. Kemudian, 25% berasal dari Loyal Customers. Alangkah baiknya ritel online ini menerapkan strategi yang mampu menjaga loyalitas pelanggan segmen tersebut, seperti pelayan khusus untuk dapat memporelah produk-produk limited edition, dan sebagainya.

Kemudian, pada segmen-segmen yang telah berhenti belanja dan telah lama tidak melakukan belanja, mereka dapat diberikan promo khusus pada barang-barang yang mungkin mereka sukai. Untuk mengetahui produk yang pelanggan sukai, maka dapat dilakukan analisis dengan metode Collaborative Filtering.

Sejalan dengan persentase total frequency dari semua total transaksi yang terjadi, persentase total monetary dari segmen champions dan Loyal Customers mampu memberikan lebih dari 80% pendapatan yang diperoleh ritel online ini.

Business Strategy

Berikut adalah beberapa strategi yang dapat diterapkan untuk setiap kelompok pelanggan:

Champions:

  • Berfokus pada mempertahankan dan meningkatkan loyalitas mereka.
  • Tawarkan program loyalitas eksklusif atau keuntungan tambahan.
  • Kumpulkan umpan balik mereka untuk memahami lebih lanjut preferensi dan keinginan mereka.

Loyal Customers:

  • Terus berikan penawaran khusus dan promosi eksklusif.
  • Dorong partisipasi dalam program loyalitas dan program referral.
  • Pantau perilaku pembelian mereka dan sesuaikan tawaran berdasarkan preferensi.

Potential Loyalist:

  • Tingkatkan kesadaran merek melalui kampanye pemasaran khusus.
  • Tawarkan insentif tambahan untuk mendorong pembelian berulang.
  • Berikan pengalaman pelanggan yang unik untuk memperkuat koneksi.

Need Attention:

  • Identifikasi faktor yang mungkin menghambat pertumbuhan pembelian.
  • Tawarkan insentif khusus untuk meningkatkan frekuensi pembelian.
  • Kirim konten yang relevan untuk mempertahankan minat mereka.

About To Sleep:

** Buat kampanye pemasaran khusus untuk membangunkan minat. ** Tawarkan diskon atau promosi eksklusif untuk mendorong pembelian. ** Kirim pengingat tentang produk atau layanan yang mereka sukai.

At Risk:

  • Identifikasi penyebab potensial kehilangan minat.
  • Tawarkan insentif besar atau promosi spesial untuk mempertahankan mereka.
  • Hubungi langsung untuk mendapatkan umpan balik dan menyelesaikan masalah.

Lost:

  • Berusaha untuk mendapatkan kembali perhatian mereka melalui promosi khusus.
  • Kirim penawaran yang sangat menggoda untuk memulihkan kepercayaan.
  • Pelajari penyebab kehilangan dan coba perbaiki masalah tersebut.

Melalui penerapan strategi ini, ritel online UK dapat lebih efektif mengelola dan meningkatkan hubungan dengan setiap kelompok pelanggan sesuai dengan kebutuhan dan karakteristik mereka.

Note

Manajemen keuangan yang baik sangat penting untuk memastikan bahwa pemberian insentif atau diskon tidak merugikan profitabilitas ritel online UK. Berikut beberapa referensi cara untuk mengelola keuangan dan tetap untung sambil memberikan insentif kepada pelanggan:

  1. Segmentasi yang Tepat:
  • Fokuskan insentif pada kelompok pelanggan yang memberikan dampak positif terbesar pada profitabilitas.
  • Gunakan data analitik untuk mengidentifikasi segmen pelanggan yang memiliki potensi tinggi untuk pertumbuhan dan retensi.
  1. Batasi Pengeluaran:
  • Tetapkan batas maksimal untuk pengeluaran insentif atau diskon untuk setiap kampanye.
  • Evaluasi secara cermat potensi dampak finansial dari setiap inisiatif pemasaran.
  1. Program Loyalitas yang Efisien:
  • Desain program loyalitas yang memberikan nilai tambah bagi pelanggan tanpa mengorbankan margin keuntungan.
  • Pertimbangkan untuk memberikan insentif non-moneter seperti akses ke produk eksklusif atau layanan prioritas.
  1. Penawaran Berbasis Tingkat Pengeluaran:
  • Sesuaikan insentif berdasarkan tingkat pengeluaran pelanggan. Pelanggan yang menghabiskan lebih banyak dapat menerima insentif yang lebih besar.
  1. Analisis Kembali Marginalitas Produk:
  • Evaluasi profitabilitas produk atau layanan individu.
  • Prioritaskan insentif pada produk atau layanan yang memberikan margin keuntungan lebih tinggi.
  1. Kendalikan Persediaan:
  • Jaga agar persediaan tetap efisien dan hindari overstocking.
  • Diskon atau promosi dapat digunakan untuk mengelola stok yang berlebihan.
  1. Pemantauan dan Evaluasi Secara Berkala:
  • Lakukan pemantauan dan evaluasi secara berkala terhadap efektivitas kampanye dan insentif.
  • Sesuaikan strategi berdasarkan hasil dan feedback pelanggan.
  1. Strategi Penetapan Harga yang Cermat:
  • Terapkan strategi penetapan harga yang bijaksana, termasuk penetapan harga diferensial untuk pelanggan berbeda.
  • Pertimbangkan penyesuaian harga yang strategis selama periode promosi.

Potential Advanced Analysis

Terdapat serangkaian metode analisis yang dapat dikembangkan dan dilakukan untuk semakin mengembangkan ritel online UK ini:

  1. Market basket Analysis: Melalu analisis ini, ritel online UK dapat menyediakan bundling package dengan promo tertentu untuk meningkatkan pembelian dan melakukan cross selling.

  2. Personalized Product Recommendations based on Collaborative Filtering: Strategi bisnis sebelumnya, seperti insentif dan promo alangkah baiknya diberikan terhadap produk yang benar-benar diinginkan atau disukai oleh pelanggan. Hal itu dapat dicapai dengan melakukan metode analisis Collaborative Filtering.

  3. Time Series Analysis: Meneliti pola dan tren dalam data transaksi sepanjang waktu. Ini membantu dalam memahami bagaimana perilaku pembelian berubah seiring waktu, misalnya, apakah ada peningkatan penjualan pada musim tertentu.

  • Demand analysis: Untuk membantu menyiapkan stok produk, juga membantu inventory management.
  • Customer Life Time Value Analysis: Mengoptimasi penentuan perlakuan bisnis selain dari RFM analisis.