客戶流失預警分析(簡易版)

一.商業理解

1.商業背景

  在國內航空行業競爭日益激烈的情形下,獲得一個新客戶所付出的成本遠遠大於挽留一個老客戶,因爲獲得一個新客戶需要在宣傳、項目、建立客戶資料及維持客戶關係方面耗費巨大的人力物力,而挽留一個老客戶只需在維持客戶關係方面提高他的忠誠度即可,所以留住一名現有客戶比吸引一名新客戶更具有價值,因此老客戶的流失給公司帶來的損失是非常巨大的。而客戶爲航空公司帶來的利潤主要是根據客戶的生命週期決定的,客戶的生命週期越長,給公司帶來的利潤就會越多,所以如何延長流失的客戶的生命週期就成爲了航空公司佔領市場份額的決定性策略。然而,延長流失客戶的生命週期的前提是航空公司能準確地預測即將流失的客戶,因此分析客戶的流失顯得非常必要,根據分析得出航空公司客戶流失的一些規則,基於流失客戶的一些共同特徵,航空公司可以據此提出相應對策和改進措施來保留客戶和預防潛在客戶流失,進而提高航空公司競爭力。

2.商業目標

  對可能流失的高價值的客戶做出相應的措施,幫助營銷部門確定客戶挽留市場活動的目標客戶羣體以及合適的營銷方案,以延長生命週期,提高航空公司的上座率,增加公司收益。分成以下分目標:

  • 預測那些用戶可能會流失?
  • 可能流失的客戶特徵是什麼?
  • 市場挽留活動的預計收益?

3.工具與技術的評估

開發工具:Mysql、Excel、SPPS Modeler、Python(Scipy、SK-learn)
  應用Excel的篩選、頻率圖對數據的分佈狀況、是否缺少進行了解,並使用SPPS Modeler進行快速的數據處理和初步的數據探索性分析,並把最終數據集導入到Mysql數據庫中,接着使用Python機器學習與matplotlib視圖化方式,進行一步的探索與挖掘數據統計規律。

二、數據理解及數據準備

1.數據理解

  數據集測量的時間窗口爲某航空公司連續兩年的運營數據,共有62986條會員數據個案,每個個案有56個變量,包括客戶基本信息(例如:會員卡號、年齡、性別等),客戶乘坐記錄(例如:總乘坐次數、總飛行次數、總積分等)以及一個流失標記變量(流失記爲1,未流失記爲0)。

2.數據清洗及數據構建

  利用Excel篩選、頻率分佈以及SPSS Modeler數據審覈,確定缺失數據的變量,根據數據缺失佔比以及對目標的影響程度,選擇丟棄或填充;迴繞業務目標,衍生反應客戶行爲的統計類指標。

  1. 性別、年齡,第1第2年總票價缺失較少,對流失目標影響較小,選擇丟棄處理;
  2. 衍生總票價以兩年票價求和,作爲衡量客戶價值指標;

航空客戶數據準備

圖 2-1 航空客戶數據準備

3.數據探索性分析

(1)離散變量的探索性分析

  1)會員等級與流失標誌

性別與流失

圖 2-3 會員等級與流失標誌

  分析:從圖2-3可知,會員等級4客戶人數最多,達到了92.17%,同時也是流失人數比例最高,相對於會員等級5、6恰好相反,特別會員等級5流失率最低,形成向中間等級流失率低的趨勢,可以適當調整會員等級的劃分,特別是提高有價值的會員等級4客戶。

  2)客戶性別與流失標誌

客戶性別與流失標誌

圖 2-4 客戶性別與流失標誌

  分析:從圖 2-4可知,主要客戶羣體爲男性客戶,佔到了四分之三,女性客戶相對較少,並且流失比例也是最高的,反應了航空公司對女性客戶的服務可能存在不足,建議航空公司推出一些關愛女性的活動,以吸引女性客戶,提高女性客戶的忠誠度和滿意度。

(2)連續變量的探索性分析

