網站數據分析(11)——聚類分析

1、如何選擇聚類分析算法

聚類算法有幾十種之多,聚類算法的選擇,主要參考如下因素:算法

  • 若是數據集是高維的,那麼選擇譜聚類,它是子空間劃分的一種。·若是數據量爲中小規模,例如在100萬條之內,那麼K均值將是比較好的選擇;若是數據量超過100萬條,那麼能夠考慮使用Mini Batch KMeans。
  • 若是數據集中有噪點(離羣點),那麼使用基於密度的DBSCAN能夠有效應對這個問題。
  • 若是追求更高的分類準確度,那麼選擇譜聚類將比K均值準確度更好,在Docu-ment clustering using locality preserving indexing中關於K- means和Spectral Clustering應用到TDT2和Reuters-21578兩組數據的準確率對比結果證實了這個結論。 點擊查看論文

2、KMeans算法

2.1 原理

K-Means算法的思想很簡單,對於給定的樣本集,按照樣本之間的距離大小,將樣本集劃分爲K個簇。讓簇內的點儘可能緊密的連在一塊兒,而讓簇間的距離儘可能的大。bash

若是用數據表達式表示,假設簇劃分爲(C1,C2,...Ck),則咱們的目標是最小化平方偏差E:cors

其中μi是簇Ci的均值向量,有時也稱爲質心,表達式爲:dom

首先咱們看看K-Means算法的一些要點。ide

(1)對於K-Means算法,首先要注意的是k值的選擇,通常來講,咱們會根據對數據的先驗經驗選擇一個合適的k值,若是沒有什麼先驗知識,則能夠經過交叉驗證選擇一個合適的k值。ui

(2)在肯定了k的個數後,咱們須要選擇k個初始化的質心,就像上圖b中的隨機質心。因爲咱們是啓發式方法,k個初始化的質心的位置選擇對最後的聚類結果和運行時間都有很大的影響,所以須要選擇合適的k個質心,最好這些質心不能太近。idea

好了,如今咱們來總結下傳統的K-Means算法流程。 spa

輸入是樣本集D={x1,x2,...xm},聚類的簇樹k,最大迭代次數N3d

輸出是簇劃分C={C1,C2,...Ck} code

(1)從數據集D中隨機選擇k個樣本做爲初始的k個質心向量: {μ1,μ2,...,μk}

(2)對於n=1,2,...,N

  a) 將簇劃分C初始化爲Ct=∅t=1,2...k

  b) 對於i=1,2...m,計算樣本xi和各個質心向量μj(j=1,2,...k)的距離:dij=||xi−μj||22,將xi標記最小的爲dij所對應的類別λi。此時更新Cλi=Cλi∪{xi}

  c) 對於j=1,2,...,k,對Cj中全部的樣本點從新計算新的質心μj=1|Cj|∑x∈Cjx

  e) 若是全部的k個質心向量都沒有發生變化,則轉到步驟3)

(3)輸出簇劃分C={C1,C2,...Ck}

2.2 代碼實例

(1)原始數據 Sklearn中有專門的聚類庫cluster,在作聚類時只需導入這個庫,即可使用其中多種聚類算法,例如K均值、DBSCAN、譜聚類等。 本示例模擬的是對一份沒有任何標籤的數據集作聚類分析,以獲得不用類別的特徵和分佈狀態等,主要使用Sklearn作聚類、用Matplotlib 作圖形展現。數據源文件命名爲clustring.txt。

(2)代碼實現

# 導入庫
import numpy as np  # 導入numpy庫
import matplotlib.pyplot as plt  # 導入matplotlib庫
from sklearn.cluster import KMeans  # 導入sklearn聚類模塊
from sklearn import metrics  # 導入sklearn效果評估模塊

# 數據準備
raw_data = np.loadtxt('./cluster.txt')  # 導入數據文件
X = raw_data[:, :-1]  # 分割要聚類的數據
y_true = raw_data[:, -1]

