前言
通常來說,在傳統零售行業中80%的收益來自於20%的客戶,因此對客戶的價值進行分類顯得尤其重要,而在本文我們基於批發經銷商客戶的真實消費數據,建立K-means聚類模型來對客戶價值進行細分。
目錄
1. 數據來源及背景
2. 明確分析目的
3. 數據探索分析
4. 數據預處理
5. 構建模型
6. 客戶價值細分
正文
1. 數據來源及背景
數據來源: http://archive.ics.uci.edu/ml/machine-learning-databases/00292;
數據背景: 這是某批發經銷商客戶在各類型產品的年度支出數據集. 該數據集樣本容量為440, 共有8個特征, 其分別為: 客戶渠道, 客戶所在地區, 以及在新鮮產品, 奶制品, 食品雜貨, 冷凍產品, 洗滌劑和紙制品, 熟食產品這6種類型產品的年度支出.
2. 明確分析目的
通過提出一系列問題, 明確我們的分析目的:
1) 各類產品的年度支出平均水平如何?哪個產品最高?哪個又最低?
2) 如何對這些客戶進行分類呢?他們的消費行為又是怎樣的呢?
3) 商家該如何根據分類結果制定營銷計划呢?
3. 數據探索分析
1. 查看前2行和后2行
import pandas as pd df = pd.read_csv(r'D:\Data\Wholesale customers data.csv') pd.set_option('display.max_rows', 4) df
可通過以上看出我們的數據維度的確是440行×8列, 以及每列都是數字, 到底是字符串類型還是數值類型, 需要進一步探索.
2. 查看數據整體信息
df.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 440 entries, 0 to 439 Data columns (total 8 columns): Channel 440 non-null int64 Region 440 non-null int64 Fresh 440 non-null int64 Milk 440 non-null int64 Grocery 440 non-null int64 Frozen 440 non-null int64 Detergents_Paper 440 non-null int64 Delicassen 440 non-null int64 dtypes: int64(8) memory usage: 27.6 KB
通過查看數據整體信息, 可以確定每列都是數值型, 且均為64位整數型;另外, 也可以看出數據里是沒有缺失值的, 即全部為440.
數據類型現在已經確定了, 接下來尋找我們第一個問題的答案了.
3. 描述性統計
df.describe()
1) 各類產品的年度支出平均水平如何?哪個產品最高?哪個又最低?
這里的平均水平用平均數和中位數這兩者中的哪個合適呢?通過分別對比各類型產品的平均數和中位數, 發現平均數都大於中位數, 呈現右偏分布, 顯然這里采用中位數來代表較為妥當.
各類型產品的年度支出平均水平分別為: 新鮮產品8504.0m.u.、奶制品3627.0m.u.、食品雜貨4755.5m.u.、冷凍產品1526.0m.u.、洗滌劑和紙質品816.5m.u.、熟食產品965.5m.u.
其中, 新鮮產品排名第一,第二是食品雜貨,第三、第四和第五分別是奶制品、冰凍產品和熟食產品,第六則是洗滌劑和紙質品.
對於第二個問題,我們利用k-means聚類模型來對其進行分類,而在建模之前,我們需要對數據進行數據預處理
4. 數據預處理
1. 數據清洗
1) 缺失值處理
沒有缺失值, 因此不用缺失值處理
2) 異常值處理
在處理異常值之前, 先來通過箱線圖查看異常值.
import seaborn as sns import matplotlib.pyplot as plt def get_boxplot(data, start, end): fig, ax = plt.subplots(1, end-start, figsize=(24, 4)) for i in range(start, end): sns.boxplot(y=data[data.columns[i]], data=data, ax=ax[i-start]) get_boxplot(df, 2, 8)
可以看到以上6個連續型變量均有不同程度的異常值, 由於k-means算法對異常值較敏感, 因此選擇剔除它
def drop_outlier(data, start, end): for i in range(start, end): field = data.columns[i] Q1 = np.quantile(data[field], 0.25) Q3 = np.quantile(data[field], 0.75) deta = (Q3 - Q1) * 1.5 data = data[(data[field] >= Q1 - deta) & (data[field] <= Q3 + deta)] return data del_df = drop_outlier(df, 2, 8) print("原有樣本容量:{0}, 剔除后樣本容量:{1}".format(df.shape[0], del_df.shape[0])) get_boxplot(del_df, 2, 8)
原有樣本容量:440, 剔除后樣本容量:318
在剔除一次異常值之后, 6個連續變量的波動幅度也都都大致接近, 你可能會問為什么還有異常值存在? 現在的異常值是相對於新數據集產生的, 而我們把原數據集中的異常值已經剔除了, 通常來說, 對於異常值只需剔除一次即可, 如果徹底剔除的話, 樣本容量可能會有大幅度的變化, 比如:
df_new = df.copy() #直到第10次的時候圖像上才沒有出現異常值 for i in range(10): df_new = drop_outlier(df_new, 2, 8) print("原有樣本容量:{0}, 徹底剔除后樣本容量:{1}".format(df.shape[0], df_new.shape[0])) get_boxplot(df_new, 2, 8)
原有樣本容量:440, 徹底剔除后樣本容量:97
可以看到現在的數據集中已經不存在異常了, 但是樣本容量也從440大幅度下降為97, 因此這里不建議徹底刪除.
2. 數據變換
對數據中的離散型變量和連續型變量分別進行適當的變換,以適應模型的要求
1) 離散型變量
將離散型變量處理成啞變量.
del_df['Channel'] = del_df.Channel.astype(str) del_df['Region'] = del_df.Region.astype(str) del_df = pd.get_dummies(del_df)
2) 連續型變量
由於連續型變量的數值范圍有大有小, 為消除其對聚類結果的影響, 這里采用z-score進行歸一化處理
for i in range(6): field = del_df.columns[i] del_df[field] = del_df[field].apply(lambda x: (x - del_df[field].mean()) / del_df[field].std())
數據預處理這部分的工作已大致完成,下一步進行模型構建.
5. 構建模型
選取一個初始的k值, 來進行構建k-means聚類模型
1. 構建K=2的聚類模型
from sklearn.cluster import KMeans km = KMeans(n_clusters=2, random_state=10) km.fit(del_df) print(km.cluster_centers_) print(km.labels_)
[[ 0.08057098 -0.36005276 -0.42021772 0.11899282 -0.66737726 -0.10885484 0.97333333 0.02666667 0.2 0.10222222 0.69777778] [-0.19492979 0.8710954 1.01665578 -0.28788585 1.61462241 0.26335849 0.13978495 0.86021505 0.10752688 0.07526882 0.8172043 ]] [1 1 0 1 1 1 0 1 1 0 1 1 1 0 1 1 0 0 0 1 0 0 0 0 0 0 0 1 1 1 0 1 1 1 0 0 1 0 0 1 0 1 1 1 1 0 0 1 0 0 1 0 0 0 0 1 1 0 1 0 0 1 0 1 0 0 0 1 1 1 0 0 1 1 0 1 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 1 0 0 1 1 0 0 0 1 0 0 1 0 0 0 0 1 0 0 0 1 1 1 0 0 1 0 1 0 0 0 0 0 1 0 0 0 1 1 1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 0 0 1 1 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 1 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 0 1 0 1 1 1 1 0 1 1 0 0 1 1 0 0 0 0 0 0 0 0]
將客戶分為兩類合適嗎?我們通過迭代的方式來選擇合適的k值.
2. 迭代選擇合適的k值
import matplotlib.pyplot as plt K = range(1, 10) sse = [] for k in K: km = KMeans(n_clusters=k, random_state=10) km.fit(del_df) sse.append(km.inertia_) plt.figure(figsize=(8, 6)) plt.plot(K, sse, '-o', alpha=0.7) plt.xlabel("K") plt.ylabel("SSE") plt.show()
根據肘部法則, 選擇K=2, 也就是說將客戶分成兩類.
6. 客戶價值細分
from pandas.plotting import parallel_coordinates #訓練模型 km = KMeans(n_clusters=2, random_state=10) km.fit(del_df) centers = km.cluster_centers_ labels = km.labels_ customer = pd.DataFrame({'0': centers[0], "1": centers[1]}).T customer.columns = del_df.keys() df_median = pd.DataFrame({'2': del_df.median()}).T customer = pd.concat([customer, df_median]) customer["category"] = ["customer_1", "customer_2", 'median'] #繪制圖像 plt.figure(figsize=(12, 6)) parallel_coordinates(customer, "category", colormap='flag'') plt.xticks(rotation = 15) plt.show()
將各類型產品年度支出的聚類中心以及中位數繪制如上圖所示, 那么我們的第二個問題也就有了答案.
2) 如何對這些客戶進行分類呢?他們的消費行為又是怎樣的呢?
我們通過k-means聚類模型將這些客戶分為兩群: 客戶群1和客戶群2.
就六種類型產品的年度支出來看, 客戶群1在冷凍產品上最高, 在洗滌劑和紙制品上最低; 客戶群2在冷凍產品上則最低, 在洗滌劑和紙制品上則最高. 另外, 客戶群2在這六種產品的年度支出聚類中心均位於中位數水平之上上, 因此可將客戶群2視為重要價值客戶, 而客戶群1則為一般價值客戶.
最后, 我們將所有客戶的聚類結果繪制在平行坐標圖上
#將聚類后的標簽加入數據集 del_df['category'] = labels del_df['category'] = np.where(del_df.category == 0, 'customer_1', 'customer_2') customer = pd.DataFrame({'0': centers[0], "1": centers[1]}).T customer["category"] = ['customer_1_center', "customer_2_center"] customer.columns = del_df.keys() del_df = pd.concat([del_df, customer]) #對6類產品每年消費水平進行繪制圖像 df_new = del_df[['Fresh', 'Milk', 'Grocery', 'Frozen', 'Detergents_Paper', 'Delicassen', 'category']] plt.figure(figsize=(18, 6)) parallel_coordinates(df_new, "category", colormap='cool') plt.xticks(rotation = 15) plt.show()
通過上圖可以看出模型的聚類效果較為理想, 同時也顯示出客戶群2(重要價值客戶)相對於客戶群1(一般價值客戶)的數量較少, 畢竟重要的總是占少數.
針對這些結果, 該采取什么措施呢?來到我們的第三個問題
3) 商家該如何根據分類結果制定營銷計划呢?
就六大類型產品來說, 可通過問卷的方式來調研改善店鋪內布局以及增加產品種類是否會影響客戶的購買行為; 另外, 根據聚類結果發現高價值客戶的來源傾向於渠道2, 可加大在該渠道上的宣傳力度; 最后,可進行一些打折促銷活動,刺激客戶的購買行為.
參考資料:
網易雲課堂《吳恩達機器學習》
《數據分析與挖掘實戰》
聲明: 本文僅用於學習交流