在這裏插入圖片描述

圖 2-5 統計量指標與流水標誌

  分析:統計指標中的平均乘機時間間隔、入會時長、總票價、觀測窗口總基本積分、觀測窗口總飛行公里數、飛行次數等,總的流失趨勢爲上述指標取值越小,流失的可能性就越高。

三、建立模型

1.建模前的特徵選擇

  特徵集數量較多,並且目標變量爲離散型變量,因此選擇的樹模型和隨機稀釋模型爲分類類型的,並運用集合(Set)交集運算,SelectFromModel模塊確定特徵。

特徵選擇

圖 3-1 交集特徵選擇

'''去除方差小的特徵'''
from sklearn.feature_selection import VarianceThreshold
'''RFE_CV'''
from sklearn.ensemble import ExtraTreesClassifier
'''隨機稀疏模型'''
from sklearn.linear_model import RandomizedLogisticRegression
'''特徵選擇'''
from sklearn.feature_selection import SelectFromModel
class FeatureSelection(object):
    def __init__(self,DataFrame):
        self.train_test=DataFrame.drop(['會員卡號','流失標誌'],axis=1)    # features #
        self.label =DataFrame['流失標誌']                                 # target   #
        self.feature_name = list(self.train_test.columns)                 # feature name #
    
    def variance_threshold(self):  #方差選擇
        sel = VarianceThreshold(threshold=(.8 * (1 - .8)))
        feature_num=sel.fit_transform(self.train_test,self.label).shape[1]
        feature_var = list(sel.variances_)                      # feature variance #
        features = dict(zip(self.feature_name, feature_var))
        features = list(dict(sorted(features.items(), key=lambda d: d[1])).keys())[-feature_num:]
        return set(features)   # return set type #
    def tree_select(self):        #樹模型選擇
        clf = ExtraTreesClassifier(n_estimators=300, max_depth=7, n_jobs=4).fit(self.train_test,self.label)
        model= SelectFromModel(clf, prefit=True)                         #feature select#
        feature_num= model.transform(self.train_test).shape[1]           
        feature_var = list(clf.feature_importances_)  # feature scores #
        features = dict(zip(self.feature_name, feature_var))
        features = list(dict(sorted(features.items(), key=lambda d: d[1])).keys())[-feature_num:]
        return set(features)  # return set type #
    def rlr_select(self):         #隨機稀釋模型選擇
        clf = RandomizedLogisticRegression()
        feature_num= clf.fit_transform(self.train_test,self.label).shape[1]           
        feature_var = list(clf.scores_)  # feature scores #
        features = dict(zip(self.feature_name, feature_var))
        features = list(dict(sorted(features.items(), key=lambda d: d[1])).keys())[-feature_num:]
        return set(features)  # return set type #
    def return_feature_set(self, variance_threshold=False,tree_select=False,rlr_select=False):
        names = set([])
        if variance_threshold is True:
            name_one = self.variance_threshold()
            names = names.union(name_one)
        if tree_select is True:
            name_two = self.tree_select()
            names = names.intersection(name_two)
        if rlr_select is True:
            name_three = self.rlr_select()
            names = names.intersection(name_three)
        return list(names)

2.聚類分析–刻畫用戶流失特徵

(1)初步聚類 – 確定高價值用戶

  根據業務目標,劃分爲低中高流失率的客戶聚體,確定聚類數爲3,選擇衡量客戶價值的“會員卡級別、總票價,總累計積分”等指標,對客戶羣體進行聚類。

