RFM Analizi ile Müşteri Segmentasyonu + Proje

Saltuk Bugra Karacan
7 min readJul 16, 2020

Merhaba, yeni bir konu ve projeyle karşınızdayım. Konumuz, RFM analizi ve müşteri segmentasyonu. Bir önceki yazımda olduğu gibi önce tanımlar daha sonra terimler ve en son da proje olacak şekilde ilerleyeceğiz.

Müşteri Segmentasyonu Nedir?

Başarılı bir pazarlama için müşterilerimizi iyi tanımamız gerekir. Müşterilerimizi iyi tanımamız için de onları segmentlere, bölümlere ayırmamız gerekir. Müşterilerimizi iyi tanırsak ve ne isteyebileceklerini bilirsek, onları mutlu ederek kendimize bağlayabiliriz. İşte müşterilerimizi segmentlere ayırarak onları bir grubun içine sokma işine müşteri segmentasyonu denir.

Tam bu noktada müşterilerimizi segmentlere ayırmakta bize yardımcı olacak bir analizden bahsedeceğim: RFM Analizi.

RFM Analizi Nedir?

RFM’de gördüğümüz bu 3 harf RFM analizinin önemli terimleridir.

R: Recency (yenilik, yeni olma durumu, yakın zamanda olan)

F: Frequency (sıklık)

M: Monetary (parasal, para ile ilgili)

anlamına gelir.

Müşterilerimizin yaptığı aksiyonlara göre bu 3 değere 1 ile 5 arasında değerler veririz ve onları aşağıda gördüğünüz tabloya göre segmentlere ayırırız.

rfm analizi ve müşteri segmentasyonu

Recency (Yenilik)

Kısaca, müşterimizin alışveriş yaptığı son gün üzerinden geçen süredir.

Yakın zamanda alışveriş yapmış olan bir müşteri, bizim için Recency skoru yüksek bir müşteridir. Yakın zamanda alışveriş yapmış olan müşterilerimizin Recency skoru 5, Son alışverişini çok uzun zaman önce yapmış olan müşterilerimizin Recency skoru 1 olur.

Frequency (Sıklık)

Müşterimizin bu zamana dek yaptığı alışverişlerin sayısı ile sıklık skorunu ölçmüş oluruz.

Alışveriş sayısı yüksek olan müşteri, bizim için Frequency skoru yüksek bir müşteridir. Alışveriş sayısı fazla olan müşterilerimizin Frequency skoru 5, Alışveriş sayısı az olan müşterilerimizin Frequency skoru 1 olur.

Monetary

Müşterilerimizin yaptığı alışverişlerde bıraktığı para miktarıdır.

Bıraktığı para miktarı çok olan müşteri, bizim için Monetary skoru yüksek bir müşteridir. Bıraktığı para miktarı yüksek olan müşterilerimizin Monetary skoru 5, bıraktığı para miktarı az olan müşterilerimizin Monetary skoru 1 olur.

Recency, Frequency, Monetary

Monetary değeri genelde yukarıda da gördüğünüz gibi segmentler tablosunda yer almaz. Bu tabloya hangi 2 değeri koyacağınızı yapacağınız işe ve çalışacağınız sektöre göre belirleyebilirsiniz.

Örneğin; bir otelin RFM analizini yapıyorsanız, Recency (yenilik) değeri yerine Monetary değerine bakabilirsiniz.

Çünkü; Turizm sektörü belirli dönemlerde daha yoğun olan bir sektör olduğu için, müşterilerimizin ne kadar süre önce otelimize gelmiş olduğundan ziyade ne kadar para harcamış olduğu bizi daha çok ilgilendirir.

Yukarıdaki tabloya göre segmentler hakkında aksiyon stratejileri oluşturabilirsiniz. Örneğin “Can’t Lose Them” segmentindeki müşterilerimiz bizden normalde sık sık alışveriş yapan (Frequency skoru 5) ama uzun süredir bizden alışveriş yapmamış (Recency skoru 1–2) olan müşterilerdir. Bu segmentler bu şekilde yorumlanır ve müşterilerin bu durumlarına göre çeşitli aksiyon planları (hediyeler, indirimler vs.) oluşturulabilir.

Proje kısmına geçerken şunu belirteyim, bu kısımda sadece RFM Analizini yapmak için gerekli olan kısmı göstereceğim. Github profilimde paylaştığım projede RFM kısmına geçmeden önce Pandas ile biraz oyun oynuyoruz :) (en çok sipariş veren ülkeleri getirme, en çok sipariş edilen ürün isimlerini getirme vs. gibi bir sürü işlem var.).

Eğer bu tür analizleri çıkarmak ilginizi çekerse projenin tamamına buraya tıklayarak gidebilirsiniz.

Şimdi projeye geçelim.

import pandas as pd
import numpy as np
#gerekli kütüphaneleri import etme işlemi

