Segmentacja klientów z RFM
Po pierwsze, czym jest RFM?
RFM to kluczowy wskaźnik składający się z trzech miar pozwalających zrozumieć aktualne relacje klientów z firmami. Analiza RFM jest szeroko stosowaną, opartą na danych, opartą na regułach techniką stosowaną do segmentacji klientów za pomocą wskaźników częstotliwości , częstości i monetarności z wykorzystaniem danych o klientach.
Analiza RFM jest przeprowadzana w celu lepszego zaspokojenia potrzeb różnych rodzajów klientów oddzielnie. Klienci są grupowani zgodnie z ich zwyczajami zakupowymi, dzięki czemu można opracować unikalne strategie biznesowe dla tych grup. Indywidualne zabiegi mogą zapobiec odpływowi klientów i zapewnić utrzymanie lojalnych klientów.
Trzy kluczowe czynniki:
Recency odnosi się do długości czasu ostatniej interakcji z klientem. Najmniejsza wartość aktualności odpowiada ostatniemu zakupowi; więc im mniejszy tym lepszy. Nowi klienci są bardziej wartościowi.
Recency = Data analizy — Data ostatniego zakupu
Częstotliwość odnosi się do tego, jak często klient dokonuje zakupu. Stali klienci są bardziej wartościowi.
Pieniądze odnoszą się do wartości finansowej, jaką każdy klient wydał na tę firmę.
Jak porównać te wskaźniki?
Metryki te są konwertowane na wyniki , dzięki czemu są tego samego typu i można je ze sobą porównywać. To przekształcenie można również nazwać standaryzacją. Oceny pochodzące z metryk są ze sobą powiązane i tworzą ocenę RFM dla każdego klienta. Głównie klienci są uszeregowani pod względem wartości, jaką wnoszą do firmy, od 1 do 5.
Oceny RFM mogą być w szerokim zakresie, dlatego na Oceny RFM stosowana jest metoda tworzenia segmentów, tak aby te segmenty miały sensowny wgląd.
Segmentacja według wyników RFM:
Segmentacja jest zwykle przeprowadzana za pomocą wykresu 2-D pokazanego w Tabeli 1 . W ten sposób wyniki RFM mają sens. Analiza RFM może pomóc firmom poznać swoich klientów i odpowiednio ulepszyć strategie marketingowe.
Jak widać, punktacji pieniężnej nie ma na wykresie, ponieważ w analizie CRM częstotliwość i aktualność mają większe znaczenie niż wartość pieniężna. Kiedy się nad tym zastanowić, analiza pieniędzy klienta z kilkoma transakcjami nie jest tak ważna w porównaniu do częstych klientów. Chociaż wartość pieniężna nie jest wyraźnie przedstawiona na wykresie, nadal jest ważnym elementem analizy RFM i służy do formułowania założeń.
Rozwiązanie problemu biznesowego poprzez RFM:
Zobaczmy, jak te koncepcje są stosowane w rzeczywistych zbiorach danych i jakie spostrzeżenia można wyciągnąć z danych. Możesz uzyskać dostęp do pełnego kodu w moim profilu GitHub dla lepszej demonstracji.
Podczas analizy danych należy wykonać określone kroki.
1. Problem biznesowy
Firma e-commerce z siedzibą w Wielkiej Brytanii chce podzielić swoich klientów na segmenty i zdefiniować strategie marketingowe zgodnie z tymi segmentami. Istnieje zbiór danych obejmujący sprzedaż w okresie od 01.12.2009 do 09.12.2011.
2.Zrozumienie danych
Zestaw danych zawiera 8 zmiennych, a mianowicie fakturę, kod towaru, opis, ilość, datę faktury, cenę, identyfikator klienta i kraj. Faktury zaczynające się na literę „C” dotyczą transakcji anulowanych. Aby zrozumieć, z czym mamy do czynienia, musimy przyjrzeć się danym. Analiza zostanie przeprowadzona dla lat 2010-2011, ale może być wykorzystana również dla lat 2009-2010, ponieważ na końcu proces zostanie uogólniony.
Korekty podstawowe (importowanie bibliotek i ustawianie preferencji wyświetlania danych):
import datetime as dt
import pandas as pd
pd.set_option('display.max_columns', None) #to see all the columns
pd.set_option('display.float_format', lambda x: '%.3f' % x) #to have 3 decimal points
df_ = pd.read_excel("excel-file-destination.xlsx", sheet_name="Year 2010-2011")
df = df_.copy() #It takes time to read the file,thus a copy is taken after reading the file
#so we do not have to read the file and have to wait repeatedly thoughout the analysis
df.head() #unless specified otherwise, returns the first 5 rows of the dataset
df.shape #returns the number of the ows and columns
df.isnull().sum() #returns the number of null values in every column
Problem dotyczy dużego zbioru danych z 541910 wierszami i 8 kolumnami. Ale czy powinniśmy wziąć pod uwagę wszystkie dane do analizy?
Brakuje nam wartości głównie w zmiennych Identyfikator klienta i Opis. Oznacza to, że będziemy musieli usunąć brakujące wiersze identyfikatora klienta, ponieważ analiza dotyczy konkretnego klienta, a brakujące dane nie dostarczają żadnych informacji.
Odpowiedzmy na kilka pytań:
# Number of unique products
df["Description"].nunique()
# Number of products appearing in invoices()
df["Description"].value_counts().head()
# Most ordered product (including quantities)
df.groupby("Description").agg({"Quantity": "sum"}).sort_values("Quantity", ascending=False).head()
# Number of unique invoices
df["Invoice"].nunique()
# Add a new column for TotalPrice
df["TotalPrice"] = df["Quantity"] * df["Price"]
# Find the total cost in every invoice
df.groupby("Invoice").agg({"TotalPrice": "sum"}).head()
# needed for monetary metric
Przygotowanie danych odgrywa ważną rolę w analizie. Dane muszą być przetwarzane w sposób umożliwiający wyciąganie wniosków. Problemy dotyczące tego zestawu danych i rozwiązania są wyjaśnione poniżej w kodzie.
df.shape # To observe the reducing number of rows as we make adjustments
df.isnull().sum() # Observed problem: Missing Customer ID data, needed to be erased
df.describe().T # Observed problem: Negative Quantitity values, no meaning, needed to be erased
df = df[(df['Quantity'] > 0)] # To solve Negative Quantitity values problem
df.dropna(inplace=True)
# To solve Missing Customer ID data problem
# Inplace makes the changes on dataset immediately without a need for assigning
df["Invoice"] = df["Invoice"].astype(str)
df = df[~df["Invoice"].str.contains("C", na=False)]
# Cancelled invoices do not need to be in the analysis, so they are erased.
# "~" means except this:
4. Obliczanie metryk RFM
Do tej pory w zasadzie przygotowywaliśmy dane tak, aby można było na nich przeprowadzić analizę RFM. Teraz zacznijmy analizę od obliczenia metryk. Ponieważ nie żyjemy już w latach 2010–2011, musimy ustalić datę, w której przeprowadzana jest analiza. W tym celu znajdźmy najpóźniejszą datę i wybierzmy najbliższy jej dzień do przeprowadzenia analizy.
Następnie operacje są wykonywane na kolumnach InvoiceDate, Invoice i TotalPrice i grupowane według identyfikatora klienta w celu uzyskania ramki danych RFM zawierającej odpowiednio metryki Recency, Frequency i Monetary.
df["InvoiceDate"].max() # latest date on data
today_date = dt.datetime(2011, 12, 11)
# added 2 days to last day to form today's date
# utilized datetime library so that today_date's datatype is datetime
type(today_date)
rfm = df.groupby('Customer ID').agg({'InvoiceDate': lambda InvoiceDate: (today_date - InvoiceDate.max()).days,
'Invoice': lambda Invoice: Invoice.nunique(),
'TotalPrice': lambda TotalPrice: TotalPrice.sum()})
# In order, Recency, Frequency, Monetary are found.
# Recency is the difference in the today's date and last purchase on Customer ID level.
# Frequency is the number of unique invoices that belongs to the same customer.
# Monetary is summation of total prices of the same customer, so we know how much each customer brings to the company.
rfm.head()
# check the data
rfm.columns = ['recency', 'frequency', 'monetary']
# change the column names
rfm.describe().T # to see if there is an unsual situation
rfm = rfm[rfm["monetary"] > 0]
# min monetary = 0 is unusual, so they are excluded.
rfm.shape
5. Obliczanie wyników RFM:
Podczas obliczania wyników RFM pierwszą rzeczą, którą należy wziąć pod uwagę, jest to, że oceny aktualności są przypisywane wstecz w porównaniu z częstotliwością i pieniędzmi ze względu na ich znaczenie.
rfm["recency_score"] = pd.qcut(rfm['recency'], 5, labels=[5, 4, 3, 2, 1])
# recency metrics divided 5 equal parts acoording to their sizes and
# labelled such a way that greatest recency got 1, the smallest recency got 5.
rfm["frequency_score"] = pd.qcut(rfm['frequency'].rank(method="first"), 5, labels=[1, 2, 3, 4, 5])
# the problem in frequency is some numbers are too repetitive that
# qcut can not label the same frequency number diffently
# rank method solves this problem by assigning the first comer number to first label.
rfm["monetary_score"] = pd.qcut(rfm['monetary'], 5, labels=[1, 2, 3, 4, 5])
rfm["RFM_SCORE"] = (rfm['recency_score'].astype(str) +
rfm['frequency_score'].astype(str))
# by RFM definition, string is created with recency and frequency score
# and formed final RFM Score
# monetary score is necessary for observation, but it is not used in forming RFM Score
rfm.describe().T
# newly created scores did not apper with describe function
# since they are strings and not integers
rfm[rfm["RFM_SCORE"] == "55"]
# champions
rfm[rfm["RFM_SCORE"] == "11"]
# hibernating
Aby zwiększyć czytelność tabeli, dodamy, co oznacza dla nas każdy segment zgodnie z Tabelą 1 .
RegEx (wyrażenia regularne) zawiera dopasowania, które są zgodne z określonym wzorcem w serii. To jest część, w której wyciągamy wnioski z danych.
# regex
# RFM Naming (Pattern Matching)
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'
}
# Basically the R-F table is coded using regex.
rfm['segment'] = rfm['RFM_SCORE'].replace(seg_map, regex=True)
segment_analysis = rfm[["segment", "recency", "frequency", "monetary"]].groupby("segment").agg(["mean", "count"])
rfm[rfm["segment"] == "cant_loose"].head()
cant_loose_customers = rfm[rfm["segment"] == "cant_loose"].index
# A list of customers which the company should be more careful with is formed.
# This way, every segment of customers is accesible.
new_df = pd.DataFrame()
# Empty dataframe is formed
new_df["new_customer_id"] = rfm[rfm["segment"] == "new_customers"].index
new_df["new_customer_id"] = new_df["new_customer_id"].astype(int)
# To get rid of the decimals
new_df.to_csv("new_customers.csv")
rfm.to_csv("rfm.csv")
# Segment information is extracted into an excel file.
Zgodnie z podstawowymi zasadami programowania, takimi jak DRY (Don't Repeat Yourself), funkcjonalizacja całego tego procesu jest koniecznością. W ten sposób możemy wielokrotnie korzystać z tej funkcji, stąd Analiza RFM, na różnych ramkach danych.
Czysta wersja wszystkich powyższych danych zapisanych w poniższej funkcji w nazwie create_rfm z opcją utworzenia pliku csv.
def create_rfm(dataframe, csv=False):
PS Dziękuję bardzo za poświęcenie czasu na przeczytanie tego wszystkiego. Dzielę się wiedzą, gdy się uczę, więc co tydzień będzie pojawiać się nowy artykuł związany z nauką o danych. Mam nadzieję, że ten post też ci pomoże. Nie wahaj się zostawić komentarza :) Powodzenia na własnej drodze do nauki o danych.
Połącz się ze mną na LinkedIn
Połącz się ze mną na Medium
Odniesienie:
- Filmy z wykładami Miuula

![Czym w ogóle jest lista połączona? [Część 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