from sklearn.cluster import KMeans
new_df = df  
feature = new_df[['會員卡級別','總票價','總累計積分']]    
#初步聚類  
kmean = KMeans(n_clusters=3, random_state=10).fit(feature)
new_df['jllable'] = kmean.labels_
#繪製圖表比較
Mean = feature.groupby(kmean.labels_).mean()
figsize=11,12
index=Mean.index
colors=['r','y','b']
fig,ax=plt.subplots(nrows=3,ncols=1,figsize=figsize,facecolor='w',edgecolor='blue',sharex=True, sharey='row') #返回figure、axes對象
#會員卡級別
ax[0].bar(index,Mean['會員卡級別'],color=colors)
ax[0].set_title('會員卡級別',fontstyle='italic',fontsize=12)
for x,y in zip(index,Mean['會員卡級別']):
    ax[0].text(x,y,'%.2f'%y,ha='center',va='bottom',fontsize=12)
#總票價
ax[1].bar(index,Mean['總票價'],color=colors)
ax[1].set_title('總票價',fontstyle='italic',fontsize=12)
for x,y in zip(index,Mean['總票價']):
    ax[1].text(x,y,'%.2f'%y,ha='center',va='bottom',fontsize=12)
#總積分
ax[2].bar(index,Mean['總累計積分'],color=colors)
ax[2].set_title('總累計積分',fontstyle='italic',fontsize=12)
for x,y in zip(index,Mean['總累計積分']):
    ax[2].text(x,y,'%.2f'%y,ha='center',va='bottom',fontsize=12)
plt.xticks(index,['聚類0','聚類1','聚類2'],fontsize=16)
plt.gcf().savefig('Cluster_select.png')
plt.show()

客戶價值比較

圖 2-1 會員等級、總票價、總累計積分比較

  分析:從圖中可知,會員等級、總票價、總累計積分最高的爲聚類2,確定爲高價值客戶聚體,對其進行進一步分析。

(2)進一步聚類

from sklearn.cluster import KMeans
from sklearn.decomposition import PCA
import pandas as pd
import numpy as np
from sklearn import metrics
import matplotlib.pyplot as plt

