精準營銷!用機器學習完成客户分羣!

語言: 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:消費頻率較低,消費數額小,上一次購買的時間較早。可以視作『流失客户羣』。

參考資料

「其他文章」