RFM ile Müşteri Segmentasyonu

Barış Kavuş
5 min readJan 22, 2021

--

Merhaba!

Bu yazıda RFM ile müşteri segmentasyonu projesini ele alacağız.

Pazarlama stratejileri müşteri odaklıdır. Bu nedenle başarılı bir pazarlama için müşterilerimizi çok iyi tanımamız gerekmektedir. Bunun için RFM yöntemini kullanacağız.

Peki RFM nedir?

Recency, Frequency, Monetary = RFM!

Recency: Müşterilerin son satın alma tarihinden bugüne kadar geçen süre,

Frequency: Sıklık -frekans,

Monetary: Toplam ödenen para miktarı, anlamlarına gelmektedir.

Bu değerlerin belirli bir skalada skorlanması ve gruplara ayrılmasına ise müşteri segmentasyonu denir. Genelde 1–5 arası skorlama yapılır fakat sektöre göre değişiklik gösterebilir.

Tabloya ufak bir göz gezdirdiğimizde Recency değeri 5, Frequency değeri 5 olan müşteriler “Champions” grubunda yer alıyor. Yani bu grup en sık alışveriş yapan ve son alışveriş tarihleri günümüze en yakın olan gruptur yorumu yapılabilir.

Burada görüldüğü gibi Monetary değeri segment tablosunda yer almaz. Segmentler genelde Recency ve Frequency değerlerine göre oluşturulur. Fakat skorlama skalasında olduğu gibi yine sektöre göre bu durum değişliklik gösterebilir.

Peki skorlamaları nasıl yapıyoruz dediğinizi duyar gibiyim :)

Bir müşterinin Recency değeri yüksek ise bu müşterinin puanı düşük olacaktır. Yani son alışveriş tarihi uzaklaştıkça skoru düşecektir. Frequency ve Monetary değerleri yüksek olan kişilerin skorlarının ise yüksek olması beklenir.

Toparlayacak olursak, RFM analizi ile müşterilerimizi segmentlere ayırabilirsek bu segmentlerde yer alan müşterilerin alışkanlıklarına göre gerekli aksiyonları doğru bir şekilde alabiliriz.

Şimdi projemize geçelim.

1. Veri Seti Hikayesi

Veri seti İngiltere merkezli online hediyelik eşya satan bir mağazanın 2009–2011 arasındaki satışları içeriyor. Müşterilerin çoğunluğunun toptancı olduğu söylenebilir. Aşağıdaki linkten indirebilirsiniz.

https://archive.ics.uci.edu/ml/datasets/Online+Retail+II

İndirmiş olduğumuz excelde 2 sayfa mevcut. (2009–2011 ve 2010–2011) Bu projede 2010–2011 yılları arasındaki satışları ele alacağız.

Değişkenlerimiz;

InvoiceNo: Fatura numarası. Her işleme yani faturaya ait eşsiz numara. Eğer bu kod C ile başlıyorsa işlemin iptal edildiğini ifade eder.
StockCode: Ürün kodu. Her bir ürün için eşsiz numara.
Description: Ürün ismi
Quantity: Ürün adedi. Faturalardaki ürünlerden kaçar tane satıldığını ifade etmektedir.
InvoiceDate: Fatura tarihi ve zamanı.
UnitPrice: Ürün fiyatı (Sterlin cinsinden)
CustomerID: Eşsiz müşteri numarası
Country: Ülke ismi. Müşterinin yaşadığı ülke.

2. Veri Okuma

import pandas as pd
import datetime as dt

df_yedek = pd.read_excel("datasets/online_retail_II.xlsx",
sheet_name="Year 2010-2011")

df = df_yedek.copy()

Çıktıların daha düzenli görünmesi için birkaç bir kaç ayar yapalım.

pd.set_option('display.max_columns', None)
pd.set_option('display.max_rows', None)
pd.set_option('display.float_format', lambda x: '%.3f' % x)
Tüm satır / sütunların görünmesini ve virgülden sonra 3 basamak yazdırmasını belirttik.

3. Pandas Alıştırmaları

Veri seti üzerinde birkaç pandas alıştırmaları yapalım !

# Eşsiz ürün sayısı
df["Description"].nunique()

# Ürün adetleri;
df["Description"].value_counts().head()

# En çok sipariş edilen ürün;
df.groupby("Description").agg({"Quantity": "sum"})

# Toplam kaç fatura kesilmiştir?;
df["Invoice"].nunique()

# Fatura başına ortalama kaç para kazanılmıştır?;
df["Total Price"] = df["Price"] * df["Quantity"]

# En pahalı ürünler;
df.sort_values("Price", ascending=False).head(10)

# Ülkere göre sipariş adetleri;
df["Country"].value_counts()

# Ülkere göre fatura tutarları;
df.groupby("Country").agg({"Total Price": "sum"}).sort_values("Total Price", ascending=False).head(10)

4. Veri Ön İşleme

Veri setinin metadata bilgilerini inceleyelim.

df.head() 
df.tail()
df.shape
df.info()
df.columns
df.index

Veri setinde null değerler ve iade faturaları yer almaktadır. Hadi yok edelim :)

df.isnull().sum()
df.dropna(inplace=True)
df.isnull().sum()
df = df[~df["Invoice"].str.contains("C", na=False)]

5. RFM Metriklerini ve Skorlarını Oluşturma