class Cluster(object):
    ##定義全局屬性##
    __Colors=['r','y','b','c','m','g','k','w']  #顏色
    __Markers=['+','s','*','^','x','o','v','x'] #標記
    __kmean_df=None                     #聚類結果
    __k=None                            #聚類數

    def __init__(self,DataFrame,min_k=3,max_k=9): ## 1.初始化建立聚類##
        ##特徵選擇及數據準備
        new_order = np.random.permutation(len(DataFrame))
        new_df = DataFrame.take(new_order)
        f = FeatureSelection(new_df)
        feature_names = f.return_feature_set(variance_threshold=True,tree_select=True)
        feature = new_df[feature_names]
        #K均值聚類 
        Kmeans=[]   
        for k in range(min_k,max_k):
            kmean = KMeans(n_clusters=k, random_state=10).fit(feature)
            Kmeans.append((k,metrics.calinski_harabaz_score(feature,kmean.labels_),kmean))
        Best_kmean=sorted(Kmeans,key=lambda d: d[1])[-1]   #選擇最好聚類
        feature['jllable']=Best_kmean[-1].labels_
        feature['流失標誌']=new_df['流失標誌']
        self.__k = Best_kmean[0]
        self.__kmean_df = feature
        self.Cluster_assess(Kmeans)                        #輸出效果
        print('分成了%s個聚類!'%self.__k)
        
    def Cluster_assess(self,Kmeans):              ## 2.1聚類效果評價## 
        plt.figure(figsize=(13,5))
        plt.subplot(1,2,1)
        plt.title('Calinski-Harabasz分數值評估')
        plt.xlabel('K')
        plt.ylabel('Scores')
        plt.plot(np.array(Kmeans)[:,0],np.array(Kmeans)[:,1])
        plt.subplot(1,2,2)
        feature=self.__kmean_df.drop(['流失標誌','jllable'],axis=1)
        pca = PCA(n_components=2)
        new_pca = pd.DataFrame(pca.fit_transform(feature))
        plt.title('聚類效果分佈散點圖降維(二維)')
        for i in range(self.__k):
            d = new_pca[self.__kmean_df['jllable']==i]
            plt.plot(d[0], d[1], self.__Colors[i]+self.__Markers[i])
        plt.legend(np.char.add('聚類',list(map(str,range(self.__k)))))
        plt.gcf().savefig('Cluster_assess.png')
        plt.show()
        
    def Cluster_rate(self):                       ## 3.1聚類流失率分析##
        plt.figure(figsize=(13,5))  
        Ser_count_type=self.__kmean_df['jllable'].value_counts()
        Ser_runoff_rate=self.__kmean_df['流失標誌'].groupby(self.__kmean_df['jllable']).mean()
        df_runoff_rate=pd.concat([Ser_count_type,Ser_runoff_rate],axis=1,keys=['客戶數量','流失率'])
        labels=np.char.add('聚類',list(map(str,df_runoff_rate.index)))
        values_count=df_runoff_rate['客戶數量']
        values_rate=df_runoff_rate['流失率']
        plt.subplot(1,2,1)
        plt.title('航空客戶數量餅圖')
        explode=[0]*self.__k
        explode[values_rate.idxmax()]=0.3
        plt.pie(values_count,labels=labels,colors=self.__Colors[:self.__k],explode=explode,startangle=180,
               shadow=True,autopct='%1.2f%%', pctdistance=0.5,textprops = { 'fontsize': 14, 'color': 'k'},
               wedgeprops = { 'linewidth': 1.5, 'edgecolor': 'w'})
        plt.axis('equal')
        plt.subplot(1,2,2)
        plt.title('航空客戶流失率條形圖')
        plt.bar(labels,values_rate,color=self.__Colors[:self.__k])
        plt.grid(True)
        for x,y in zip(labels,values_rate):
            plt.text(x,y,'%.3f'%y,ha='center',va='bottom',fontsize=14)
        plt.gcf().savefig('Cluster_rate.png')
        plt.show()
        
    def Cluster_cmp(self):                       ##3.2聚類特徵變量對比(Z標準化)
        new_df=self.__kmean_df.drop(['流失標誌','jllable'],axis=1).groupby(self.__kmean_df['jllable']).mean()
        result=new_df.copy()
        def f(x):
            return (x-np.mean(x))/np.std(x)
        new_df=new_df.apply(f).T
        barh=new_df.plot(kind='barh',figsize=(17,30),fontsize=20,grid=True,color=self.__Colors[:self.__k])
        barh.legend(np.char.add('聚類',list(map(str,new_df.columns))),fontsize=16,loc=2)
        plt.gcf().savefig('Cluster_cmp.png')
        plt.show()
        return result

在這裏插入圖片描述

圖 3-2 聚類效果圖

  分析:從左圖可知,當聚類數爲5時,Calinski-Harabasz分數值評估值最高(最佳聚類數),因此最終確定聚類數爲5。右圖爲最佳聚類時所繪製的二維散點圖,圖中每個聚類都形成了自己的局域塊,相對比較集中,可進行下一步分析。

(3)聚類結果分析

  1)聚類流失率分析

在這裏插入圖片描述

圖 3-2 聚類流失率

  分析:從圖中可知,

  2)聚類特徵變量比較分析

  通過聚類所得的聚類標誌進行分組,並計算平均值,考慮到每種特徵變量值區差異較大,爲了利於數據間的比較,進行Z標準化
在這裏插入圖片描述

圖 3-2 特徵變量比較

  分析:從圖中可知,橫座標爲0.0爲“平均線“”的位置,位於左邊的低於平均線,右邊的高於平均線,經過比較,得出了以下流失客戶的特徵。

羣組編號 羣組佔比 重要特徵 特徵概況
聚類0 82.74% 總票、總積分、總飛行次數、總公里數總換次數很少;
年乘機次數比率、年裏程下降;
入會時長短、乘機時間間隔大;
客戶價值低,呈現下降趨勢;
乘機頻率低,間隔大;
聚類1 15.58% 總票、總積分、總飛行次數、總公里數總換次數較少;
年乘機次數比率、年裏程積分比例稍有上升;
較高價值客戶,呈現緩慢上升趨勢;
表 3-3 聚類特徵表

  結論從表中可知,客戶流失的最重要特徵爲"客戶價值低且呈下降趨勢,上座率低,下次乘機時間長",因此,營銷活動部門可以根據這一客戶特徵,提前發現即將流失的客戶,採取相應的營銷活動挽留客戶,以延長客戶的使用生命週期,增加航空公司收益。

