[機器學習筆記] 用Python進行航空公司客戶價值分析筆記

用Python進行航空公司客戶價值分析(數據分析)

學習資料:

參考圖書:《Python數據分析與挖掘實戰》(機械工業出版社)第7章

參考博文:https://blog.csdn.net/a857553315/article/details/79177524

https://blog.csdn.net/weixin_39722361/article/details/79225305?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

https://www.kesci.com/home/project/5a71818f94eaea7410491462


目標

書中介紹了背景,要求根據背景通過數據挖掘實現如下目標:

  • 藉助航空公司客戶數據,對客戶進行分類
  • 對不同的客戶類別進行特徵分析,比較不同客戶的客戶價值
  • 對不同價值的客戶類別提供個性化服務,制定相應的營銷策略

分析方法和過程

FRM模型(Frequency Recency Monetary)

F:消費頻率

R:最近消費時間間隔

M:消費金額

傳統的RFM模型分析的屬性分箱方法,如圖所示。它是依據屬性的平均值進行劃分,其中大於平均值得表示爲向上的箭頭(↑),小於平均值的表示爲向下的箭頭(↓),雖然也能夠識別出最具有價值的客戶,但是細分的客戶羣太多,提高了針對性營銷的成本。

書中採用了LRFMC模型的五個指標進行K-Means聚類,識別出最有價值的客戶。

L:客戶關係長度

R:消費時間間隔

F:消費頻率

M:飛行里程

C:平均值

爲什麼選擇這五個指標呢?

  • 選擇客戶在一定時間內積累的飛行里程M和客戶在一定時間內乘坐艙位所對應的折扣係數的平均值C兩個指標代替了消費金額。
  • 考慮航空公司會員入會時間的長短在一定程度上能夠影響客戶價值,所以在模型中增加客戶關係長度L,作爲區分客戶的另一指標。

指標含義:

模型 L R F M C
LRFMC模型 會員入會時間距觀測窗口結束的月數 客戶最近一次乘坐公司飛機距觀測窗口結束的月數 客戶在觀測窗口內乘坐公司飛機的次數 客戶在觀測窗口內累計的飛行里程 客戶在觀測窗口內乘坐艙位所對應的折扣系統的平均值

分析步驟:

(1)從航空公司的數據源中進行選擇性抽取與新增數據抽取分別形成歷史數據和增量數據;

(2)對步驟(1)中形成的兩個數據集進行數據探索分析(EDA)與預處理,包括數據缺失值與異常值的探索分析,數據的屬性規約、清洗和變換。

(3)對步驟(2)中形成的已完成數據預處理的建模數據,基於旅客價值LRFMC模型進行客戶分羣,對各個客戶羣進行特徵分析,識別出有價值的客戶;

(4)針對模型結果得到不同價值的客戶,採用不同的營銷手段,提供定製化的服務。


數據探索分析(EDA)實施

省略一些代碼……

explore = data.describe(percentiles = [], include = 'all').T #包括對數據的基本描述,percentiles參數是指定計算多少的分位數表(如1/4分位數、中位數等);T是轉置,轉置後更方便查閱
explore['null'] = len(data)-explore['count'] #describe()函數自動計算非空值數,需要手動計算空值數

explore = explore[['null', 'max', 'min']]
explore.columns = [u'空值數', u'最大值', u'最小值'] #表頭重命名
'''這裏只選取部分探索結果。
describe()函數自動計算的字段有count(非空值數)、unique(唯一值數)、top(頻數最高者)、freq(最高頻數)、mean(平均值)、std(方差)、min(最小值)、50%(中位數)、max(最大值)'''

explore.to_excel(resultfile) #導出結果

接下來進行數據預處理。

 


數據預處理

採用數據清洗、屬性規約與數據變換等預處理方法。

通過EDA分析,發現數據中存在缺失值,票價最小值爲0,折扣率最小值爲0,總飛行公里數大於0的記錄。

由於原始數據量大,這類數據所佔據比例較小,對於問題影響不大,因此對其進行丟棄處理。

具體方法如下:

  • 丟棄票價爲空的記錄
  • 丟棄票價爲0、平均折扣率不爲0、總飛行公里數大於0的記錄

 

通過觀測可知,數據集中存在票價爲零但是飛行公里大於零的不合理值,但是所佔比例較小,這裏直接刪去

只保留票價非零的,或者平均折扣率與總飛行公里數同時爲0的記錄。

 刪除後剩餘的樣本值是62044個,可見異常樣本的比例不足1.5%,因此不會對分析結果產生較大的影響。

屬性規約

選擇與LRFMC指標相關的6個屬性。刪除與其不相關、弱相關或者冗餘的屬性。