# 訓練聚類模型
n_clusters = 3  # 設置聚類數量
model_kmeans = KMeans(n_clusters=n_clusters, random_state=0)  # 創建聚類模型對象
model_kmeans.fit(X)  # 訓練聚類模型
y_pre = model_kmeans.predict(X)  # 預測聚類模型

# 模型效果指標評估
n_samples, n_features = X.shape  # 總樣本量,總特徵數
inertias = model_kmeans.inertia_  # 樣本距離最近的聚類中心的總和
adjusted_rand_s = metrics.adjusted_rand_score(y_true, y_pre)  # 調整後的蘭德指數
mutual_info_s = metrics.mutual_info_score(y_true, y_pre)  # 互信息
adjusted_mutual_info_s = metrics.adjusted_mutual_info_score(y_true, y_pre)  # 調整後的互信息
homogeneity_s = metrics.homogeneity_score(y_true, y_pre)  # 同質化得分
completeness_s = metrics.completeness_score(y_true, y_pre)  # 完整性得分
v_measure_s = metrics.v_measure_score(y_true, y_pre)  # V-measure得分
silhouette_s = metrics.silhouette_score(X, y_pre, metric='euclidean')  # 平均輪廓係數
calinski_harabaz_s = metrics.calinski_harabaz_score(X, y_pre)  # Calinski和Harabaz得分
print('總樣本量: %d \t 總特徵數: %d' % (n_samples, n_features))  # 打印輸出樣本量和特徵數量
print(70 * '-')  # 打印分隔線
print('ine\tARI\tMI\tAMI\thomo\tcomp\tv_m\tsilh\tc&h')  # 打印輸出指標標題
print('%d\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%d' % (
    inertias, adjusted_rand_s, mutual_info_s, adjusted_mutual_info_s, homogeneity_s, completeness_s,
    v_measure_s,
    silhouette_s, calinski_harabaz_s))  # 打印輸出指標值
print(70 * '-')  # 打印分隔線
print('簡寫 \t 全稱')  # 打印輸出縮寫和全名標題
print('ine \t 樣本距離最近的聚類中心的總和')
print('ARI \t 調整後的蘭德指數')
print('MI \t 互信息')
print('AMI \t 調整後的互信息')
print('homo \t 同質化得分')
print('comp \t 完整性得分')
print('v_m \t V-measure得分')
print('silh \t 平均輪廓係數')
print('c&h \t Calinski和Harabaz得分')

# 模型效果可視化
centers = model_kmeans.cluster_centers_  # 各種別中心
colors = ['#4EACC5', '#FF9C34', '#4E9A06']  # 設置不一樣類別的顏色
plt.figure()  # 創建畫布
for i in range(n_clusters):  # 循環讀類別
    index_sets = np.where(y_pre == i)  # 找到相同類的索引集合
    cluster = X[index_sets]  # 將相同類的數據劃分爲一個聚類子集
    plt.scatter(cluster[:, 0], cluster[:, 1], c=colors[i], marker='.')  # 展現聚類子集內的樣本點
    plt.plot(centers[i][0], centers[i][1], 'o', markerfacecolor=colors[i], markeredgecolor='k',
             markersize=6)  # 展現各聚類子集的中心
plt.show()  # 展現圖像
複製代碼

結果:

總樣本量: 1000 	 總特徵數: 2
----------------------------------------------------------------------
ine	ARI	MI	AMI	homo	comp	v_m	silh	c&h
300	0.96	1.03	0.94	0.94	0.94	0.94	0.63	2860
----------------------------------------------------------------------
簡寫 	 全稱
ine 	 樣本距離最近的聚類中心的總和
ARI 	 調整後的蘭德指數
MI 	     互信息
AMI 	 調整後的互信息
homo 	 同質化得分
comp 	 完整性得分
v_m 	 V-measure得分
silh 	 平均輪廓係數
c&h 	 Calinski和Harabaz得分
複製代碼

2.3 效果評估

經過不一樣的指標來作聚類效果評估。

