Python ile RFM Analizi
RFM kelimesinin açılımı recency (güncellik), frequency (sıklık), monetary (parasal) anlamlarına denk gelmektedir. RFM analizinde ölçümlemek istenen müşterinin hesaplanan segment içerisindeki ürüne ya da hizmete satın almasındaki ya da kullanımdaki davranış hareketlerinin analiz etmektir. Analiz temelde müşterilerin geçmişteki satın alma davranışlarına bakarak ilerlemektedir. Ne kadar güncel, ne kadar sık ya da ne kadar para harcadı gibi sorular ile RFM analizinin çerçevesini oluşturabiliriz.
Python programa dilinin pazarlama alanında kullanımı ile ilgili aşağıdaki yazıma bir göz gezdirebilirsiniz.
RFM hangi müşterinin kurum için daha değerli olduğunu söyleyebilir. Potansiyel müşteri bularak doğrudan kar etmeye yönelik stratejik adımlar atılmasını sağlayabilir. Aşağıda RFM kelimesinin oluşturan harfleri tek tek açıklayalım.
- Recency (Güncellik): Recency kavramında bir müşterinin en son ne zaman hizmeti ya da ürünü satın aldığı bilgisi yer almaktadır. Gün bazında hesaplanmakta olup müşterinin en son temas ettiği gün ile bugün arasındaki gün farkı alınır.
- Frequency (Sıklık): Müşteri ne kadar sıklıkla alışveriş yapıyor. Toplam işlem sayısının yer aldığı özelliktir.
- Monetary (Parasal): Müşterilerin harcama hacimlerinin yer aldığı değişkendir.
Temel olarak bu üç değişken üzerinden RFM skoru üretilmektedir. Her bir değişken içinde eşit sayıda müşteri adedine denk gelecek (quartile) 4 adet çeyrekliğe bölünerek bu işlem yapılıyor. Çeyreklik yani quartile mantığı aşağıdaki tabloda yer almaktadır.
Tablo 1'de görüldüğü üzere müşteri sayısına göre veri seti 4 parçaya ayrılmıştır. Çeyreklikler ayrılırken önce medyan bulunur. İkiye bölünen veri seti tekrar medyan ile ikiye bölünerek 4 eşit parçaya ayrılmış olur. Tablo 1'de görüldüğü üzere medyan tam orta kalırken, ortalama ise 3. çeyrek sınırında görülmektedir. Aslında son çeyrekte anormal artan tutarlar yüzünden ortalamayı da yüksek görmekteyiz. Buradan yola çıkarak bile sıra dışı verileri (outleir detection) yakalayabiliriz.
Yukarıdaki tablodan yola çıkarak “Hesap Tutar” yerine RFM’in 3 değişkeni/kolonu olduğunu düşünelim. Bu üç değişkenin her birisi için 4 çeyreklik hesaplanacak dolayısıyla 4 x 4 x 4 ile ifade etmemiz gerekirse 64 adet farklı kombinasyonda müşteri grubuna ulaşmış oluyoruz.
RFM hesaplama mantığına adım adım bakalım:
- Her bir müşteri için tek tek Recency, Frequency, Monetary değerleri hesaplanır.
- Çeyrekliklerden yola çıkarak her bir değişkene karşılık gelen çeyreklik değeri (İlk çeyrek için 1, ikincisi için 2 …) yani diğer adı ile “bin” tabloya eklenir.
- Tabloya eklenen bu 3 bin değeri yan yana olacak şekilde birleştirilir. Zaten her bir değişken için en az 1 en fazla 4 değeri alacağı için RFM skoru 111 ile 444 arasında bir değerden oluşmaktadır. Aşağıda yer alan tablo 2'den hesaplanma mantığını inceleyebilirsiniz.
Tablo 2'de görüldüğü üzere 1 numaralı müşterinin RFM elementleri hesaplanmış ve çeyreklikleri çıkarılmıştır. Ardından bu çeyrekliklerden çıkarılan bin değerleri birleştirilerek 4 & 1 & 1 RFM skoru hesaplanmıştır.
Python’da Uygulamalı RFM Analizi
Bu uygulamaya ait kod ve dataya GITHUB sayfam üzerinden erişebilirsiniz. Veri seti işlem (transaction) bazlı olup müşterinin satın alma geçmişini göstermektedir. Veri setindeki değişkenlerin açıklaması.
- Customer_id: Müşteriye ait tekil bir numara — ID
- Date: Müşterinin ürünü satın aldığı tarih
- Amount: Müşterinin satın aldığı tarihte ödediği ücret
- Bought: Satın alınan işletim sistemi olarak düşünülebilir
Öncelikle gerekli kütüphaneleri yükleyip datayı içeri alalım.
import pandas as pd
import datetime as dt
import numpy as np
import matplotlib.pyplot as plt
pd.set_option("display.max_columns",100)
df = pd.read_csv("DATA_SOURCE/rfmUsingData.csv",
sep=";",
decimal=',',
parse_dates=["Date"])
print(f"Satır sayısı {df.shape[0]} ve kolon sayısı {df.shape[1]}")
# ÇIKTI: Satır sayısı 635 ve kolon sayısı 4
df.head() # ilk beş satırı gösterir
Kodda görüldüğü üzere datayı Pandas dataframe yapısına dönüştürürken CSV dosyasında verileri ayırt edebilmesi için “sep = ;” kullanılmıştır. Ayrıca yine dosya içerisinde tutar kısmı “,” ile ayrıldığı için onu batı versiyonu olan “.” olarak dönüştürülmüş olup tarih kolonunun dataframe yapısına uyarlanması için “parse_dates” parametresine tarih alanı tanımlanmıştır. Genel olarak datayı inceleyeceğimiz kodu yazalım.
Tekil müşteri sayısına bakalım.
len(df["Customer_id"].unique())
# ÇIKTI: 117
635 işlem satırı içeren veride 117 tekil müşteri bulunuyor. Satın alınan ürüne dair ayrıntıların yer aldığı Bought değişkenine incelediğimizde…
df["Bought"].value_counts()
# ÇIKTI:
# Android 399
# Apple 232
# Windows Phone 4
Windows Phone satın alan çok az. Ancak bu durum müşterinin satın aldığı gerçeğini değiştirmeyeceği için veriden çıkarmamıza gerek yok. Harcanan tutar sürekli ve sayısal bir değer olduğu için betimleyici istatistiklerine aşağıdaki şekilde bakabiliriz.
df["Amount"].describe()
# ÇIKTI:
# count 635.000000
# mean 20.192898
# std 12.030023
# min 0.140000
# 25% 9.565000 1.quartile
# 50% 20.160000 (medyan)
# 75% 28.800000 3.quartile
# max 48.890000
Medyan ile ortalama (mean) arasında çok fark olmaması verinin normal dağıldığına dair bize ufak bir ipucu veriyor. Tarih yani harcama yapılan zamanın başlangıcından bugününe kadar olan dağılımına bir bakalım.
plt.style("ggplot")
plt.hist(df['Date'],bins=10,)
plt.grid(alpha=0.75)
plt.xlabel("Tarih")
plt.ylabel("İşlem Adet")
plt.show()
Şekil 1'de yer alan histogram incelendiğinde satın alma işlemlerinin 1992 ile 2012 arasında olduğunu görmekteyiz. Ancak 2010 sonrası işlem hacminin düşük olması sebebiyle son 2–2.5 yılı datadan çıkarabiliriz. Öncelikle eski tarihten bugüne gün farkını alarak RFM’in ilk elementi olan “Recency” bulalım.
sonTarih = dt.datetime(2012,5,4)
df['Gun_farkı'] = sonTarih - df['Date']
df['Gun_farkı'].astype('timedelta64[D]')
df['Gun_farkı'] = df['Gun_farkı'] / np.timedelta64(1, 'D')
df.head()
Gün farkının dağılımına bakarak şekil 1'de gördüğümüzün teyidini alalım.
plt.hist(df['Gun_farkı'])
plt.grid(alpha=0.75)
plt.xlabel("Gün Farkı")
plt.ylabel("İşlem Adet")
plt.show()
Şekil 2'de görüldüğü üzere son 1000 gün yani yaklaşık 2–2.5 senelik kısımda fazla bir işlem sayısı olmadığından veri setinden çıkarıyoruz.
df = df[df['Gun_farkı'] >= 1000]
print(f"Satır sayısı: {df.shape[0]}")
# ÇIKTI: Satır sayısı 626
Son 1000 günü dahil etmediğimizde veri adedi 635'den 626'ya düşüyor. Bu veri seti için büyük bir kayıp anlamına gelmez.
RFM değişkenlerinin ana bileşenleri olan recency, frequency, monetary değişkenlerini müşteri bazında diğer kolonların ortalamasını alarak hesaplayalım.
rfmTable = df.groupby('Customer_id').agg(
{'Gun_farkı': lambda x:x.min(), # Recency
'Customer_id': lambda x: len(x), # Frequency
'Amount': lambda x: x.sum()}) # Monetary Value
rfmTable.rename(columns=
{'Gun_farkı': 'recency',
'Customer_id': 'frequency',
'Amount': 'monetary_value'},
inplace=True)
rfmTable.head()
Yapılan işlemde müşteri numarası bazında, bir müşterinin en son satın alma tarihinin gün farkı (recency), yapılan işlem adedi için müşteri numarası saydırılmış (frequency) ve harcama tutarı müşteri bazlı olarak toplanmıştır (monetary). Ardından kolon isimleri değiştirilerek “rfmTable” adında yeni bir tablo oluşturulmuştur.
Tablo 3'de görüldüğü üzere tekil müşteri bazında değerler hesaplanarak RFM skoru için hazırlık adımlarının atılmasını sağlayan tablo oluşturulmuştur.
Hesaplanacak değerlerden sonra yukarıda bahsedilen çeyreklikleri (quartiles) bulmak için Pandas kütüphanesindeki “quantile” fonksiyonu kullanılmıştır. Bu fonksiyondan çıkan değerleri ise daha sonraki işlemler için bir sözlük formatına dönüştürülmektedir.
quart = rfmTable.quantile(q=[0.25,0.50,0.75])
quart
Tablo 4'de görüldüğü üzere üç değişken içinde çeyreklik değerleri çıkarılmıştır. Önce bu değerleri bir sözlük formatında tutup arından çeyreklik değerlerini RFM skoru hesaplamak için müşteri bazlı olarak yazdıralım.
quart = quart.to_dict()
print(quart)
{
'recency':
{
0.25: 2131.0,
0.5: 3032.0,
0.75: 4170.0
},
'frequency':
{
0.25: 4.0,
0.5: 5.0,
0.75: 6.0
},
'monetary_value':
{
0.25: 79.61,
0.5: 104.04,
0.75: 134.9
}
}
# Recency için çeyrekliğe göre sınıfların belirlenmesi
def RClass(x, p, d):
if x <= d[p][0.25]:
return 1
elif x <= d[p][0.50]:
return 2
elif x <= d[p][0.75]:
return 3
else:
return 4
# Frequency ve Monetary için çeyrekliğe göre sınıfların belirlenmesi
def FMClass(x, p, d):
if x <= d[p][0.25]:
return 4
elif x <= d[p][0.50]:
return 3
elif x <= d[p][0.75]:
return 2
else:
return 1
rfmSeg = rfmTable
rfmSeg['R_Quartile'] = rfmSeg['recency'].apply(RClass, args=('recency', quart,))
rfmSeg['F_Quartile'] = rfmSeg['frequency'].apply(FMClass, args=('frequency', quart,))
rfmSeg['M_Quartile'] = rfmSeg['monetary_value'].apply(FMClass, args=('monetary_value', quart,))
Yukarıdaki fonksiyonların ardından çeyrekliklere göre oluşan değerler tabloya aktarılmıştır. Son adımda bu değerler yan yana yazılarak RFM skoru belirlenmektedir.
rfmSeg['RFMScore'] = rfmSeg.R_Quartile.map(str) \
+ rfmSeg.F_Quartile.map(str) \
+ rfmSeg.M_Quartile.map(str)
rfmSeg.head()
Tablo 6'da da görüldüğü üzere RFM skorunu yazdırılmıştır. Artık bu noktadan sonrası analizi yorumlamanıza kalıyor. Yaratılan müşteri bazlı tabloda skora göre sıralayarak ilgili kampanyaları yapabilir pazarlama stratejilerine katkı sağlayacak bilgiler çıkarabilirsiniz.