原始數據集的特徵屬性太多,而且各屬性不具有降維的特徵,故這裏選取幾個對航空公司來說比較有價值的幾個特徵進行分析,這裏並沒有完全按照書中的做法選取特徵,最終選取的特徵是第一年總票價、第二年總票價、觀測窗口總飛行公里數、飛行次數、平均乘機時間間隔、觀察窗口內最大乘機間隔、入會時間、觀測窗口的結束時間、平均折扣率這八個特徵。下面說明這麼選的理由:

  • 選取的特徵是第一年總票價、第二年總票價、觀測窗口總飛行公里數是要計算平均飛行每公里的票價,因爲對於航空公司來說並不是票價越高,飛行公里數越長越能創造利潤,相反而是那些近距離的高等艙的客戶創造更大的利益。
  • 當然總飛行公里數、飛行次數也都是評價一個客戶價值的重要的指標
  • 入會時間可以看出客戶是不是老用戶及忠誠度
  • 通過平均乘機時間間隔、觀察窗口內最大乘機間隔可以判斷客戶的乘機頻率是不是固定
  • 平均折扣率可以反映出客戶給公里帶來的利益,畢竟來說越是高價值的客戶享用的折扣率越高

 對特徵進行變換:

 

由於不同的屬性相差範圍較大,這裏進行標準化處理

對於K-Means方法,k的取值是一個難點,因爲是無監督的聚類分析問題,所以不尋在絕對正確的值,需要進行研究試探。這裏採用計算SSE的方法,嘗試找到最好的K數值。編寫函數如下:
def distEclud(vecA, vecB):
    """
    計算兩個向量的歐式距離的平方,並返回
    """
    return np.sum(np.power(vecA - vecB, 2))
 
def test_Kmeans_nclusters(data_train):
    """
    計算不同的k值時,SSE的大小變化
    """
    data_train = data_train.values
    nums=range(2,10)
    SSE = []
    for num in nums:
        sse = 0
        kmodel = KMeans(n_clusters=num, n_jobs=4)
        kmodel.fit(data_train)
        # 簇中心
        cluster_ceter_list = kmodel.cluster_centers_
        # 個樣本屬於的簇序號列表
        cluster_list = kmodel.labels_.tolist()
        for index in  range(len(data)):
            cluster_num = cluster_list[index]
            sse += distEclud(data_train[index, :], cluster_ceter_list[cluster_num])
        print("簇數是",num , "時; SSE是", sse)
        SSE.append(sse)
    return nums, SSE
 
nums, SSE = test_Kmeans_nclusters(filter_zscore_data)

 畫圖

#畫圖,通過觀察SSE與k的取值嘗試找出合適的k值
# 中文和負號的正常顯示
plt.rcParams['font.sans-serif'] = 'SimHei'
plt.rcParams['font.size'] = 12.0
plt.rcParams['axes.unicode_minus'] = False
# 使用ggplot的繪圖風格
plt.style.use('ggplot')
## 繪圖觀測SSE與簇個數的關係
fig=plt.figure(figsize=(10, 8))
ax=fig.add_subplot(1,1,1)
ax.plot(nums,SSE,marker="+")
ax.set_xlabel("n_clusters", fontsize=18)
ax.set_ylabel("SSE", fontsize=18)
fig.suptitle("KMeans", fontsize=20)
plt.show()

 

 觀察圖像,並沒有的所謂的“肘”點出現,是隨k值的增大逐漸減小的,這裏選取當k分別取4, 5, 6時進行,看能不能通過分析結果來反向選取更合適的值,k取值4時的代碼如下:

kmodel = KMeans(n_clusters=4, n_jobs=4)
kmodel.fit(filter_zscore_data)
# 簡單打印結果
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(filter_zscore_data.columns) + [u'類別數目'] #重命名錶頭
 
# 繪圖
fig=plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, polar=True)
center_num = r.values
feature = ["入會時間", "飛行次數", "平均每公里票價", "總里程", "時間間隔差值", "平均折扣率"]
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()

 分別取 k=5;k=6時,做出雷達圖進行分析。

 


結論

通過觀察可知:

  • 當k取值4時,每個人羣包含的信息比較複雜,且特徵不明顯
  • 當k取值5時,分析的結果比較合理,分出的五種類型人羣都有自己的特點又不相互重複
  • 當k取值6時,各種人羣也都有自己的特點,但是第4簇人羣完全在第5簇人羣特徵中包含了,有點冗餘的意思

綜上,當k取值爲5時,得到最好的聚類效果,將所有的客戶分成5個人羣,再進一步分析可以得到以下結論:

  • 第一簇人羣,10957人,最大的特點是時間間隔差值最大,分析可能是“季節型客戶”,一年中在某個時間段需要多次乘坐飛機進行旅行,其他的時間則出行的不多,這類客戶我們需要在保持的前提下,進行一定的發展;
  • 第二簇人羣,14732人,最大的特點就是入會的時間較長,屬於老客戶按理說平均折扣率應該較高才對,但是觀察窗口的平均折扣率較低,而且總里程和總次數都不高,分析可能是流失的客戶,需要在爭取一下,儘量讓他們“回心轉意”;
  • 第三簇人羣,22188人,各方面的數據都是比較低的,屬於一般或低價值用戶
  • 第三簇人羣,8724人,最大的特點就是平均每公里票價和平均折扣率都是最高的,應該是屬於乘坐高等艙的商務人員,應該重點保持的對象,也是需要重點發展的對象,另外應該積極採取相關的優惠政策是他們的乘坐次數增加
  • 第五簇人羣,5443人, 總里程和飛行次數都是最多的,而且平均每公里票價也較高,是重點保持對象
  • 分析完畢,結果暗合市場的二八法則的,價值不大的第二三簇的客戶數最多,而價值較大的第四五簇的人數較少。
     

持續更新

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章