RFM metriklerinden birisi olan Recency değerlerini oluşturmak için başta import ettiğimiz datetime modülünü kullanacağız. Burada dikkat edilmesi gereken en önemli nokta veri setindeki maksimum tarihin analizin yapıldığı tarih olarak kabul edilmesidir. Böylelikle aradaki uçurumu engellemiş oluruz. Bir diğer önemli nokta ise veri setindeki maksimum tarihte yapılan alışverişleri de yakalamak için bugünün tarihini belirlerken üzerine 1 veya 2 gün koyulmalıdır.

df["InvoiceDate"].max()
Timestamp('2011-12-09 12:50:00')
today_date = dt.datetime(2011, 12, 11)

Bir diğer metriğimiz Monetary için toplam alışveriş tutarı diye yeni bir değişken oluşturmamız gerekiyor. Bu değişkeni birim fiyat ile adetleri çarparak oluşturuyoruz.

df["Total Price"] = df["Price"] * df["Quantity"]

Şimdi Customer ID üzerinden bir gruplama işlemi yapıp tüm müşterilerin RFM metriklerini oluşturalım.

rfm = df.groupby("Customer ID").agg({
"InvoiceDate": lambda recency:(today_date -recency.max()).days,
"Invoice": lambda frequency: len(frequency),
"Total Price": lambda monetary: monetary.sum()})
rfm.columns = ["Recency", "Frequency", "Monetary"]

Burada ne yaptık?

Customer ID’leri grupladık ve lambda (isimsiz fonksiyon) yardımı ile her bir müşteri için Recency (en son alışveriş üzerinden geçen gün sayısı), Frequency (alışveriş sayısı) ve Monetary (toplam alışveriş tutarı) adında yeni değişlenler oluşturduk ve isimlerini “Recency”, “Frequency”, “Monetary” olarak değiştirdik.

Dikkat etmemiz gereken bir nokta daha var. Müşteri hediye çeki, kupon vs. ile alışveriş yapmış olabilir. Bu durumu engellemek için aşağıdaki düzeltmeyi yapmamız gerekmektedir.

rfm = rfm[(rfm["Frequency"]) > 0 & (rfm["Monetary"] > 0)]
RFM Metrikleri

Oluşturduğumuz bu değerler RFM metrikleridir. Segmentleri oluşturmak için bu metrikleri skorlara çevirmemiz gerekiyor.

rfm["RecencyScore"]=pd.qcut(rfm["Recency"],5,labels=[5,4,3,2,1])rfm["FrequencyScore"]=pd.qcut(rfm["Frequency"],5,labels=[1,2,3,4,5])rfm["MonetaryScore"]=pd.qcut(rfm["Monetary"],5,labels=[1,2,3,4,5])

Segment denilince aklımıza “qcut” fonksiyonu gelmeli. Bu fonksiyon değerleri küçükten büyüğe sıralar ve çeyrekliklere göre belirtilen etiketlere göre atama yapar.

Hadi gelin şimdi final skorlarımızı oluşturalım.

rfm["RFM_SCORE"] = (rfm["RecencyScore"].astype(str) +
rfm["FrequencyScore"].astype(str) +
rfm["MonetaryScore"].astype(str))

Veri setimizin son halini bir kaç skor üzerinden yorumlayalım. Görüldüğü gibi 12346 Id ye sahip olan müşteri en son 326 gün önce alışveriş yapmış ve 1 alışverişi bulunuyor. Kazandırdığı toplam tutar ise 77183 birim para. Bu müşterinin skorlaması ise 115'tir.

12347 Id ye sahip müşterinin son alışverişinin üzerinden 3 gün geçmiş ve bu müşteri 182 kere alışveriş yapmış. Toplam kazandırdığı tutar ise 4310. Bu müşterinin skorlaması ise 555'tir.

Eeee, biz sürekli böyle tek tek skor mu toplayacağız!

Tabiki hayır. Gelin bu müşterileri Recency ve Frequency değerlerine göre belirli segmentlere ayılarım.

rfm["Segment"] = rfm["RecencyScore"].astype(str) +
rfm["FrequencyScore"].astype(str)
Recency ve Frequency ile yeni bir “Segment” değişkeni oluşturduk
seg_map = {
r'[1-2][1-2]': 'Hibernating',
r'[1-2][3-4]': 'At_Risk',
r'[1-2]5': 'Cant_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'}

Burada ki mantık; oluşturduğumuz RF skorlarının ilk değeri 1 veya 2, ikinci değeri 5 ise “Cant_Loose” olarak değiştirmektir. Bunun için Regex yapısını kullanacağız.

“Regex” ile yukarıda görülen segmentleri veri setimize ekleyelim.

rfm["Segment"] = rfm["Segment"].replace(seg_map, regex=True)

Görüldüğü gibi tüm müşterileri alışveriş alışkanlıklarına göre segmentlere ayırdık. Artık bu segmentlerde yer alan müşterilere göre çeşitli aksiyonlar alabiliriz.

Peki bizden At_Risk grubu özelinde bir aksiyon almak için bu segmentte yer alan müşteriler istenirse?

new_df = pd.DataFrame()new_df["AtRisk"] = rfm[rfm["Segment"] == "At_Risk"].indexnew_df.to_csv("At_Risk.csv")

Artık “At_Risk.csv” dosyasını ilgili departmanlara gönderebilir ya da bir database içerisine aktarabiliriz :)

Yeniden görüşmek dileğiyle..

KAYNAKLAR

1. Data Science and Machine Learning Bootcamp https://github.com/mvahit/DSMLBootcamp

2. https://www.customermonitor.com/blog/rfm-modelling-a-powerful-customer-segmentation-tool

--

--