(1)樣本距離最近的聚類中心的總和

inertias:inertias是K均值模型對象的屬性,表示樣本距離最近的聚類中心的總和,它是做爲在沒有真實分類結果標籤下的非監督式評估指標。該值越小越好,值越小證實樣本在類間的分佈越集中,即類內的距離越小。

(2) 調整後的蘭德指數

adjusted_rand_s:調整後的蘭德指數(Adjusted Rand Index),蘭德指數經過考慮在預測和真實聚類中在相同或不一樣聚類中分配的全部樣本對和計數對來計算兩個聚類之間的類似性度量。調整後的蘭德指數經過對蘭德指數的調整獲得獨立於樣本量和類別的接近於0的值,其取值範圍爲[-1,1],負數表明結果很差,越接近於1越好意味着聚類結果與真實狀況越吻合。

(3) 互信息

mutual_info_s:互信息(Mutual Information,MI),互信息是一個隨機變量中包含的關於另外一個隨機變量的信息量,在這裏指的是相同數據的兩個標籤之間的類似度的量度,結果是非負值。

(4) 調整後的互信息

adjusted_mutual_info_s:調整後的互信息(Adjusted MutualInformation,AMI),調整後的互信息是對互信息評分的調整得分。它考慮到對於具備更大數量的聚類羣,一般MI較高,而無論其實是否 有更多的信息共享,它經過調整聚類羣的機率來糾正這種影響。當兩個聚類集相同(即徹底匹配)時,AMI返回值爲1;隨機分區(獨立標籤)平均預期AMI約爲0,也可能爲負數。

(5) 同質化得分

homogeneity_s:同質化得分(Homogeneity),若是全部的聚類都只包含屬於單個類的成員的數據點,則聚類結果將知足同質性。其取值範圍[0,1]值越大意味着聚類結果與真實狀況越吻合。

(6) 完整性得分

completeness_s:完整性得分(Completeness),若是做爲給定類的成員的全部數據點是相同集羣的元素,則聚類結果知足完整性。其取值範圍[0,1],值越大意味着聚類結果與真實狀況越吻合。

(7) V-measure得分

v_measure_s:它是同質化和完整性之間的諧波平均值,v=2*(均勻性*完整性)/(均勻性+完整性)。其取值範圍[0,1],值越大意味着聚類結果與真實狀況越吻合。

(8) 輪廓係數

silhouette_s:輪廓係數(Silhouette),它用來計算全部樣本的平均輪廓係數,使用平均羣內距離和每一個樣本的平均最近簇距離來計算, 是一種非監督式評估指標。其最高值爲1,最差值爲-1,0附近的值表示重疊的聚類,負值一般表示樣本已被分配到錯誤的集羣。

(9) 羣內離散與簇間離散的比值

calinski_harabaz_s:該分數定義爲羣內離散與簇間離散的比值,它是一種非監督式評估指標。

3、基於RFM的用戶價值度分析

3.1 案例背景

用戶價值細分是瞭解用戶價值度的重要途徑,而銷售型公司中對於訂單交易尤其關注,所以基於訂單交易的價值度模型將更適合運營需求。

對於用戶價值度模型而言,因爲用戶的狀態是動態變化的,所以通常須要按期更新,業務方的主要需求是至少每週更新一次。因爲要兼顧歷史狀態變化,所以在每次更新時都須要保存歷史數據,不一樣時間點下的數據將經過日期區分。

輸入源數據score.csv

3.2 代碼實現

(1)讀取數據

# 導入庫
import time  # 導入時間庫
import numpy as np  # 導入numpy庫
import pandas as pd  # 導入pandas庫

# 讀取數據
dtypes = {'ORDERDATE': object, 'ORDERID': object, 'AMOUNTINFO': np.float32}  # 設置每列數據類型
raw_data = pd.read_csv('sales.csv', dtype=dtypes, index_col='USERID')  # 讀取數據文件

