聚類算法屬於無監督學習的一種,而其中KMeans算法是比較常用的聚類算法。
主要思想是: 1、在給定K值和K個初始類簇中心點的情況下,把每個點(亦即數據記錄)分到離其最近的類簇中心點所代表的類簇中。 2、 所有點分配完畢之后,根據一個類簇內的所有點重新計算該類簇的中心點(取平均值)。 3、再迭代的進行分配點和更新類簇中心點的步驟,直至類簇中心點的變化很小,或者達到指定的迭代次數。
本文數據量:62988,
第一步:數據探索
拿到數據集,先進行整體上的觀察
import pandas as pd
import numpy as np
df = pd.read_csv( 'air_data.csv', encoding = 'utf-8') #讀取原始數據,指定UTF-8編碼(需要用文本編輯器將數據裝換為UTF-8編碼)
print(df.shape)
print(df.info)
看看前5行
df.head()
簡單加工一下44屬性名稱
進行空值,最小,最大值的計算
ex = df.describe(percentiles = [], include = 'all').T #包括對數據的基本描述,percentiles參數是指定計算多少的分位數表(如1/4分位數、中位數等);T是轉置,轉置后更方便查閱
ex['null'] = len(df)- ex['count'] #describe()函數自動計算非空值數,需要手動計算空值數
ex = ex[['null', 'max', 'min']]
ex.columns = [u'空值數', u'最大值', u'最小值'] #表頭重命名
ex
發現數據集存在票價為空,總飛行公里數大於0的臟數據
具體處理方法如下: 刪去票價為0的數據 及票價為0,折扣率不為0,總飛行公里數大於0的記錄
第二步:數據清洗
df= df[df['SUM_YR_1'].notnull()&df['SUM_YR_2'].notnull()] #票價非空值才保留
#只保留票價非零的,或者平均折扣率與總飛行公里數同時為0的記錄。
index1 = df['SUM_YR_1'] != 0
index2 = df['SUM_YR_2'] != 0
index3 = (df['SEG_KM_SUM'] == 0) & (df['avg_discount'] == 0) #該規則是刪去臟數據,要么有飛有折扣有公里數,要么就都是折扣為0且里程數為0
df= df[index1 | index2 | index3] #該規則是“或”
df.T
最終得到62044樣本量
第三步 數據規約
在客戶分類中,RFM模型是一個經典的分類模型,——最近消費(Recency)、消費頻率(Frequency)、消費金額(Monetary)細分客戶群體,從而分析不同群體的客戶價值。
同樣金額的不同旅客對公司的價值是不同的,比如買長航線低等級艙位的旅客與短途高等級艙位旅客相比,后者相對價值更高。因此,M消費金額不能用於衡量客戶價值的一個因素,我們將其分解成兩個。一定時間內的飛行里程M,一定時間內所坐艙位的平均折扣系數C。
最終我們選擇: L(客戶入會時間距今月數)、 R(客戶最近一次乘機時間距今月數)、 F(客戶在樣本時間內乘機次數)、 M(客戶在樣本時間內的飛行里程)、 C(客戶在樣本時間內乘坐艙位的平均折扣系數) 因此,我們選擇入會時間(FFP_date)、樣本觀測結束時間LOAD TIME、飛行次數(flight count)、平均折扣率(AVG DISCOUNT)、總飛行公里數(seg-km-sum)、最后一次乘機時間距今時長(last to end)這6個屬性進行分析,刪去其他弱相關屬性
第四步 數據轉換–LRMFC
L=LOAD_TIME-FFP_DATE(入會時長)
R=LAST_TO_END(最近一次乘機時間)
F=FLIGHT_COUNT(頻次)
M=SEG_KM_SUM(飛行公里數)
C=AVG_DISCOUNT(平均折扣率)
df['LOAD_TIME']=pd.to_datetime(df['LOAD_TIME']) #將字符串格式轉換為日期格式
df['FFP_DATE'] = pd.to_datetime(df['FFP_DATE'])
df['L']=df['LOAD_TIME']- df['FFP_DATE']
#特征提取,只選L,LAST_TO_END,SEG_KM_SUM,avg_discount
#即入會時間離觀測結束的天數,最近一次乘機的月數,觀測窗口的飛行次數,總飛行里程,折扣平均
df1 = df[['L','LAST_TO_END','SEG_KM_SUM','FLIGHT_COUNT','avg_discount']]
df1=df1.rename(
columns = {'L':'L入會時間','LAST_TO_END':'R最近消費距今時間','SEG_KM_SUM':'M總里程','FLIGHT_COUNT':'F飛行次數','avg_discount':'C平均折扣率'},
inplace = False
)
df1.head()
觀察一下各組數據間的最大最小值
由於不同的屬性相差范圍較大,這里進行標准化處理
##數據標准化
df1 = (df1 - df1.mean(axis = 0))/(df1.std(axis = 0)) #簡潔的語句實現了標准化變換,類似地可以實現任何想要的變換。
df1.columns=['Z'+i for i in df1.columns] #表頭重命名。
df1.head()
第五步 模型構建
首先采用無監督學習中K-means 進行模型構建,首先根據上述5個客戶指標進行聚類,其次根據結果結合業務針對不同客戶群進行分析,並進行排名。
K-Means算法主要就在於k=n_cluster參數的確定上面,到底是將k確定為幾能進行更好的分類.因為是無監督的聚類分析問題,所以不存在絕對正確的值,需要進行研究試探。
這里采用計算SSE(肘點)的方法,嘗試找到最好的K數值。
SSE值代表了每一個數據點離聚類中心的距離的評分,即為誤差平方。當k小於真實聚類數時,隨着k增大數據之間的聚合度會增加,SSE下降幅度會很大,當k快達到真實聚類值時,SSE下降幅度會變平穩,就想一個手肘的形狀,肘點即為最優k值。
注:剛學完吳恩達機器學習,其實有時候K值也要參考實際商業價值來決定,例如賣T恤,是只賣3種型號,S、M、L還是xs,s,m,l,xl,等,哪種更符合人群,影響后續銷量,這些都不一定是靠肘點能得到的,這點要注意。
代碼如下
##模型構建
from sklearn.cluster import KMeans #導入K均值聚類算法
import matplotlib.pyplot as plt
SSE = []
for k in range(1,9):
estimator = KMeans(n_clusters=k)
estimator.fit(df1)
SSE.append(estimator.inertia_)#樣本到最近的聚類中心的距離平方之和
X = range(1,9)
plt.xlabel('k')
plt.ylabel('SSE')
plt.plot(X,SSE,'o-')
plt.show()
觀察圖像,並沒有的所謂的“肘”點出現,基本上是隨k值的增大逐漸減小的。在k=4,5這段區間變化放緩 設K=5
#取k=5進行的類別聚類
k = 5
#df1中讀取數據並進行聚類分析
#調用k-means算法#
kmodel = KMeans(n_clusters = k, n_jobs = 4) #n_jobs是並行數,一般等於CPU數較好
kmodel.fit(df1) #訓練模型
kmodel.cluster_centers_ #查看聚類中心
kmodel.labels_ #查看各樣本對應的類別
r1 = pd.Series(kmodel.labels_).value_counts() #統計各個類別的數目 r2 = pd.DataFrame(kmodel.cluster_centers_)#找出聚類中心 # 所有簇中心坐標值中最大值和最小值 max = r2.values.max() min = r2.values.min() r = pd.concat([r2, r1], axis = 1) #橫向連接(0是縱向),得到聚類中心對應的類別下的數目 r.columns = list(df1.columns) + [u'各類別人數'] #重命名表頭 r
第六步 繪制可視化雷達圖
注:此部分代碼主要參考
##繪圖 ## 中文和負號的正常顯示 plt.rcParams['font.sans-serif'] = 'SimHei' plt.rcParams['font.size'] = 12.0 plt.rcParams['axes.unicode_minus'] = False fig=plt.figure(figsize=(10, 8)) ax = fig.add_subplot(111, polar=True) center_num = r.values feature = ["L入會時間", "R最近消費距今時間", "M總里程", "F飛行次數程", "C平均折扣率"] N =len(feature) for i, v in enumerate(center_num): # 設置雷達圖的角度,用於平分切開一個圓面 angles=np.linspace(0, 2*np.pi, N, endpoint=False) # 為了使雷達圖一圈封閉起來,需要下面的步驟 center = np.concatenate((v[:-1],[v[0]])) angles=np.concatenate((angles,[angles[0]])) # 繪制折線圖 ax.plot(angles, center, 'o-', linewidth=2, label = "第%d簇人群,%d人"% (i+1,v[-1])) # 填充顏色 ax.fill(angles, center, alpha=0.25) # 添加每個特征的標簽 ax.set_thetagrids(angles * 180/np.pi, feature, fontsize=15) # 設置雷達圖的范圍 ax.set_ylim(min-0.1, max+0.1) # 添加標題 plt.title('客戶群特征分析圖', fontsize=20) # 添加網格線 ax.grid(True) # 設置圖例 plt.legend(loc='upper right', bbox_to_anchor=(1.3,1.0),ncol=1,fancybox=True,shadow=True) # 顯示圖形 plt.show()
第七步 總結分析
基於LRFMC模型的具體含義,我們可以對這5個客戶群進行價值排名。同時,將這5個客戶群重新定義為五個等級的客戶類別:重要保持客戶,重要挽留客戶,重要發展客戶,一般發展客戶,低價值客戶。 注意:每次跑出來的類型順序會不一樣,要做好辨別。
對應客戶群1: 重要保持客戶:這類客戶乘坐的次數(F)和飛行的里程數(M)都很高。折扣率(C)和入會時間(L)也不低,說明他們經常乘坐飛機,且有一定經濟實力,是航空公司的高價值客戶。
對應客戶群2 最大的特點是時間間隔差值(R)最大,其他指標表現一般,分析可能是“季節型客戶”,一年中可能有一段時間需要乘坐飛機進行旅行等等,屬於一般發展客戶
對應客戶群3 重要挽留客戶:這類客戶最大的特點就是入會的時間(L)較長,入會時間長(L),平均折扣率較低,而且總里程和總次數都不高,分析可能是流失的客戶,需要在爭取一下,盡量讓他們“回心轉意”;
對應客戶群4: 重要發展客戶:這類客戶平均折扣率很高(C),最近乘坐過本航班時間間隔(R)短,但是乘坐的次數(F)和(M)都很低,成為會員的時間也很近(L),說明這些乘客剛入會員不久,所以乘坐飛機次數少,是未來重要發展客戶。
對應客戶群5
低價值客戶:這類客戶乘坐時間間隔長(R)或乘坐次數(F)和總里程(M)低,平均折扣也很低,各方面的數據都是比較低的
最終將表格的客戶進行分類
df1['聚類類別'] = kmodel.labels_ #划分客戶類別 for i in range(len(df1)): if df1['聚類類別'][i] == 0: df1['聚類類別'][i] = '重要保持客戶' elif df1['聚類類別'][i] == 1: df1['聚類類別'][i] = '一般發展客戶' elif df1['聚類類別'][i] == 2: df1['聚類類別'][i] = '重要挽留客戶' elif df1['聚類類別'][i] == 3: df1['聚類類別'][i] = '重要發展客戶' else: df1['聚類類別'][i] = '低價值客戶' #重命名屬性 df1.columns = ['L','R','M','F','C','客戶類別']
結果如下
參考文章:
保持渴求,不要沉寂