
CDA數據分析師 出品
作者:真達、Mika
數據:真達
【導讀】
今天教大家如何用python寫一個電信用戶流失預測模型。之前我們用Python寫了員工流失預測模型,這次我們試試Python預測電信用戶的流失。
01、商業理解
流失客戶是指那些曾經使用過產品或服務,由于對產品失去興趣等種種原因,不再使用產品或服務的顧客。
電信服務公司、互聯網服務提供商、保險公司等經常使用客戶流失分析和客戶流失率作為他們的關鍵業務指標之一,因為留住一個老客戶的成本遠遠低于獲得一個新客戶。
預測分析使用客戶流失預測模型,通過評估客戶流失的風險傾向來預測客戶流失。由于這些模型生成了一個流失概率排序名單,對于潛在的高概率流失客戶,他們可以有效地實施客戶保留營銷計劃。
下面我們就教你如何用Python寫一個電信用戶流失預測模型,以下是具體步驟和關鍵代碼。
02、數據理解
此次分析數據來自于IBM Sample Data Sets,統計自某電信公司一段時間內的消費數據。共有7043筆客戶資料,每筆客戶資料包含21個字段,其中1個客戶ID字段,19個輸入字段及1個目標字段-Churn(Yes代表流失,No代表未流失),輸入字段主要包含以下三個維度指標:用戶畫像指標、消費產品指標、消費信息指標。字段的具體說明如下:
03、數據讀入和概覽
首先導入所需包。
# 數據處理 import numpy as np import pandas as pd # 可視化 import matplotlib.pyplot as plt import seaborn as sns import plotly as py import plotly.graph_objs as go import plotly.figure_factory as ff # 前處理 from sklearn.preprocessing import LabelEncoder from sklearn.preprocessing import StandardScaler # 建模 from sklearn.linear_model import LogisticRegression from sklearn.neighbors import KNeighborsClassifier from sklearn.tree import DecisionTreeClassifier from sklearn import tree from sklearn.ensemble import RandomForestClassifier from sklearn.naive_bayes import GaussianNB from sklearn.neural_network import MLPClassifier from sklearn.svm import SVC from lightgbm import LGBMClassifier from xgboost import XGBClassifier # 模型評估 from sklearn.model_selection import train_test_split, GridSearchCV from sklearn.metrics import confusion_matrix, accuracy_score, classification_report from sklearn.metrics import roc_auc_score, roc_curve, scorer from sklearn.metrics import recall_score, precision_score, f1_score, cohen_kappa_score pd.set_option('display.max_columns', None)
讀入數據集
df = pd.read_csv('./Telco-Customer-Churn.csv') df.head()
04、數據初步清洗
首先進行初步的數據清洗工作,包含錯誤值和異常值處理,并劃分類別型和數值型字段類型,其中清洗部分包含:
# 錯誤值處理 repl_columns = ['OnlineSecurity', 'OnlineBackup', 'DeviceProtection', 'TechSupport','StreamingTV', 'StreamingMovies'] for i in repl_columns: df[i] = df[i].replace({'No internet service' : 'No'}) # 替換值SeniorCitizen df["SeniorCitizen"] = df["SeniorCitizen"].replace({1: "Yes", 0: "No"}) # 替換值TotalCharges df['TotalCharges'] = df['TotalCharges'].replace(' ', np.nan) # TotalCharges空值:數據量小,直接刪除 df = df.dropna(subset=['TotalCharges']) df.reset_index(drop=True, inplace=True) # 重置索引 # 轉換數據類型 df['TotalCharges'] = df['TotalCharges'].astype('float') # 轉換tenure def transform_tenure(x): if x <= 12: return 'Tenure_1' elif x <= 24: return 'Tenure_2' elif x <= 36: return 'Tenure_3' elif x <= 48: return 'Tenure_4' elif x <= 60: return 'Tenure_5' else: return 'Tenure_over_5' df['tenure_group'] = df.tenure.apply(transform_tenure) # 數值型和類別型字段 Id_col = ['customerID'] target_col = ['Churn'] cat_cols = df.nunique()[df.nunique() < 10].index.tolist() num_cols = [i for i in df.columns if i not in cat_cols + Id_col] print('類別型字段:\n', cat_cols) print('-' * 30) print('數值型字段:\n', num_cols)
類別型字段: ['gender', 'SeniorCitizen', 'Partner', 'Dependents', 'PhoneService', 'MultipleLines', 'InternetService', 'OnlineSecurity', 'OnlineBackup', 'DeviceProtection', 'TechSupport', 'StreamingTV', 'StreamingMovies', 'Contract', 'PaperlessBilling', 'PaymentMethod', 'Churn', 'tenure_group'] ------------------------------ 數值型字段: ['tenure', 'MonthlyCharges', 'TotalCharges']
05、探索性分析
對指標進行歸納梳理,分用戶畫像指標,消費產品指標,消費信息指標。探索影響用戶流失的關鍵因素。
1. 目標變量Churn分布
經過初步清洗之后的數據集大小為7032條記錄,其中流失客戶為1869條,占比26.6%,未流失客戶占比73.4%。
df['Churn'].value_counts() No 5163 Yes 1869 Name: Churn, dtype: int64
trace0 = go.Pie(labels=df['Churn'].value_counts().index, values=df['Churn'].value_counts().values, hole=.5, rotation=90, marker=dict(colors=['rgb(154,203,228)', 'rgb(191,76,81)'], line=dict(color='white', width=1.3)) ) data = [trace0] layout = go.Layout(title='目標變量Churn分布') fig = go.Figure(data=data, layout=layout) py.offline.plot(fig, filename='./html/整體流失情況分布.html')
2.性別
分析可見,男性和女性在客戶流失比例上沒有顯著差異。
plot_bar(input_col='gender', target_col='Churn', title_name='性別與是否流失的關系')
3. 老年用戶
老年用戶流失比例更高,為41.68%,比非老年用戶高近兩倍,此部分原因有待進一步探討。
plot_bar(input_col='SeniorCitizen', target_col='Churn', title_name='老年用戶與是否流失的關系')
4. 是否有配偶
從婚姻情況來看,數據顯示,未婚人群中流失的比例比已婚人數高出13%。
plot_bar(input_col='Partner', target_col='Churn', title_name='是否有配偶與是否流失的關系')
5. 上網時長
經過分析,這方面可以得出兩個結論:
plot_bar(input_col='tenure_group', target_col='Churn', title_name='在網時長與是否流失的關系')
6. 付款方式
支付方式上,支付上,選擇電子支票支付方式的用戶流失最高,達到45.29%,其他三種支付方式的流失率相差不大。
pd.crosstab(df['PaymentMethod'], df['Churn'])
plot_bar(input_col='PaymentMethod', target_col='Churn', title_name='付款方式與是否流失關系')
7. 月費用
整體來看,隨著月費用的增加,流失用戶的比例呈現高高低低的變化,月消費80-100元的用戶相對較高。
plot_histogram(input_col='MonthlyCharges', title_name='月費用與是否流失關系')
8. 數值型屬性相關性
從相關性矩陣圖可以看出,用戶的往來期間和總費用呈現高度相關,往來期間越長,則總費用越高。月消費和總消費呈現顯著相關。
plt.figure(figsize=(15, 10)) sns.heatmap(df.corr(), linewidths=0.1, cmap='tab20c_r', annot=True) plt.title('數值型屬性的相關性', fontdict={'fontsize': 'xx-large', 'fontweight':'heavy'}) plt.xticks(fontsize=12) plt.yticks(fontsize=12) plt.show()
06、特征選擇
使用統計檢定方式進行特征篩選。
# 刪除tenure df = df.drop('tenure', axis=1) from feature_selection import Feature_select # 劃分X和y X = df.drop(['customerID', 'Churn'], axis=1) y = df['Churn'] fs = Feature_select(num_method='anova', cate_method='kf', pos_label='Yes') x_sel = fs.fit_transform(X, y)
2020 09:30:02 INFO attr select success! After select attr: ['DeviceProtection', 'MultipleLines', 'OnlineSecurity', 'TechSupport', 'tenure_group', 'PaperlessBilling', 'InternetService', 'PaymentMethod', 'SeniorCitizen', 'MonthlyCharges', 'Dependents', 'Partner', 'Contract', 'StreamingTV', 'TotalCharges', 'StreamingMovies', 'OnlineBackup']
經過特征篩選,gender和PhoneService字段被去掉。
07、建模前處理
在python中,為滿足建模需要,一般需要對數據做以下處理:
# 篩選變量 select_features = x_sel.columns # 建模數據 df_model = pd.concat([df['customerID'], df[select_features], df['Churn']], axis=1) Id_col = ['customerID'] target_col = ['Churn'] # 分類型 cat_cols = df_model.nunique()[df_model.nunique() < 10].index.tolist() # 二分類屬性 binary_cols = df_model.nunique()[df_model.nunique() == 2].index.tolist() # 多分類屬性 multi_cols = [i for i in cat_cols if i not in binary_cols] # 數值型 num_cols = [i for i in df_model.columns if i not in cat_cols + Id_col] # 二分類-標簽編碼 le = LabelEncoder() for i in binary_cols: df_model[i] = le.fit_transform(df_model[i]) # 多分類-啞變量轉換 df_model = pd.get_dummies(data=df_model, columns=multi_cols) df_model.head()
08、模型建立和評估
首先使用分層抽樣的方式將數據劃分訓練集和測試集。
# 重新劃分 X = df_model.drop(['customerID', 'Churn'], axis=1) y = df_model['Churn'] # 分層抽樣 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0, stratify=y) print(X_train.shape, X_test.shape, y_train.shape, y_test.shape) #修正索引 for i in [X_train, X_test, y_train, y_test]: i.index = range(i.shape[0])
(5625, 31) (1407, 31) (5625,) (1407,)
# 保存標準化訓練和測試數據 st = StandardScaler() num_scaled_train = pd.DataFrame(st.fit_transform(X_train[num_cols]), columns=num_cols) num_scaled_test = pd.DataFrame(st.transform(X_test[num_cols]), columns=num_cols) X_train_sclaed = pd.concat([X_train.drop(num_cols, axis=1), num_scaled_train], axis=1) X_test_sclaed = pd.concat([X_test.drop(num_cols, axis=1), num_scaled_test], axis=1)
然后建立一系列基準模型并比較效果。
假如我們關注roc指標,從模型表現效果來看,Naive Bayes效果最好。我們也可以對模型進行進一步優化,比如對決策樹參數進行調優。
parameters = {'splitter': ('best','random'), 'criterion': ("gini","entropy"), "max_depth": [*range(3, 20)], } clf = DecisionTreeClassifier(random_state=25) GS = GridSearchCV(clf, parameters, scoring='f1', cv=10) GS.fit(X_train, y_train) print(GS.best_params_) print(GS.best_score_)
{'criterion': 'entropy', 'max_depth': 5, 'splitter': 'best'} 0.585900839405024
clf = GS.best_estimator_ test_pred = clf.predict(X_test) print('測試集:\n', classification_report(y_test, test_pred))
測試集: precision recall f1-score support 0 0.86 0.86 0.86 1033 1 0.61 0.61 0.61 374 accuracy 0.79 1407 macro avg 0.73 0.73 0.73 1407 weighted avg 0.79 0.79 0.79 1407
將這棵樹繪制出來。
import graphviz dot_data = tree.export_graphviz(decision_tree=clf, max_depth=3, out_file=None, feature_names=X_train.columns, class_names=['not_churn', 'churn'], filled=True, rounded=True ) graph = graphviz.Source(dot_data)
輸出決策樹屬性重要性排序:
imp = pd.DataFrame(zip(X_train.columns, clf.feature_importances_)) imp.columns = ['feature', 'importances'] imp = imp.sort_values('importances', ascending=False) imp = imp[imp['importances'] != 0] table = ff.create_table(np.round(imp, 4)) py.offline.iplot(table)
后續優化方向:
數據分析咨詢請掃描二維碼
若不方便掃碼,搜微信號:CDAshujufenxi
在本文中,我們將探討 AI 為何能夠加速數據分析、如何在每個步驟中實現數據分析自動化以及使用哪些工具。 數據分析中的AI是什么 ...
2025-05-20當數據遇見人生:我的第一個分析項目 記得三年前接手第一個數據分析項目時,我面對Excel里密密麻麻的銷售數據手足無措。那些跳動 ...
2025-05-20在數字化運營的時代,企業每天都在產生海量數據:用戶點擊行為、商品銷售記錄、廣告投放反饋…… 這些數據就像散落的拼圖,而相 ...
2025-05-19在當今數字化營銷時代,小紅書作為國內領先的社交電商平臺,其銷售數據蘊含著巨大的商業價值。通過對小紅書銷售數據的深入分析, ...
2025-05-16Excel作為最常用的數據分析工具,有沒有什么工具可以幫助我們快速地使用excel表格,只要輕松幾步甚至輸入幾項指令就能搞定呢? ...
2025-05-15數據,如同無形的燃料,驅動著現代社會的運轉。從全球互聯網用戶每天產生的2.5億TB數據,到制造業的傳感器、金融交易 ...
2025-05-15大數據是什么_數據分析師培訓 其實,現在的大數據指的并不僅僅是海量數據,更準確而言是對大數據分析的方法。傳統的數 ...
2025-05-14CDA持證人簡介: 萬木,CDA L1持證人,某電商中廠BI工程師 ,5年數據經驗1年BI內訓師,高級數據分析師,擁有豐富的行業經驗。 ...
2025-05-13CDA持證人簡介: 王明月 ,CDA 數據分析師二級持證人,2年數據產品工作經驗,管理學博士在讀。 學習入口:https://edu.cda.cn/g ...
2025-05-12CDA持證人簡介: 楊貞璽 ,CDA一級持證人,鄭州大學情報學碩士研究生,某上市公司數據分析師。 學習入口:https://edu.cda.cn/g ...
2025-05-09CDA持證人簡介 程靖 CDA會員大咖,暢銷書《小白學產品》作者,13年頂級互聯網公司產品經理相關經驗,曾在百度、美團、阿里等 ...
2025-05-07相信很多做數據分析的小伙伴,都接到過一些高階的數據分析需求,實現的過程需要用到一些數據獲取,數據清洗轉換,建模方法等,這 ...
2025-05-06以下的文章內容來源于劉靜老師的專欄,如果您想閱讀專欄《10大業務分析模型突破業務瓶頸》,點擊下方鏈接 https://edu.cda.cn/g ...
2025-04-30CDA持證人簡介: 邱立峰 CDA 數據分析師二級持證人,數字化轉型專家,數據治理專家,高級數據分析師,擁有豐富的行業經驗。 ...
2025-04-29CDA持證人簡介: 程靖 CDA會員大咖,暢銷書《小白學產品》作者,13年頂級互聯網公司產品經理相關經驗,曾在百度,美團,阿里等 ...
2025-04-28CDA持證人簡介: 居瑜 ,CDA一級持證人國企財務經理,13年財務管理運營經驗,在數據分析就業和實踐經驗方面有著豐富的積累和經 ...
2025-04-27數據分析在當今信息時代發揮著重要作用。單因素方差分析(One-Way ANOVA)是一種關鍵的統計方法,用于比較三個或更多獨立樣本組 ...
2025-04-25CDA持證人簡介: 居瑜 ,CDA一級持證人國企財務經理,13年財務管理運營經驗,在數據分析就業和實踐經驗方面有著豐富的積累和經 ...
2025-04-25在當今數字化時代,數據分析師的重要性與日俱增。但許多人在踏上這條職業道路時,往往充滿疑惑: 如何成為一名數據分析師?成為 ...
2025-04-24以下的文章內容來源于劉靜老師的專欄,如果您想閱讀專欄《劉靜:10大業務分析模型突破業務瓶頸》,點擊下方鏈接 https://edu.cda ...
2025-04-23