df_2010_2011 = pd.read_excel("online_retail_II.xlsx", sheet_name = "Year 2010-2011")
#veri setimiz excel dosyasında bulunduğu için read_excel fonksiyonunu kullandık.
"sheet_name" parametresini kullanmamızın sebebi elimdeki veri seti tek sayfa değil ve ben "Year 2010-2011" isimli sayfanın içindeki verileri kullanıyorum. (Eğer bu veri setini başka bir yerden bulduysanız 2 sayfalık excel şeklinde olmayabilir o halde "sheet_name" parametresini kaldırabilirsiniz.)
“Year 2010–2011” sayfasını kullandığımızı belirtmek için “sheet_name” parametresini kullanırız.
df.head() #ilk 5 satırı getiren kod bloğu
Veri setinin ilk 5 satırı
df["TotalPrice"] = df["Quantity"]*df["Price"]
#TotalPrice(ToplamFiyat) adında yeni bir sütun(column) oluşturulur ve her satırın Quantity(miktar) ve Price(fiyat) değeri çarpılır. Tahmin ettiğiniz gibi buradan faturadaki alınan o ürünün toplam tutarını elde ederiz. ve yine tahmin edebileceğiniz gibi bu değeri monetary değerini bulurken kullanacağız.
df.head() #kontrol için ilk 5 satırı getirelim.

Gördüğünüz gibi her satırın TotalPrice değeri, o satırdaki Quantity ve Price değişkenlerinin çarpımıdır. İlk satırımızın Quantity değeri 6, Price değeri 2.55. Çarparsak 6 * 2.55 = 15.3 TotalPrice değişkenindeki değerin 15.3 olduğunu görebilirsiniz ilk satır için.

df.isnull().sum()
#tüm sütunlarda bulunan boş(na) verilerin sayısını ayrı ayrı getirir.
df.dropna(inplace = True) 
#bütün boş veri bulunduran satırları toptan siler. Yani elimizdeki veri setinden 135080+1454 satır silinir.

Recency

df["InvoiceDate"].min() 
#bu veri setindeki en eski tarihli invoice(fatura)nin tarihini getirir.
En eski tarihli faturanın tarihi
df["InvoiceDate"].max()
#bu veri setindeki en yeni tarihli faturanın tarihini getirir.
En yeni tarihli faturanın tarihi
import datetime as dt
#tarih ile ilgili işlemleri yapabileceğimiz kütüphaneyi import ediyoruz.
today = dt.datetime(2011,12,9)
#bugünün tarihini "today" değişkenine atıyoruz. Bugünün tarihi 2011,12,9 değil ama en yeni faturanın tarihi bu tarihte olduğu için ona yakın olsun diye böyle bir atama yaptım.
İstersem bugünün tarihini de atayabilirim çok önemli bir değişiklik olmaz. Sadece son alışveriş üzerinden geçen gün sayısı çok yüksek olur.df["Customer ID"] = df["Customer ID"].astype(int)
#yukarıda dikkatinizi çektiyse dataframe içinde bulunan "Customer ID" değeri float ve rahatsız edici görünüyor diye integer değere çevirdim. Proje için çok önemli bir yeri yok.

Şimdi bu kısıma dikkat edin. Son alışveriş üzerinden geçen zamanı bulacağız.

temp_df = (today - df.groupby("Customer ID").agg({"InvoiceDate":                    "max"}))#bugünün tarihinden her müşterinin en yeni fatura tarihini (yani en yeni alışveriş tarihini) çıkarır.#Burası önemli bir nokta. Bu kod bloğunu parça parça ele alırsak:df.groupby("Customer ID").agg({"InvoiceDate":"max"})bu kod diyor ki: bütün Customer ID(müşteri no)leri grupla, ve o customer id'ye ait en yeni faturanın tarihini getir.temp_df #yukarıda oluşturduğumuz dataframeyi getirir.
Müşterilerin son alışverişleri üzerinden geçen gün sayısı. Soldaki sayılar müşteri numaralarıdır yani her numara belirli bir müşteriyi temsil ediyor. (T.C. kimlik numarası gibi düşünebilirsiniz.)
temp_df.rename(columns={"InvoiceDate":"Recency"},inplace=True)
#Yukarıdaki görselde gördüğünüz InvoiceDate değerinin ismini Recency yapar.
recency_df = temp_df["Recency"].apply(lambda x: x.days)
#bu kod bloğu, recency değerini sadece güne çevirir. Yani "324 days 13:43:00" değerini yalnıza 324 yapar.
recency_df.head()
Yukarıdaki 324 days 13:43:00 değeri gitti yerine yalnızca 324 değeri geldi.

Frequency

freq_df = temp_df.groupby("Customer ID").agg({"Invoice":"count"})
#Müşteri numaralarını listele ve o müşterilere ait bütün faturaları say.
freq_df #yukarıda oluşturduğumuz freq_df tablosu
freq_df.rename(columns={"Invoice":"Frequency"},inplace = True)
#freq_df tablosunun "Invoice" sütununun adını değiştirip "Frequency" yap.
freq_df #freq_df tablosu
aynı tablonun sütun adının değişmiş hali.