2.決策樹分析–獲取用戶流失規則

(1) 確定相關參數及建立決策樹

  根據數集有50多個特徵6萬多條數據記錄(訓練集80%,測試集20%),類別分佈有一定的偏倚,類別權重設爲平衡,爲獲得最簡易的流失規則,應用全部特徵選擇,初步確定最大深度爲3,最小劃分節點樣本數爲6,數據預排序。

from sklearn import tree
import os       
import numpy as np
import pandas as pd
from IPython.display import Image  
import pydotplus,math
os.environ["PATH"] += os.pathsep + 'D:\\Program Files (x86)\\Graphviz2.38\\bin'

class Tree(object):              ##1.初始化建立決策樹              
    def __init__(self,DataFrame,max_depth=3): 
        #特徵選擇
        new_order=np.random.permutation(len(DataFrame))
        new_df=DataFrame.take(new_order)
        f=FeatureSelection(new_df)
        self.column_names=f.return_feature_set(variance_threshold=True,tree_select=True,rlr_select=True)
        feature=new_df[self.column_names]
        target=new_df['流失標誌']
        #準備訓練和測試數據
        breakPoint=math.floor(len(feature)*0.2)
        feature_Train=feature[:-breakPoint]
        target_Train=target[:-breakPoint]
        self.feature_Test=feature[-breakPoint:]
        self.target_Test=target[-breakPoint:]
        #分類決策樹
        self.clf = tree.DecisionTreeClassifier(max_depth=max_depth,min_samples_split=6,
                                               min_samples_leaf=3,class_weight='balanced',presort=True)
        self.clf = self.clf.fit(feature_Train,target_Train)
        print('模型準確率爲:%2.2f %%'%(self.clf.score(feature_Train,target_Train)*100))
        print('決策完成!')  

    def Tree_assess(self):        ##2.模型準確率評價
        pre_Test=self.clf.predict(self.feature_Test)
        df_result=pd.DataFrame(np.column_stack((pre_Test,np.array(self.target_Test))),
                               columns=['$C-流失標誌','流失標誌'])
        def a(x):
            if x[0]==x[1]:
                return 1
            else:
                return 0
        df_result['判斷']=df_result.apply(a,axis=1)
        preRate=df_result['判斷'].groupby(df_result['流失標誌']).mean()
        preRT=df_result['判斷'].mean()
        preCount=df_result.groupby([df_result['流失標誌'],df_result['判斷']]).count()
        DT=pd.DataFrame([[preCount['$C-流失標誌'][0.0,0],preCount['$C-流失標誌'][0.0,1],preRate[0.0]],
                        [preCount['$C-流失標誌'][1.0,0],preCount['$C-流失標誌'][1.0,1],preRate[1.0]],
                        [preCount['$C-流失標誌'][0.0,0]+preCount['$C-流失標誌'][1.0,0],
                         preCount['$C-流失標誌'][0.0,1]+preCount['$C-流失標誌'][1.0,1],preRT]],
                         columns=['錯誤數','正確數','準確率'],index=[0,1,'總計']).round(2)    
        return DT
    
    def Tree_view(self):         ##3.1模型結果透視化
        transform=pd.read_csv('中英互釋.csv',engine='python',index_col='中文名')
        dot_data = tree.export_graphviz(self.clf, out_file=None, 
                                 feature_names=list(transform['英文名'][self.feature_Test.columns]),  
                                 class_names=['0','1'],  
                                 filled=True, rounded=True,  
                                 special_characters=True)  
        graph = pydotplus.graph_from_dot_data(dot_data)
        graph.write_pdf("TreeView.pdf")
        return Image(graph.create_png()) 
    
    def Tree_feat_import(self): ##3.2特徵變量重要性
        clf=self.clf
        feature_name=self.column_names
        feature_var = list(clf.feature_importances_)  # feature scores #
        features = dict(zip(feature_name, feature_var))
        features = dict(sorted(features.items(), key=lambda d: d[1]))
        index=list(features.keys())
        values=list(features.values())
        plt.figure(figsize=(13,7))
        plt.title('決策樹特徵重要性條形圖',fontsize=24)
        plt.barh(index,values,alpha=0.7)
        plt.xlabel('特徵重要性',color='gray',fontsize=16)
        plt.ylabel('特徵變量名',color='gray',fontsize=16)
        plt.xticks(fontsize=14)
        plt.yticks(fontsize=14)
        plt.gcf().savefig('Tree_feature_importances.png')
        plt.show()