# 數據審查和校驗
# 數據概覽
print('Data Overview:')
print(raw_data.head(4))  # 打印原始數據前4條
print('-' * 30)
print('Data DESC:')
print(raw_data.describe())  # 打印原始數據基本描述性信息
print('-' * 60)
複製代碼

結果

Data Overview:
         ORDERDATE     ORDERID  AMOUNTINFO
USERID                                    
142074  2016-01-01  4196439032      9399.0
56927   2016-01-01  4198324983      8799.0
87058   2016-01-01  4191287379      6899.0
136104  2016-01-01  4198508313      5999.0
------------------------------
Data DESC:
         AMOUNTINFO
count  86127.000000
mean     744.762939
std     1425.194336
min        0.500000
25%       13.000000
50%       59.000000
75%      629.000000
max    30999.000000
複製代碼

(2)缺失值審查

# 缺失值審查
na_cols = raw_data.isnull().any(axis=0)  # 查看每一列是否具備缺失值
print('NA Cols:')
print(na_cols)  # 查看具備缺失值的列
print('-' * 30)
na_lines = raw_data.isnull().any(axis=1)  # 查看每一行是否具備缺失值
print('NA Recors:')
print('Total number of NA lines is: {0}'.format(na_lines.sum()))  # 查看具備缺失值的行總記錄數
print(raw_data[na_lines])  # 只查看具備缺失值的行信息
print('-' * 60)
複製代碼

結果

NA Cols:
ORDERDATE      True
ORDERID       False
AMOUNTINFO     True
dtype: bool
------------------------------
NA Recors:
Total number of NA lines is: 10
         ORDERDATE     ORDERID  AMOUNTINFO
USERID                                    
75849   2016-01-01  4197103430         NaN
103714         NaN  4136159682       189.0
155209  2016-01-01  4177940815         NaN
139877         NaN  4111956196         6.3
54599   2016-01-01  4119525205         NaN
65456   2016-01-02  4195643356         NaN
122134  2016-09-21  3826649773         NaN
116995  2016-10-24  3981569421         NaN
98888   2016-12-06  3814398698         NaN
145951  2016-12-29  4139830098         NaN
複製代碼

(3)異常值處理

# 數據異常、格式轉換和處理
# 異常值處理
sales_data = raw_data.dropna()  # 丟棄帶有缺失值的行記錄
sales_data = sales_data[sales_data['AMOUNTINFO'] > 1]  # 丟棄訂單金額<=1的記錄

# 日期格式轉換
sales_data['ORDERDATE'] = pd.to_datetime(sales_data['ORDERDATE'], format='%Y-%m-%d')  # 將字符串轉換爲日期格式
print('Raw Dtypes:')
print(sales_data.dtypes)  # 打印輸出數據框全部列的數據類型
print('-' * 60)

# 數據轉換
recency_value = sales_data['ORDERDATE'].groupby(sales_data.index).max()  # 計算原始最近一次訂單時間
frequency_value = sales_data['ORDERDATE'].groupby(sales_data.index).count()  # 計算原始訂單頻率
monetary_value = sales_data['AMOUNTINFO'].groupby(sales_data.index).sum()  # 計算原始訂單總金額
複製代碼

結果

Raw Dtypes:
ORDERDATE     datetime64[ns]
ORDERID               object
AMOUNTINFO           float32
dtype: object
複製代碼

(4)計算RFM得分

# 計算RFM得分
# 分別計算R、F、M得分
deadline_date = pd.datetime(2017, 0o1, 0o1)  # 指定一個時間節點,用於計算其餘時間與該時間的距離
r_interval = (deadline_date - recency_value).dt.days  # 計算R間隔
r_score = pd.cut(r_interval, 5, labels=[5, 4, 3, 2, 1])  # 計算R得分
f_score = pd.cut(frequency_value, 5, labels=[1, 2, 3, 4, 5])  # 計算F得分
m_score = pd.cut(monetary_value, 5, labels=[1, 2, 3, 4, 5])  # 計算M得分

