Kundensegmentierung mit RFM
Erstens: Was ist RFM?
RFM ist ein Schlüsselindikator, der aus drei Metriken besteht, um die aktuellen Beziehungen der Kunden zu den Unternehmen zu verstehen. Die RFM-Analyse ist eine weit verbreitete, datengesteuerte, regelbasierte Technik zur Kundensegmentierung mit Aktualitäts- , Häufigkeits- und Währungsmetriken unter Verwendung der Kundendaten.
Die RFM-Analyse wird durchgeführt, um den Bedürfnissen verschiedener Kundentypen besser gerecht zu werden. Kunden werden nach ihren Kaufgewohnheiten gruppiert, sodass für diese Gruppen einzigartige Geschäftsstrategien entwickelt werden können. Individuelle Behandlungen können die Abwanderung von Kunden verhindern und dafür sorgen, dass treue Kunden auch bleiben.
Drei Schlüsselfaktoren:
Unter Aktualität versteht man die Dauer der letzten Interaktion mit dem Kunden. Der kleinste Aktualitätswert entspricht dem letzten Kauf; also je kleiner desto besser. Neuere Kunden sind wertvoller.
Aktualität = Datum der Analyse – Datum des letzten Kaufs
Unter Häufigkeit versteht man, wie oft ein Kunde einen Kauf tätigt. Stammkunden sind wertvoller.
Monetär bezieht sich auf den finanziellen Wert, den jeder Kunde für dieses Unternehmen ausgegeben hat.
Wie kann man diese Kennzahlen vergleichen?
Diese Metriken werden in Scores umgewandelt , sodass sie vom gleichen Typ sind und miteinander vergleichbar sind. Diese Umwandlung kann auch als Standardisierung bezeichnet werden. Die aus den Metriken resultierenden Bewertungen werden miteinander verknüpft und bilden den RFM-Score für jeden einzelnen Kunden. Hauptsächlich werden Kunden hinsichtlich des Werts, den sie für das Unternehmen bringen, von 1 bis 5 eingestuft.
RFM-Scores können in einem weiten Bereich liegen. Daher wird auf RFM-Scores eine Methode angewendet, um Segmente zu bilden, damit diese Segmente aussagekräftige Erkenntnisse liefern.
Segmentierung durch RFM-Scores:
Die Segmentierung erfolgt üblicherweise über das in Tabelle 1 dargestellte 2D-Diagramm . Auf diese Weise sind RFM-Scores sinnvoll. Die RFM-Analyse kann Unternehmen dabei helfen, ihre Kunden zu kennen und ihre Marketingstrategien entsprechend zu verbessern.
Wie Sie sehen, ist der monetäre Score nicht in der Grafik enthalten, da in der CRM-Analyse Häufigkeit und Aktualität wichtiger sind als der monetäre Wert. Wenn Sie darüber nachdenken, ist die Analyse der Geldbeträge eines Kunden mit wenigen Transaktionen im Vergleich zu Stammkunden nicht so wichtig. Obwohl der Geldwert in der Grafik nicht explizit dargestellt wird, ist er dennoch ein wichtiger Bestandteil der RFM-Analyse und wird zur Annahme verwendet.
Lösung eines Geschäftsproblems durch RFM:
Sehen wir uns an, wie diese Konzepte auf einen realen Datensatz angewendet werden und welche Erkenntnisse aus den Daten gewonnen werden können. Den vollständigen Code finden Sie zur besseren Demonstration in meinem GitHub-Profil .
Bei einer Datenanalyse müssen bestimmte Schritte befolgt werden.
1.Geschäftsproblem
Ein in Großbritannien ansässiges E-Commerce-Unternehmen möchte seine Kunden in Segmente einteilen und Marketingstrategien entsprechend dieser Segmente definieren. Es existiert ein Datensatz bestehend aus den Verkäufen zwischen dem 01.12.2009 und dem 09.12.2011.
2. Die Daten verstehen
Der Datensatz enthält 8 Variablen, nämlich „Rechnung“, „StockCode“, „Beschreibung“, „Menge“, „Rechnungsdatum“, „Preis“, „Kunden-ID“ und „Land“. Rechnungen, die mit „C“ beginnen, gelten für stornierte Transaktionen. Um zu verstehen, womit wir es zu tun haben, müssen wir einen Blick auf die Daten werfen. Die Analyse wird für die Jahre 2010–2011 durchgeführt, sie kann jedoch auch für die Jahre 2009–2010 verwendet werden, da der Prozess am Ende verallgemeinert wird.
Primäre Anpassungen (Importieren der Bibliotheken und Festlegen der Datenanzeigeeinstellungen):
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
Es handelt sich um einen großen Datensatz mit 541910 Zeilen und 8 Spalten. Aber sollten wir alle Daten für die Analyse berücksichtigen?
In den meisten Kunden-ID- und Beschreibungsvariablen fehlen Werte. Das bedeutet, dass wir die fehlenden Kunden-ID-Zeilen löschen müssen, da die Analyse kundenspezifisch ist und fehlende Daten keine Informationen liefern.
Beantworten wir einige Fragen:
# 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
Bei der Analyse spielt die Datenaufbereitung eine wichtige Rolle. Daten müssen so manipuliert werden, dass Rückschlüsse gezogen werden können. Die Probleme in diesem Datensatz und die Lösungen werden unten im Code erläutert.
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. Berechnen von RFM-Metriken
Bisher haben wir die Daten grundsätzlich so aufbereitet, dass wir darauf eine RFM-Analyse durchführen können. Beginnen wir die Analyse nun mit der Berechnung der Kennzahlen. Da wir nicht mehr in den Jahren 2010–2011 leben, müssen wir ein Datum festlegen, an dem die Analyse durchgeführt wird. Zu diesem Zweck suchen wir das späteste Datum und legen einen Tag in der Nähe fest, an dem wir die Analyse durchführen möchten.
Anschließend werden Operationen an den Spalten „InvoiceDate“, „Invoice“ und „TotalPrice“ durchgeführt und nach Kunden-ID gruppiert, um einen RFM-Datenrahmen zu erhalten, der die Metriken „Aktualität“, „Häufigkeit“ und „Monetär“ enthält.
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. Berechnung der RFM-Scores:
Bei der Berechnung der RFM-Scores ist zunächst zu berücksichtigen, dass Aktualitätswerte aufgrund ihrer Bedeutung im Vergleich zu Häufigkeit und Geldwert rückwärts zugeordnet werden.
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
Um die Lesbarkeit der Tabelle zu verbessern, werden wir hinzufügen, was jedes Segment gemäß Tabelle 1 für uns bedeutet .
RegEx (Reguläre Ausdrücke) enthält Übereinstimmungen, die einem bestimmten Muster innerhalb einer Reihe entsprechen. Dies ist der Teil, in dem wir Erkenntnisse aus den Daten extrahieren.
# 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.
Nach grundlegenden Programmierprinzipien wie DRY (Don't Repeat Yourself) ist die Funktionalisierung dieses gesamten Prozesses ein Muss. Daher können wir diese Funktion, also die RFM-Analyse, wiederholt für verschiedene Datenrahmen verwenden.
Saubere Version aller oben genannten Daten, geschrieben in der Funktion unten im Namen „create_rfm“ mit der Option zum Erstellen einer CSV-Datei.
def create_rfm(dataframe, csv=False):
PS: Vielen Dank, dass Sie sich die Zeit genommen haben, das alles zu lesen. Ich teile, während ich lerne, daher wird es jede Woche einen neuen Artikel zum Thema Datenwissenschaft geben. Ich hoffe, dieser Beitrag hilft Ihnen auch. Bitte zögern Sie nicht, einen Kommentar zu hinterlassen :) Viel Glück auf Ihrer eigenen datenwissenschaftlichen Reise.
Vernetzen Sie sich mit mir auf LinkedIn
Vernetzen Sie sich mit mir auf Medium
Referenz:
- Miuul-Vorlesungsvideos

![Was ist überhaupt eine verknüpfte Liste? [Teil 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