(2) 模型評價

模型預測準確率

表 3-4 模型預測準確率

  分析:從表中可知,對測試數據集,對於未流失客戶的預測達到了96.4%,對於流失用戶的預測命中率達到了88.1%,模型總體的準確率達到了93.2%,基本上可以接受,可以繼續流失規則分析。

(3) 結果分析

決策樹透視化
決策樹特徵重要性

圖 3-5 決策樹透視化和特徵重要性

  分析:從圖可知,“最後一次乘機時間至觀察窗口末端時長”成爲最重要的流失劃分因素。

  • a) 最後一次乘機時間至觀察窗口末端時長 > 167.5 並且 觀察窗口內最大乘機間隔<=200.5 基尼指數(Gini)=0.059
  • b) 最後一次乘機時間至觀察窗口末端時長 <= 12.5 並且 觀察窗口內最大乘機間隔 <=31.5 並且 基尼指數(Gini)=0.17

      結論: 營銷部門可以根據以上所得的流失規則(特別是“最後一次乘機時間至觀察窗口末端時長”是否小於167.5),對客戶進行規則匹配,得出流失可能會流失的客戶,並對其給予一定的優惠,達到挽回客戶,增加收益的目的。

3.流失評分–確定挽留目標客戶

(1)建立流失評分

  目標變量爲離散型,呈現爲非線性模型,樹模型具有較好擬合,此次客戶流失評分使用分類決策數模型,並通過以下規則轉換爲1到100的流失評分標準。

流失規則轉換

圖 3-6 轉成評分規則

from sklearn import tree    
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import math