# R、F、M數據合併
rfm_list = [r_score, f_score, m_score]  # 將r、f、m三個維度組成列表
rfm_cols = ['r_score', 'f_score', 'm_score']  # 設置r、f、m三個維度列名
rfm_pd = pd.DataFrame(np.array(rfm_list).transpose(), dtype=np.int32, columns=rfm_cols,
                      index=frequency_value.index)  # 創建r、f、m數據框
print('RFM Score Overview:')
print(rfm_pd.head(4))
print('-' * 60)
複製代碼

結果

RFM Score Overview:
        r_score  f_score  m_score
USERID                           
51220         4        1        1
51221         2        1        1
51224         3        1        1
51225         4        1        1
複製代碼

(5)計算RFM總得分

# 計算RFM總得分
# 方法一:加權得分
rfm_pd['rfm_wscore'] = rfm_pd['r_score'] * 0.6 + rfm_pd['f_score'] * 0.3 + rfm_pd['m_score'] * 0.1
# 方法二:RFM組合
rfm_pd_tmp = rfm_pd.copy()
rfm_pd_tmp['r_score'] = rfm_pd_tmp['r_score'].astype(np.str)
rfm_pd_tmp['f_score'] = rfm_pd_tmp['f_score'].astype(np.str)
rfm_pd_tmp['m_score'] = rfm_pd_tmp['m_score'].astype(np.str)
rfm_pd['rfm_comb'] = rfm_pd_tmp['r_score'].str.cat(rfm_pd_tmp['f_score']).str.cat(
    rfm_pd_tmp['m_score'])

# 打印輸出和保存結果
# 打印結果
print('Final RFM Scores Overview:')
print(rfm_pd.head(4))  # 打印數據前4項結果
print('-' * 30)
print('Final RFM Scores DESC:')
print(rfm_pd.describe())

# 保存RFM得分到本地文件
rfm_pd.to_csv('sales_rfm_score.csv')  # 保存數據爲csv
複製代碼

結果

Final RFM Scores Overview:
        r_score  f_score  m_score  rfm_wscore rfm_comb
USERID                                                
51220         4        1        1         2.8      411
51221         2        1        1         1.6      211
51224         3        1        1         2.2      311
51225         4        1        1         2.8      411
------------------------------
Final RFM Scores DESC:
            r_score       f_score       m_score    rfm_wscore
count  59676.000000  59676.000000  59676.000000  59676.000000
mean       3.299970      1.013439      1.000134      2.384027
std        1.402166      0.116017      0.018307      0.845380
min        1.000000      1.000000      1.000000      1.000000
25%        2.000000      1.000000      1.000000      1.600000
50%        3.000000      1.000000      1.000000      2.200000
75%        5.000000      1.000000      1.000000      3.400000
max        5.000000      5.000000      5.000000      5.000000
複製代碼

3.3 效果評估

因爲在RFM劃分時,將區間劃分爲5份,所以能夠將這5份區間分別定義了:高、中、通常、差和很是差5個級別,分別對應到R、F、M中的5/4/3/2/1。

基於RFM得分業務方獲得這樣的結論:

  • 公司的會員中99%以上的客戶消費狀態都不容樂觀,主要體如今消費頻率低R、消費總金額低M。——通過分析,這裏主要因爲其中有一個用戶(ID爲74270)消費金額很是高,致使作5分位時收到最大值的影響,區間向大值域區偏移。
  • 公司中有一些典型客戶的整個貢獻特徵明顯,重點是RFM得分爲555的用戶(ID爲74270),該用戶不只影響了訂單金額高,並且其頻率和購買新鮮度和消費頻率都很是高,應該引發會員管理部門的重點關注。
  • 本週表現處於通常水平以上的用戶的比例(R、F、M三個維度得分均在3以上的用戶數)相對上週環比增加了1.3%。這種良好趨勢體現了活躍度的提高。
  • 本週低價值(R、F、M得分爲111以上)用戶名單中,新增了1221個新用戶,這些新用戶的列表已經被取出。
相關文章
相關標籤/搜索