电信客户流失分析
1、数据理解
导入数据集文件、查看数据集前5条信息,查看数据集大小和摘要信息。
1 2 3 4 5 6 | df = pd.read_csv( '../input/telco-customer-churn/WA_Fn-UseC_-Telco-Customer-Churn.csv' ) df.head() df.shape #执行df.shape会返回一个元组,该元组的第一个元素代表行数,第二个元素代表列数,这就是这个数据的基本形状,也是数据的大小 df.info() #Pandas dataframe.info()函数用于获取 DataFrame 的简要摘要。在对数据进行探索性分析时,它非常方便。为了快速浏览数据集,我们使用dataframe.info()功能。 |
2、数据清洗
1 2 3 | msno.matrix(df); ## 将缺失值可视化为矩阵,发现无缺失值 # 无效数据密度显示,若是图中白线越多,则说明缺失值越多。左侧纵坐标上的两个数值为样本数量的始末(即从 1 开始数有 506 条数据),右下角数字 12 表示数据中共有 12 列不存在缺失值,右侧数字 14 表示数据共计 14 列。\ |
1 2 3 4 5 | df = df.drop([ 'customerID' ], axis = 1 ) df.head() #删除没用的列,再次查看前五行 #删除表中的某一行或者某一列更明智的方法是使用drop,它不改变原有的df中的数据,而是返回另一个dataframe来存放删除后的数据。 #drop函数默认删除行,列需要加axis = 1 |
1 2 3 4 5 | df[ 'TotalCharges' ] = pd.to_numeric(df.TotalCharges, errors = 'coerce' ) df.isnull(). sum () # 类型转换1,将‘TotalCharges’总消费额的数据类型转换为数字类型,统计每列缺失值的个数,有11个缺失值 #arg : scalar(标量),list(列表),(tuple)元组,一维数组(1-d array)或Series #errors : {'ignore','raise','coerce'},默认为'raise'如果为‘raise’,则无效的解析将引发异常如果为 ‘coerce’,则将无效解析设置为NaN如果为 ‘ignore’,则无效的解析将返回输入 |
1 2 | df[np.isnan(df[ 'TotalCharges' ])] #查看这11行带有缺失值的数据,发现这11个用户‘tenure’(入网时长)为0个月 |
1 2 | df[df[ 'tenure' ] = = 0 ].index #查看tenure为0的索引,看是否有其他月费存在但是入网时间为0的用户,发现没有 |
1 2 3 4 5 6 7 8 | df.drop(labels = df[df[ 'tenure' ] = = 0 ].index, axis = 0 , inplace = True ) df[df[ 'tenure' ] = = 0 ].index #删除标签为表格中tenure=0对应的11行,对数据影响不大,并改变表格, #labels:一个字符或者数值,加上axis ,表示带label标识的行或者列;如 (labels='A', axis=1) 表示A列 #axis:axis=0表示行,axis=1表示列 #columns:列名 #index:表示dataframe的index, 如index=1, index=a #inplace:True表示删除某行后原dataframe变化,False不改变原始dataframe |
1 2 3 | df[ "SeniorCitizen" ]= df[ "SeniorCitizen" ].map({0: "No" , 1: "Yes" }) df.head() #类型转换2,把seniorcitizen数据类型转换为字符型,替换列值使用字典进行映射 |
1 2 | df.isnull(). sum () #再次查看缺失值,无缺失 |
1 2 3 | numerical_cols = [ 'tenure' , 'MonthlyCharges' , 'TotalCharges' ] df[numerical_cols].describe() #获取数据类型的描述统计信息,根据一般经验,所有数据正常。 |
3、数据可视化
1 2 3 4 | #客户流失饼状图 plt.pie(df[ "Churn" ].value_counts(), labels = df[ "Churn" ].value_counts().index, explode = ( 0.1 , 0 ), autopct = '%1.2f%%' , shadow = True , colors = [ '#c2c2f0' , '#ffb3e6' , '#66b3ff' ]) plt.title( "客户流失比例" ) plt.show()<br> #属于不平衡数据 |
3.1用户分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | #分别查看老年人和性别对客户流失的影响<br>def barplot_percentages(feature,orient='v',axis_name="percentage of customers"): ratios = pd.DataFrame() g = (df.groupby(feature)[ "Churn" ].value_counts() / len (df)).to_frame() g.rename(columns = { "Churn" :axis_name},inplace = True ) g.reset_index(inplace = True ) #print(g) if orient = = 'v' : ax = sns.barplot(x = feature, y = axis_name, hue = 'Churn' , data = g, orient = orient) ax.set_yticklabels([ '{:,.0%}' . format (y) for y in ax.get_yticks()]) plt.rcParams.update({ 'font.size' : 13 }) #plt.legend(fontsize=10) else : ax = sns.barplot(x = axis_name, y = feature, hue = 'Churn' , data = g, orient = orient) ax.set_xticklabels([ '{:,.0%}' . format (x) for x in ax.get_xticks()]) plt.legend(fontsize = 10 ) plt.title( 'Churn(Yes/No) Ratio as {0}' . format (feature)) plt.show() barplot_percentages( "SeniorCitizen" ) barplot_percentages( "gender" ) |
1 2 3 4 5 | #进一步观察性别、老年用户与流失的关系<br>df['churn_rate'] = df['Churn'].replace("No", 0).replace("Yes", 1) g = sns.FacetGrid(df, col = "SeniorCitizen" , height = 4 , aspect = . 9 ) ax = g. map (sns.barplot, "gender" , "churn_rate" , palette = "Blues_d" , order = [ 'Female' , 'Male' ]) plt.rcParams.update({ 'font.size' : 13 }) plt.show()<br> #用户流失与性别基本无关;年老用户流失占显著高于年轻用户。 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | #观察家属、配偶与用户流失的关系<br>fig, axis = plt.subplots(1, 2, figsize=(12,4)) axis[ 0 ].set_title( "Has Partner" ) axis[ 1 ].set_title( "Has Dependents" ) axis_y = "percentage of customers" # Plot Partner column gp_partner = (df.groupby( 'Partner' )[ "Churn" ].value_counts() / len (df)).to_frame() gp_partner.rename(columns = { "Churn" : axis_y}, inplace = True ) gp_partner.reset_index(inplace = True ) ax1 = sns.barplot(x = 'Partner' , y = axis_y, hue = 'Churn' , data = gp_partner, ax = axis[ 0 ]) ax1.legend(fontsize = 10 ) #ax1.set_xlabel('伴侣') # Plot Dependents column gp_dep = (df.groupby( 'Dependents' )[ "Churn" ].value_counts() / len (df)).to_frame() #print(gp_dep) gp_dep.rename(columns = { "Churn" : axis_y} , inplace = True ) #print(gp_dep) gp_dep.reset_index(inplace = True ) #print(gp_dep) ax2 = sns.barplot(x = 'Dependents' , y = axis_y, hue = 'Churn' , data = gp_dep, ax = axis[ 1 ]) #ax2.set_xlabel('家属') #设置字体大小 plt.rcParams.update({ 'font.size' : 20 }) ax2.legend(fontsize = 10 ) #设置 plt.show()<br> #发现有伴侣的用户流失占比低于无伴侣用户<br>有家属的用户流失占比低于无家属用户 |
1 2 3 4 5 6 7 8 9 10 11 12 | # Kernel density estimaton核密度估计观察入网时间与流失关系 def kdeplot(feature,xlabel): plt.figure(figsize = ( 9 , 4 )) plt.title( "KDE for {0}" . format (feature)) ax0 = sns.kdeplot(df[df[ 'Churn' ] = = 'No' ][feature].dropna(), color = 'navy' , label = 'Churn: No' , shade = 'True' ) ax1 = sns.kdeplot(df[df[ 'Churn' ] = = 'Yes' ][feature].dropna(), color = 'orange' , label = 'Churn: Yes' ,shade = 'True' ) plt.xlabel(xlabel) #设置字体大小 plt.rcParams.update({ 'font.size' : 20 }) plt.legend(fontsize = 10 ) kdeplot( 'tenure' , 'tenure' ) plt.show()<br> #发现新用户比较容易流失 |
3.2产品分析
1 2 | #电话服务和多线对用户流失影响较小<br>plt.figure(figsize=(9, 4.5)) barplot_percentages( "MultipleLines" , orient = 'h' ) |
1 2 | #单光纤用户流失占比较高<br>plt.figure(figsize=(9, 4.5)) barplot_percentages( "InternetService" , orient = "h" ) |
1 2 3 4 5 6 7 8 9 10 | #订阅“在线安全”、“在线备份”、“设备保护”和“技术支持”的流失率较低cols = ["PhoneService","MultipleLines","OnlineSecurity", "OnlineBackup", "DeviceProtection", "TechSupport", "StreamingTV", "StreamingMovies"] df1 = pd.melt(df[df[ "InternetService" ] ! = "No" ][cols]) df1.rename(columns = { 'value' : 'Has service' },inplace = True ) plt.figure(figsize = ( 20 , 8 )) ax = sns.countplot(data = df1, x = 'variable' , hue = 'Has service' ) ax. set (xlabel = 'Internet Additional service' , ylabel = 'Num of customers' ) plt.rcParams.update({ 'font.size' : 20 }) plt.legend( labels = [ 'No Service' , 'Has Service' ],fontsize = 15 ) plt.title( 'Num of Customers as Internet Additional Service' ) plt.show() |
1 2 3 4 5 6 7 8 9 10 | #流媒体电视、电影服务与用户流失无关<br>plt.figure(figsize=(20, 8)) df1 = df[(df.InternetService ! = "No" ) & (df.Churn = = "Yes" )] df1 = pd.melt(df1[cols]) df1.rename(columns = { 'value' : 'Has service' }, inplace = True ) ax = sns.countplot(data = df1, x = 'variable' , hue = 'Has service' , hue_order = [ 'No' , 'Yes' ]) ax. set (xlabel = 'Internet Additional service' , ylabel = 'Churn Num' ) plt.rcParams.update({ 'font.size' : 20 }) plt.legend( labels = [ 'No Service' , 'Has Service' ],fontsize = 15 ) plt.title( 'Num of Churn Customers as Internet Additional Service' ) plt.show() |
3.3用户行为分析
1 2 | #支付方式与流失<br>plt.figure(figsize=(9, 4.5)) barplot_percentages( "PaymentMethod" ,orient = 'h' )<br> #电子支付更容易流失客户。 |
1 2 3 4 | #无纸化账单与流失<br>g = sns.FacetGrid(df, col="PaperlessBilling", height=6, aspect=.9) ax = g. map (sns.barplot, "Contract" , "churn_rate" , palette = "Blues_d" , order = [ 'Month-to-month' , 'One year' , 'Two year' ]) plt.rcParams.update({ 'font.size' : 18 }) plt.show()<br> #无纸化账单的客户更容易流失。 |
1 2 3 | #月费与流失,总费与流失<br>kdeplot('MonthlyCharges','MonthlyCharges') kdeplot( 'TotalCharges' , 'TotalCharges' ) plt.show()<br> #月费率越高越容易流失客户,总费用少的用户容易流失 |
3.4总结
(1)用户流失与性别gender无关。
(2)老年人流失比率比较大,原因可能在于老年人对电信套餐认识不深,普及度较低,容易流失老年人客户。
(3)没有伴侣以及没有家属的用户流失率大。伴侣及家庭成员的存在可以显著影响电信用户的留存或流失。
(4)用户流失基本与手机服务指标“电话服务”和“多线”无关。可能是因为这是电信企业的核心业务,用户流失与此无关。
(5)网络服务指标中,采用光纤服务的用户更容易流失。可能是因为光纤服务的性价比不高。
(6)其他订阅服务指标中,前四项服务(“在线安全”、“在线备份”、“设备保护”和“技术支持”)对客户流失呈正相关,没有订阅该服务的用户较容易流失,后两项(“流媒体电视”和“流媒体电影”)对客户流失没有明显关系。
(7)电子支付更容易流失客户。可能是因为办理业务方便,抑或是操作频率高,使客户厌倦。
(8)采用无纸化账单的客户更容易流失。可能是因为让客户的钱流动没有感觉。
(9)合同签约期越长用户越不容易流失。2年合同若在中途毁约,对客户有一定损失,这在一定程度上减少了客户的流失。
(10)新客户更容易流失。可以采取一定的折扣方案挽留新用户,提高新用户的留存率。
(11)月费率越高越容易流失客户,若不在高费率的基础上提供更优质的服务,容易导致用户流失。月费为60元左右可以使得流失率较低且留存率较高,此后流失率大幅增加。80元左右时,客户的流失率达到顶峰。
(12)总费用少的用户反而容易流失。因此费用保持在60元左右最好。
3.5建议
(1)用户方面:针对老年用户、无亲属、无伴侣用户的特征推出定制服务如老年朋友套餐、温暖套餐等。鼓励用户加强关联,推出各种亲子套餐、情侣套餐等,满足客户的多样化需求。针对新注册用户,推送半年优惠如赠送消费券,以度过用户流失高峰期。
(2)产品方面:针对光纤用户可以推出光纤和通讯组合套餐,对于连续开通半年以上的用户给与优惠减免。开通网络电视、电影的用户容易流失,需要研究这些用户的流失原因,是服务体验如观影流畅度清晰度等不好还是资源如片源等过少,再针对性的解决问题。针对在线安全、在线备份、设备保护、技术支持等增值服务,应重点对用户进行推广介绍,如首月/半年免费体验,使客户习惯并受益于这些服务。
(3)用户行为方面:针对单月合同用户,建议推出年合同付费折扣活动,将月合同用户转化为年合同用户,提高用户存留时长,以减少用户流失。 针对采用电子支票支付用户,建议定向推送其它支付方式的优惠券,引导用户改变支付方式。对于开通电子账单的客户,可以在电子账单上增加等级积分等显示,等级升高可以免费享受增值服务,积分可以兑换某些日用商品。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本