class Score(object):
    def __init__(self,DataFrame,max_depth=5): ##1.初始化決策樹評分
        #特徵選擇及數據準備
        new_order=np.random.permutation(len(DataFrame))
        new_df=DataFrame.take(new_order)
        f=FeatureSelection(new_df)
        column_names=f.return_feature_set(variance_threshold=True,tree_select=True)
        feature=new_df[column_names]
        target=new_df['流失標誌']
        #準備訓練和測試數據
        breakPoint=math.floor(len(feature)*0.2)
        feature_Train=feature[:-breakPoint]
        target_Train=target[:-breakPoint]
        self.feature_Test=feature[-breakPoint:]
        self.target_Test=target[-breakPoint:]
        Test_df=new_df[-breakPoint:]
        #分類決策樹
        clf = tree.DecisionTreeClassifier(max_depth=max_depth,min_samples_split=6,
                                          min_samples_leaf=3,class_weight='balanced',presort=True)
        clf = clf.fit(feature_Train,target_Train)
        print('模型準確率爲:%2.2f %%'%(clf.score(self.feature_Test,self.target_Test)*100))
        def h(x):
            if x[0]==0:
                return np.round((0.5 - x[1]/2)*100,2)
            else:
                return np.round((0.5 + x[2]/2)*100,2)
        runoff=clf.predict(self.feature_Test)    
        Arr=np.column_stack((runoff,clf.predict_proba(self.feature_Test)))
        sore=np.apply_along_axis(h,axis=1,arr=Arr)
        Test_df['$C-流失標誌']=runoff
        Test_df['$C-流失評分']=sore
        self.Score_df=Test_df
        print('評分完成!')     
        
    def Score_assess(self):          ##2.評分效果分析
        plt.figure(figsize=(13,5))   # 第一張圖
        plt.subplot(121)             # 第一張子圖
        plt.title('流失評分直方圖',fontsize=16)
        pop=self.Score_df['$C-流失評分']
        plt.hist(pop,bins=20)
        plt.xlabel('計數')
        plt.ylabel('評分')
        plt.subplot(122)             # 第二張子圖
        new_df=self.Score_df
        result=new_df['$C-流失評分']
        bins=list(range(0,101,5))
        bins[-1]=101
        cat=pd.cut(result,bins,right=False)
        new_df['劃分']=cat
        new_Ser=new_df.groupby(['劃分','流失標誌']).count()['會員卡號']
        new_df=new_Ser.unstack()
        index=np.arange(1,len(new_df)+1)
        Ser1=new_df[0]
        Ser2=new_df[1]
        plt.axis([0,len(new_df)+1,0,7800])
        plt.title('流失評分與實際流失情況',fontsize=16)
        plt.bar(index,Ser1,color='b')
        plt.bar(index,Ser2,color='r',bottom=Ser1)
        plt.legend(['0','1'],title='流失標誌',fontsize=12)
        plt.xticks(index,list(new_df.index),rotation=90)
        plt.xlabel('評分')
        plt.ylabel('計數')
        plt.gcf().savefig('Score_assess.png')
        plt.show()
    
    def Score_marketing(self,dimRspRate=0.7,dtmDiscount=0.8,dtmCost=500):  ##3.1營銷演繹-生成相關指標
        #過濾重命名
        columns=['會員卡號','總票價','流失標誌','$C-流失評分']
        new_df=self.Score_df[columns]
        recolumn={'總票價':'客戶價值','$C-流失評分':'流失評分'}
        new_df=new_df.rename(columns=recolumn)
        #排序
        new_df
        new_df=new_df.sort_index(by='流失評分',ascending=False)
        #添加
        new_df['目標客戶']=(np.arange(1,len(new_df)+1)/len(new_df))*100
        new_df['營銷活動響應']=np.random.random(len(new_df))<=dimRspRate
        lisEarning=[]
        lisCost=[]
        earning=0
        cost=0
        for runoff,rsp,value in zip(new_df['流失標誌'],new_df['營銷活動響應'],new_df['客戶價值']):
            if runoff==1 and rsp==True:
                earning+=value*(1-(1-dtmDiscount))
                lisEarning.append(earning)
            else:
                lisEarning.append(earning)

            if value>0:
                cost+=dtmCost
                lisCost.append(cost)
            else:
                lisCost.append(cost)
        new_df['挽留收益']=np.round(lisEarning,2)
        new_df['挽留成本']=np.round(lisCost,2)
        new_df['挽留活動淨收益']=new_df['挽留收益']-new_df['挽留成本']
        lisRSCP=[]
        lisNTC=[]
        netEarning=-99999
        for ne,rs,tc in zip(new_df['挽留活動淨收益'],new_df['流失評分'],new_df['目標客戶']):
            if ne>=netEarning:
                lisRSCP.append(rs)
                lisNTC.append(tc)
                netEarning=ne
            else:
                lisRSCP.append(lisRSCP[-1])
                lisNTC.append(lisNTC[-1])
        new_df['流失評分臨界點']=lisRSCP
        new_df['營銷活動目標客戶']=lisNTC
        self.result_df=new_df
        self.Score_View()
        self.Score_To_CSV()
        print('營銷演繹完成!')
        return self.result_df
    
    def Score_View(self): 			##3.2營銷演繹--成本、收益、淨收益
        new_df=self.result_df
        index=new_df['目標客戶']
        y1=new_df['挽留收益']
        y2=new_df['挽留成本']
        y3=new_df['挽留活動淨收益']
        x_point=round(max(new_df['營銷活動目標客戶']),2)
        y_point=round(max(y3),0)
        plt.title('挽留收益、成本、淨收益折線圖',fontsize=14)
        plt.xlabel('目標客戶')
        plt.ylabel('收益,成本,淨收益')
        plt.plot(index,y1)
        plt.plot(index,y2)
        plt.plot(index,y3)
        plt.legend(['收益','成本','淨收益'])
        plt.annotate(r'最高點:(%s,%s)'%(x_point,y_point),xy=[x_point,y_point],xycoords='data',
                    xytext=[20,30],fontsize=12,textcoords='offset points',
                     arrowprops=dict(arrowstyle="->",connectionstyle='arc3,rad=0.2'))
        plt.gcf().savefig('Score_earning.png')

    def Score_To_CSV(self): 			##3.3營銷演繹--導出挽留目標客戶
        new_df=self.result_df
        result_df=new_df[new_df['目標客戶']<=max(new_df['營銷活動目標客戶'])]
        result_df=result_df[['會員卡號','流失標誌','客戶價值','流失評分']]
        result_df.to_csv('挽留活動目標客戶.csv',index=None,encoding='gbk')
        print("導出完成!")

