精準營銷!用機器學習完成客戶分群!

語言: CN / TW / HK

highlight: a11y-dark

我報名參加金石計劃1期挑戰——瓜分10萬獎池,這是我的第2篇文章,點選檢視活動詳情

我們總會聽到很多公司的技術人員在做使用者畫像的工作,細分客戶/客戶分群是一個很有意義的工作,可以確保企業構建更個性化的消費者針對策略,同時優化產品和服務。

在機器學習的角度看,客戶分群通常會採用無監督學習的演算法完成。應用這些方法,我們會先收集整理客戶的基本資訊,例如地區、性別、年齡、偏好 等,再對其進行分群。

在本篇內容中,ShowMeAI將用一個案例講解基於客戶資訊做使用者分群的方法實現。

💡 核心步驟

整個客戶分群的過程包含一些核心的步驟:

  • 資料收集
  • 建立RFM表
  • 探索資料&資料變換
  • 應用聚類做使用者分群
  • 解釋結果

💡 資料收集

下列資料操作處理與分析涉及的工具和技能,歡迎大家查閱ShowMeAI對應的教程和工具速查表,快學快用。

我們需要先結合業務場景收集資料,我們在本案例中使用的是 🏆Online_Retail線上零售資料集,大家可以在ShowMeAI的百度網盤中下載獲取資料。

本份資料對應的是線上零售業務的交易資料,包含英國線上零售從 2010 年 12 月 1 日到 2011 年 12 月 9 日的交易。核心欄位包括產品名稱、數量、價格和其他表示 ID 的列。資料集包含 541909 條資料記錄。

🏆 實戰資料集下載(百度網盤):公眾號『ShowMeAI研究中心』回覆『實戰』,或者點選 這裡 獲取本文 [24]基於機器學習的使用者價值資料探勘與客戶分群Online_Retail 線上零售資料集

ShowMeAI官方GitHubhttps://github.com/ShowMeAI-Hub

為了快速演示客戶分群過程,我們不使用全部資料,我們從資料中取樣出 10000 條演示整個過程,對應的資料讀取與取樣程式碼如下:

```python

匯入工具庫

import pandas as pd import matplotlib.pyplot as plt import numpy as np

讀取資料

df = pd.read_excel('Online_Retail.xlsx') df = df[df['CustomerID'].notna()]

資料取樣

df_fix = df.sample(10000, random_state = 42) ```

取樣出來的資料如下

💡 建立 RFM 表

資料準備好之後,為了細分客戶,我們會對資料做處理,拿到一些核心指標,比如客戶上次購買產品的時間,客戶購買產品的頻率以及客戶為產品支付的費用。

也就是我們說的製作 RFM 表的過程,我們建立對應的欄位,包括 Recency(最近一次消費)、Frequency(消費頻率)和 Monetary Value(消費金額列),它們的構建方式分別如下:

  • 可以用事務發生的日期減去快照日期,來代表最近消費時間點。
  • 可以計算每個客戶的交易量,作為頻度資訊。
  • 可以彙總每個客戶的所有交易金額,作為消費金額列。

處理過程的程式碼如下:

```python

只保留日期

from datetime import datetime df_fix["InvoiceDate"] = df_fix["InvoiceDate"].dt.date

總金額

df_fix["TotalSum"] = df_fix["Quantity"] * df_fix["UnitPrice"]

最近消費時間點快照

import datetime snapshot_date = max(df_fix.InvoiceDate) + datetime.timedelta(days=1)

統計聚合

customers = df_fix.groupby(['CustomerID']).agg({ 'InvoiceDate': lambda x: (snapshot_date - x.max()).days, 'InvoiceNo': 'count', 'TotalSum': 'sum'})

重新命名欄位

customers.rename(columns = {'InvoiceDate': 'Recency', 'InvoiceNo': 'Frequency', 'TotalSum': 'MonetaryValue'}, inplace=True) ```

得到結果如下

💡 探索資料&資料變換

下列資料預處理涉及的知識,歡迎大家查閱ShowMeAI對應的知識詳解文章。 - 機器學習實戰 | 機器學習特徵工程最全解讀

我們的很多典型的模型演算法,對於資料分佈都有一些前提假設,比如我們會認為連續值欄位是基本符合正態分佈的,我們對不同的欄位進行視覺化處理,以檢視其分佈:

python fig, ax = plt.subplots(1, 3, figsize=(15,3)) sns.distplot(customers['Recency'], ax=ax[0]) sns.distplot(customers['Frequency'], ax=ax[1]) sns.distplot(customers['MonetaryValue'], ax=ax[2]) plt.tight_layout() plt.show()

我們會發現,資料並不是完全正態分佈的,準確地說,它們都是有偏的,我們通常會通過一些資料變換手段來對資料做一些梳理,常見的資料變換方式包括:

  • 對數轉換
  • 平方根變換
  • box-cox 變換

