RFM Analizi ile Müşteri Segmentasyonu
Merhaba VBO okuyucuları!
Bu yazımda sizlere, müşteri segmentasyonu ve analizinde yaygın bir kullanımı olan RFM analizinden bahsedeceğim. Bir önceki yazımda yine e-ticaret verisi üzerinde belli analizler yapıp, veriyi incelemiştik. Yazıya buradan ulaşabilirsiniz: https://www.veribilimiokulu.com/e-ticaret-veri-analizi/
RFM nedir?
Recency, Frequency, Monetary kelimelerinin baş harflerinden oluşup, bu üç metriğin hesaplanmasından sonra birleştirilmesiyle meydana gelen bir skordur. Müşterilerin mevcut durumunun analiz edilip, bu skorlara göre segmentlere ayrılmasına yardımcı olur.
Recency: Müşterinin ne kadardır websitesinden/mağazadan hizmet aldığı, ne zamandır bize üye olduğu gibi bilgileri verir. Hesaplanması genellikle, bugünden son üyelik tarihi/son sipariş tarihinin çıkartılmasıyla elde edilir.
Frequency: Müşterinin ne sıklıkla alışveriş yaptığını, ne sıklıkla siteye giriş yaptığını gösteren metriktir. Genellikle sipariş numarası/sipariş kodunun saydırılmasıyla sonuç verir.
Monetary: Müşterinin harcamalarının toplamıdır. E-ticaret sitesine getirdiği ciro, aldığı hizmetler sonrası toplanan getiri olarak da tanımlanabilir. Ciro tanımı ne ise, müşteri bazında hayatı boyunca yapılan harcamalar toplanarak hesaplanır.
Son zamanlarda, ‘Tenure’ kavramına da yeni bir metrik olarak RFM analizlerinde yer verilmeye başlandı. Tenure ise, müşterinin e-ticaret sitesi/mağaza ile ilk kontağından bu yana geçen zaman olarak geçer. Bugünden minimum kontak tarihi çıkartılmasıyla bulunabilir.
Bu metrikler belirlendikten sonra, metrik bazında müşteri verisi 5 eşit parçaya ayrılır. Sonrasında bu rakamlar bir araya getirilerek bir RFM skoru atanır.
Şimdi bu analizin Python üzerinde uygulamasını gösterelim.
UCI Machine Learning Repository veritabanından ‘Online Retail II Data Set’ isimli veriyi yükleyip işleme başlıyoruz. https://archive.ics.uci.edu/ml/datasets/Online+Retail+II
#Kütüphaneleri yüklüyoruz import pandas as pd import numpy as np import matplotlib.pyplot as plt import datetime as dt import seaborn as sns #Veriyi yüklüyoruz data = pd.read_csv('data2.csv',encoding = 'unicode_escape') #Toplam harcamayı sütun olarak ekliyoruz data['TotalPrice'] = data['Price']*data['Quantity'] #Sipariş tarihinin veri tipini değiştiriyoruz data['InvoiceDate'] = pd.to_datetime(data['InvoiceDate']) #Bugünü/ analiz tarihini değişken olarak belirliyoruz today = dt.datetime(2012,1,1) print(today) #0'dan büyük değerleri alıyoruz. data = data[data['Quantity'] > 0] data = data[data['TotalPrice'] > 0]
#Recency ve Monetary değerleri buluyoruz. data_x = data.groupby('Customer ID').agg({'TotalPrice': lambda x: x.sum(), 'InvoiceDate': lambda x: (today - x.max()).days}) #Data StockCode bazında olduğu için, InvoiceNo'yu unique hale getiriyoruz. data_y = data.groupby(['Customer ID','Invoice']).agg({'TotalPrice': lambda x: x.sum()}) #Saydırdığımızda InvoiceNo unique halde gelmiş oluyor. data_z = data_y.groupby('Customer ID').agg({'TotalPrice': lambda x: len(x)}) #RFM tablosuna ulaşmış oluyoruz. rfm_table= pd.merge(data_x,data_z, on='Customer ID') #Sütun isimlerini belirliyoruz rfm_table.rename(columns= {'InvoiceDate': 'Recency', 'TotalPrice_y': 'Frequency', 'TotalPrice_x': 'Monetary'}, inplace= True)
#Frequency bulma def RScore(x,p,d): if x <= d[p][0.20]: return 0 elif x <= d[p][0.40]: return 1 elif x <= d[p][0.60]: return 2 elif x <= d[p][0.80]: return 3 else: return 4 quantiles = rfm_table.quantile(q=[0.20,0.40,0.60,0.80]) quantiles = quantiles.to_dict() rfm_table['Freq_Tile'] = rfm_table['Frequency'].apply(RScore, args=('Frequency',quantiles,)) #Recency bulma rfm_table = rfm_table.sort_values('Recency',ascending=True) rfm_table['Rec_Tile'] = pd.qcut(rfm_table['Recency'],5,labels=False) #Monetary bulma #rfm_table.sort_values('Monetary',ascending=False) rfm_table['Mone_Tile'] = pd.qcut(rfm_table['Monetary'],5,labels=False) #'Sıfır' değeri yer almasın istiyorsak, bulduğumuz değerleri 1 arttırıyoruz rfm_table['Rec_Tile'] = rfm_table['Rec_Tile'] + 1 rfm_table['Freq_Tile'] = rfm_table['Freq_Tile'] + 1 rfm_table['Mone_Tile'] = rfm_table['Mone_Tile'] + 1 #Bulduğumuz değerleri birleştirip tek bir skor elde ediyoruz rfm_table['RFM Score'] = rfm_table['Rec_Tile'].map(str) + rfm_table['Freq_Tile'].map(str) + rfm_table['Mone_Tile'].map(str) rfm_table.head()
#Değerlerin içeriklerini inceliyoruz. rfm_table.groupby('RFM Score').agg({ 'Recency': ['mean','min','max','count'], 'Frequency': ['mean','min','max','count'], 'Monetary': ['mean','min','max','count'] }).round(1).head()
Bu şekilde, segmentasyon işlemi aslında sonlanmış oluyor. Örneğin 121 segmentini yorumlayacak olursak,
- bu segmentte 22 kişi bulunmakta,
- ortalama olarak en son alışverişleri 31 gün önce gerçekleşmiş,
- alışveriş sıklıkları 2, yani 2 alışverişleri var,
- 209 dolar/TL harcamaları olmuş.
Kimi zaman bu metrikler arasında ağırlıklandırma yapıldığını görüyoruz. Bir şirket için parasal değer daha önemli olabilir, bu durumda mesela, %60 parasal değer, %20 recency değeri, %20 frequency değeri ile çarpıp, ortak bir skor elde edilebilir. Ya da, bu skorlar ile kmeans yapılıp, daha akıllı segmentler elde edilebilir. Bunun gibi kararlar şirketteki ilgili kişiler ile tartışılıp ortak bir karara varılması gereken durumlardır. Bazı kabuller, kurallar belirlenerek, segmentasyon kuralları dönüştürülebilir.
Yorumlarınız ve sorularınız için şimdiden teşekkürler!
Merhabalar;
Kimi zaman bu metrikler arasında ağırlıklandırma yapıldığını görüyoruz. Bir şirket için parasal değer daha önemli olabilir, bu durumda mesela, %60 parasal değer, %20 recency değeri, %20 frequency değeri ile çarpıp, ortak bir skor elde edilebilir. Ya da, bu skorlar ile kmeans yapılıp, daha akıllı segmentler elde edilebilir. Bunun gibi kararlar şirketteki ilgili kişiler ile tartışılıp ortak bir karara varılması gereken durumlardır. Bazı kabuller, kurallar belirlenerek, segmentasyon kuralları dönüştürülebilir.
Burda %60 parasal değer, dediğimizde monetary değeri mi çarpılır? yoksa monetary skoru u çarpılır?
R, F, M değerlerinin çeyreklerini bulurken neden buluruz? Biz burada hangi koşullara dayanarak [.2 , .4 , .6 , .8] bu şekilde böldük?
[0,25 , 0,50 , 0,75 ,1]’ e bölmedik?
Yardımlarınız için teşekkür ederim.