(2)模型評價

流失評分效果

圖 3-7 流失評分效果

  分析:從左圖可知,未流失率的人數佔比是最多的,跟實際的航空客戶情況一致,從右圖可知,流失評分越低的實際的流失佔比越低,流失評分越高的實際的流失佔比約高,因此,決策樹評分模型是可以接受的,可進一步分析。

(3)營銷演繹

  1)建立

  根據挽留活動淨收益最大化確定流失評分臨界點、營銷活動目標客戶。默認設置 – 活動響應率=70%;折扣率=80%;成本=500
營銷演繹流程圖

圖 3-8 營銷演繹流程圖

  2)結果透視化和導出

收益、成本、淨收益

圖 3-9 挽留收益、成本、淨收益折線圖

  分析:從圖中可知,當營銷活動的目標客戶從0到41.27時,挽留淨收益呈上升趨勢,從41.27到100.0呈下降趨勢,41.27時營銷淨收益達到最高值,建議對41.27前的目標流失客戶羣體,進行挽留活動。

挽留活動目標客戶
表 3-10 挽留活動目標客戶

  結論在本次營銷演繹中,提供了三個可變的參數,分別爲響應比率、營銷活動單位成本、折扣,可以供市場營銷部門的同事根據市場活動的實際情況進行調整。同時,在輸出客戶目標時,也提供了每個用戶的會員卡號、流失標誌、客戶價值、流失評分作爲市場營銷挽留活動的參照指標。

四、結果部署

  本次項目遵循數據挖掘方法論—CRISP-DM(跨行業數據挖掘標準流程),對航空客戶流失問題進行探索,採用了數據挖掘的聚類,決策數等,得出以下分析的結果,對於航空業務具有一定的推動作用。
  從初步探索性分析中發現,會員等級劃分不合理,會員等級 4的客戶佔比大且流失率最高,可相應部分高價值的客戶;在性別方面,女性客戶相對於男性具有較大的流失率,因此應該提高女性客戶的服務質量,如關愛女活動等。
  從聚類模型中,發現”客戶價值低,呈現下降趨勢;乘機頻率低,間隔大”是用戶流失的主要特徵;從決策數模型中,發現”最後一次乘機時間至觀察窗口末端時長” >=173.5,成爲匹配用戶是否流失主要流失規則。可結合這兩個結果,對用戶進行流失前及時發現與挽回。
  從流失評分營銷演繹中,得出了客戶的流失評分臨界點(利潤最大化),以及結合實際情況可調整的響應比率、營銷活動單位成本、折扣,最終確定市場營銷活動目標客戶的名單。

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