我們可以對原始資料,分別使用『對數變換』、『平方根變換』和『box-cox 變換處理』,把分佈繪製如下:

```python from scipy import stats def analyze_skewness(x): fig, ax = plt.subplots(2, 2, figsize=(5,5)) sns.distplot(customers[x], ax=ax[0,0]) sns.distplot(np.log(customers[x]), ax=ax[0,1]) sns.distplot(np.sqrt(customers[x]), ax=ax[1,0]) sns.distplot(stats.boxcox(customers[x])[0], ax=ax[1,1]) plt.tight_layout() plt.show()

print(customers[x].skew().round(2))
print(np.log(customers[x]).skew().round(2))
print(np.sqrt(customers[x]).skew().round(2))
print(pd.Series(stats.boxcox(customers[x])[0]).skew().round(2))

analyze_skewness('Recency') ```

python analyze_skewness('Frequency')

python fig, ax = plt.subplots(1, 2, figsize=(10,3)) sns.distplot(customers['MonetaryValue'], ax=ax[0]) sns.distplot(np.cbrt(customers['MonetaryValue']), ax=ax[1]) plt.show() print(customers['MonetaryValue'].skew().round(2)) print(np.cbrt(customers['MonetaryValue']).skew().round(2))

根據影象視覺化,我們分別對Recency、Frequency、MonetaryValue選擇box-cox變換,box-cox變換和三次方根(cbrt)變換。

python from scipy import stats customers_fix = pd.DataFrame() customers_fix["Recency"] = stats.boxcox(customers['Recency'])[0] customers_fix["Frequency"] = stats.boxcox(customers['Frequency'])[0] customers_fix["MonetaryValue"] = pd.Series(np.cbrt(customers['MonetaryValue'])).values customers_fix.tail()

處理過後的資料是這樣的

我們一會兒使用到的模型演算法(K-Means 聚類),對於不同欄位的幅度大小是敏感的,我們會再做進一步的資料處理,把資料幅度規範化,這裡我們可以直接使用 Scikit-Learn 的

```python

匯入庫

from sklearn.preprocessing import StandardScaler

初始化物件

scaler = StandardScaler()

擬合和轉換資料

scaler.fit(customers_fix) customers_normalized = scaler.transform(customers_fix)

均值為 0,方差為 1

print(customers_normalized.mean(axis = 0).round(2)) # [0. -0。 0.] print(customers_normalized.std(axis = 0).round(2)) # [1. 1. 1.] ```

得到結果如下:

💡 建模與分群

資料處理完成,我們可以進一步使用演算法模型完成客戶分群了,這裡我們使用聚類演算法 K-Means 來對資料分組。

K-Means 演算法是一種無監督學習演算法,它通過迭代和聚合來根據資料分佈確定資料屬於哪個簇。關於 K-Means 的詳細知識歡迎大家檢視ShowMeAI的教程文章: - 圖解機器學習 | 聚類演算法詳解

實際應用 K-Means 演算法是很簡單的,我們直接使用 Scikit-Learn 來實現。但是 K-Means 演算法中有一個很重要的超引數『簇數k』。下面我們使用『肘點法』來定位最好的超引數:

```python from sklearn.cluster import KMeans

sse = {} for k in range(1, 11): kmeans = KMeans(n_clusters=k, random_state=42) kmeans.fit(customers_normalized) sse[k] = kmeans.inertia_

plt.title('The Elbow Method')plt.xlabel('k') plt.ylabel('SSE') sns.pointplot(x=list(sse.keys()), y=list(sse.values())) plt.show() ```

這是結果,

根據上圖的結果,我們選定 k 取值為 3(因為大於3的k取值下,SSE的結果並不再急劇下降,而是呈現近線性)。我們設定n_clusters為3,再重新聚類:

python model = KMeans(n_clusters=3, random_state=42) model.fit(customers_normalized) model.labels_.shape

💡 模型解釋&業務理解

我們基於聚類結果來對使用者群做一些解讀和業務理解,這裡我們將聚類得到的 3 個 cluster 的聚類中心資訊輸出,程式碼如下:

python customers["Cluster"] = model.labels_ customers.groupby('Cluster').agg({ 'Recency':'mean', 'Frequency':'mean', 'MonetaryValue':['mean', 'count']}).round(2)

結合上述結果,對3類聚類得到的使用者群解讀如下:

  • 使用者群0:頻繁消費,消費數額大,且最近有購買行為。可以視作『忠實客戶群』。
  • 使用者群1: 消費頻率較低,消費數額小,但最近有購買行為。可以視作『新客戶群』。
  • 使用者群2:消費頻率較低,消費數額小,上一次購買的時間較早。可以視作『流失客戶群』。

參考資料

「其他文章」