Monetary

monetary_df = df.groupby("Customer ID").agg({"TotalPrice":"sum"})
#Müşteri numaralarına ait bütün TotalPrice değerlerini toplar.
monetary_df.rename(columns={"TotalPrice":"Monetary"},inplace=True)
#TotalPrice sütununun adını Monetary yapar.
monetary_df.head() #monetary_df tablosunun ilk 5 satırı.
12346 numaralı müşterinin toplam harcaması 0.00 gözüküyor. Bunun sebebi yukarıda bu müşteriye ait olan 2 faturanın birisi iade faturası. Bunu veri setine göz atınca gördüm.

RFM Tablosu

rfm = pd.concat([recency_df,freq_df,monetary_df],axis=1)
#Yukarıdaki başlıklarda tek tek oluşturduğumuz recency_df, freq_df ve monetary_df tablolarını birleştirip tek bir tablo oluşturur.
rfm #rfm tablosunu gösterir
Her müşterinin tek tek Recency, Frequency ve Monetary değerleri hesaplandı.
rfm["Recency Score"] = pd.qcut(rfm["Recency"],5,labels = [5,4,3,2,1])rfm["Frequency Score"] = pd.qcut(rfm["Frequency"].rank(method="first"),5,labels = [1,2,3,4,5])rfm["Monetary Score"] = pd.qcut(rfm["Monetary"],5,labels = [1,2,3,4,5])#Yukarıda rfm tablosuna 3 yeni sütun ekledik. Bu 3 sütun qcut fonksiyonu sayesinde Recency, Frequency ve Monetary tablosu altında bulunan bütün değerleri 5 ayrı gruba ayırdı.rfm.head()
İlk müşteriye bakalım yine: son alışverişi üzerinden 324 gün geçen müşterinin recency değeri 1. Çünkü uzun zaman olmuş düşük puan almalı | Toplam yaptığı alışveriş sayısı 2 bu da ona 2 Frequency score veriyor | Harcadığı para miktarı 0.00 (iade etmişti) düşük olduğu için monetary score olarak da 1 puanı hakediyor.

Müşterimizin Recency, Frequency ve Monetary puanları sırasıyla 1, 2, 3 ise bu müşterimizin RFM puanı 123 olur. RFM puanı bu şekilde bulunur.

rfm["RFM SCORE"] = rfm["Recency Score"].astype(str) + rfm["Frequency Score"].astype(str) + rfm["Monetary Score"].astype(str)#R, F ve M skorlarını tek tek stringe çevirip topladık ve bize her müşterinin RFM skorlarını vermiş oldu.rfm.head()
En sağa RFM skorları da eklendi
seg_map = {  r'[1-2][1-2]': 'Hibernating', 
r'[1-2][3-4]': 'At Risk',
r'[1-2]5': 'Can\'t Loose',
r'3[1-2]': 'About to Sleep',
r'33': 'Need Attention',
r'[3-4][4-5]': 'Loyal Customers',
r'41': 'Promising',
r'51': 'New Customers',
r'[4-5][2-3]': 'Potential Loyalists',
r'5[4-5]': 'Champions' }
#Tabloda belirtilen segmentleri yerleştirmek için bu regex komutlarını kullanacağız."Yukarıdaki görselde de görüldüğü gibi müşterimizin R ve F skorları 1 veya 2 değerlerini alıyorsa "Hibernating" segmentine aittir." Şeklinde yorumlanır bu regex komutları
rfm['Segment'] = rfm['Recency Score'].astype(str) + rfm['Frequency Score'].astype(str)
rfm['Segment'] = rfm['Segment'].replace(seg_map, regex=True)
#Bu kod blokları RF skorlarını oluşturup regex komutlarına göre segmentlere ayırtır.
rfm.head()
Gördüğünüz gibi bütün müşterilerin R, F, M, RFM skorları ve segmentleri teker teker bulunmuş oldu.

Artık müşterilerinizi nasıl filtrelemek istiyorsanız gerekli işlemleri yapabilirsiniz. Eğer benim bu yazıda yer vermediğim filtrelemeleri görmek isterseniz Github’daki projeme buraya tıklayarak gidebilirsiniz.

Bu proje, Pandas konusunda fazla antrenmanlı olmayan kişilere biraz zor gelebilir. Proje hakkında aklınıza takılan en ufak bir nokta dahi varsa bana LinkedIn’den buraya tıklayarak ulaşabilirsiniz.

Kaggle hesabımdan da aynı şekilde projeye buraya tıklayarak ulaşabilirsiniz. (Kaggle’da bulunan veri seti bilgisayarıma indirdiğimden biraz daha farklıydı ufak farklılıklar olabilir ama %90 aynı proje)

--

--

Saltuk Bugra Karacan

M. Sc. Informatics @ Technical University of Munich | AI Engineer WS @ Retorio