0.项目背景
kaggle网站上的数据集,拿来学习分析。下载地址:Telco Customer Churn | Kaggle
老年用户、未婚用户及经济未独立用户流失率比较高,根据市场份额分析,预测个体客户的生存时长,针对该类用户特征喜好制定专属套餐。
目的:分析流失用户的共同属性,预测流失用户
1.数据准备
1.1搭建环境
!pip install imblearn -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
!pip install lifelines -i https://pypi.tuna.tsinghua.edu.cn/simple
#搭建环境
import numpy as np
import pandas as pd
from pyecharts.charts import *
from pyecharts import options as opts
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] # 指定默认字体
plt.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题
#读取文件
df = pd.read_csv('WA_Fn-UseC_-Telco-Customer-Churn.csv')
1.2字段信息
字段 | 解释 |
---|---|
customerID | 用户ID |
gender | 性别 |
SeniorCitizen | 是否是老年人(1代表是) |
Partner | 是否有配偶(Yes or No) |
Dependents | 是否经济独立(Yes or No) |
tenure | 用户入网时间 |
PhoneService | 是否开通电话业务(Yes or No) |
MultipleLines | 是否开通多条电话业务(Yes 、 No or No phoneservice) |
InternetService | 是否开通互联网服务(No、DSL数字网络或Fiber optic光线网络) |
OnlineSecurity | 是否开通网络安全服务(Yes、No or No internetservice) |
OnlineBackup | 是否开通在线备份服务(Yes、No or No internetservice) |
DeviceProtection | 是否开通设备保护服务(Yes、No or No internetservice) |
TechSupport | 是否开通技术支持业务(Yes、No or No internetservice) |
StreamingTV | 是否开通网络电视(Yes、No or No internetservice) |
StreamingMovies | 是否开通网络电影(Yes、No or No internetservice) |
Contract | 合同签订方式(按月、按年或者两年) |
PaperlessBilling | 是否开通电子账单(Yes or No) |
PaymentMethod | 付款方式(bank transfer、credit card、electronic check、mailed check) |
MonthlyCharges | 月度费用 |
TotalCharges | 总费用 |
Churn 是否流失 | (Yes or No) |
2.框架分析
找到流失用户共同属性:
用户属性 | 性别、是否老年人、有无配偶、是否经济独立...... |
服务属性 | 是否开通电话业务、是否开通互联网服务...... |
消费属性 | 合同签订方式、是否开通电子账单、付款方式...... |
3.数据清洗
3.1数据信息
# 查看基本信息
df.info()
# 查看是否存在重复值--无重复值
df.duplicated().sum()
- 共21个变量,7043条数据,无缺失值,无重复值
- TotalCharges 需要转换为浮点型
# 转换变量类型
# 在转换变量中报错了,列当中存在空格字符串,逐一排查其他列是否存在同样情况
for i in df.columns:
if i == 'SeniorCitizen':
print(i,df[i].isnull().sum())
elif i == 'tenure':
print(i,df[i].isnull().sum())
elif i == 'MonthlyCharges':
print(i,df[i].isnull().sum())
else:
print(i,df[df[i] == ' '][i].count())
TotalCharges 有11个空白值,需要进行填充。这11个用户,只消费了第一个月,故TotalCharges = MonthlyCharges,即用MonthlyCharges来填充TotalCharges
total_id_blank = df.query("TotalCharges == ' '")['customerID']
df.query("customerID in @total_id_blank").groupby(
['customerID', 'tenure'])[['MonthlyCharges']].sum().reset_index()
# TotalCharges = MonthlyCharges
for i in total_id_blank:
df.loc[df.query("customerID == @i").index[0], 'TotalCharges'] = df.loc[df.query(
"customerID == @i").index[0], 'MonthlyCharges']
df['TotalCharges'] = df['TotalCharges'].astype(float)
3.2异常值处理
# 查看分类变量的所有取值
for i in df.columns:
if i not in ('customerID','MonthlyCharges','TotalCharges'):
print(i,df[i].unique())
分类型变量无异常值,接下来观察离散型变量是否存在异常值
# 离散型变量分布
pic = plt.figure(figsize=(9,3),dpi=80)
pic.add_subplot(1,2,1)#第一个子图(行数,列数,本子图位置)
plt.boxplot(df["MonthlyCharges"])
plt.title('MonthlyCharges')
pic.add_subplot(1,2,2)#第一个子图(行数,列数,本子图位置)
plt.boxplot(df["TotalCharges"])
plt.title('TotalCharges')
# 子图间距
plt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0.5, hspace=0.5)
plt.show()
可以看出均无异常值
4.流失用户属性分析
4.1用户属性
用户属性:gender、SeniorCitizen、Partner、Dependents
#用户属性分析
pic = plt.figure(figsize=(12,6),dpi=80)
pic.subplots_adjust(wspace=0.3,hspace=0.3)
for i,j in zip(df.iloc[:,1:5].columns,range(1,5)):
df_count = df.pivot_table(index='Churn',columns=i,values='customerID',aggfunc='count')
df_ratio = df_count.div(df_count.sum())
#print(df_ratio)
pic.add_subplot(2,2,j)
plt.title('Churn by '+ i)
plt.bar([0,1],df_ratio.iloc[0,:],label = df_ratio.index.values[0],width=0.5)
plt.bar([0,1],df_ratio.iloc[1,:],bottom = df_ratio.iloc[0,:],label=df_ratio.index.values[1],width=0.5)
plt.xticks([0,1],df_count.columns.values)
for a,b in zip(range(df_ratio.shape[1]),df_ratio.iloc[1,:]):
plt.text(a,0.88,round(b,4),va='bottom',ha='center',fontsize=12)
plt.legend()
plt.show()
可得到:
- 性别对于用户是否流失几乎不存在差异,流失差异2.91%
- 老年人要比年轻人更容易流失,流失率高于年轻人76.57%
- 无配偶用户(未婚)比有配偶用户(已婚)更容易流失,流失率高于已婚用户67.59%
- 经济不独立用户比经济独立用户更容易流失,流失率高于经济独立用户102.45%
4.2服务属性
服务属性:
- PhoneService 是否开通电话业务(Yes or No)
- MultipleLines 是否开通多条电话业务(Yes 、 No or No phoneservice)
- InternetService 是否开通互联网服务(No、DSL数字网络或Fiber optic光线网络)
- OnlineSecurity 是否开通网络安全服务(Yes、No or No internetservice)
- OnlineBackup 是否开通在线备份服务(Yes、No or No internetservice)
- DeviceProtection 是否开通设备保护服务(Yes、No or No internetservice)
- TechSupport 是否开通技术支持业务(Yes、No or No internetservice)
- StreamingTV 是否开通网络电视(Yes、No or No internetservice)
- StreamingMovies 是否开通网络电影(Yes、No or No internetservice)
#服务属性
pic = plt.figure(figsize=(16,9),dpi=80)
pic.subplots_adjust(wspace=0.3,hspace=0.3)
for i,j in zip(df.iloc[:,6:15].columns,range(1,10)):
df_count = df.pivot_table(index='Churn',columns=i,values='customerID',aggfunc='count')
df_ratio = df_count.div(df_count.sum())
pic.add_subplot(3,3,j)
plt.title('Churn by '+ i)
plt.bar(range(df_ratio.shape[1]),df_ratio.iloc[0,:],label = df_ratio.index.values[0],width=0.5)
plt.bar(range(df_ratio.shape[1]),df_ratio.iloc[1,:],bottom = df_ratio.iloc[0,:],label=df_ratio.index.values[1],width=0.5)
plt.xticks(range(df_ratio.shape[1]),df_count.columns.values)
for a,b in zip(range(df_ratio.shape[1]),df_ratio.iloc[1,:]):
plt.text(a,0.88,round(b,4),va='bottom',ha='center',fontsize=12)
if i=='PhoneService':
plt.legend()
plt.show()
可看出:
-
是否开通电话业务对流失率无影响
-
未开通互联网服务的流失率最低
-
开通了互联网服务的用户中,光纤网络的用户流失率最高
4.3消费属性
消费属性:
- Contract 合同签订方式(按月、按年或者两年)
- PaperlessBilling 是否开通电子账单(Yes or No)
- PaymentMethod 付款方式(bank transfer、credit card、electronic check、mailed check)
- MonthlyCharges 月度费用
- TotalCharges 总费用
pic = plt.figure(figsize=(20,9),dpi=120)
pic.subplots_adjust(wspace=0.3,hspace=0.3)
for i,j in zip(df.iloc[:,15:18].columns,range(1,4)):
df_count = df.pivot_table(index='Churn',columns=i,values='customerID',aggfunc='count')
df_ratio = df_count.div(df_count.sum())
pic.add_subplot(2,2,j)
plt.title('Churn by '+ i)
plt.bar(range(df_ratio.shape[1]),df_ratio.iloc[0,:],label = df_ratio.index.values[0],width=0.5)
plt.bar(range(df_ratio.shape[1]),df_ratio.iloc[1,:],bottom = df_ratio.iloc[0,:],label=df_ratio.index.values[1],width=0.5)
plt.xticks(range(df_ratio.shape[1]),df_count.columns.values)
for a,b in zip(range(df_ratio.shape[1]),df_ratio.iloc[1,:]):
plt.text(a,0.95,round(b,4),va='bottom',ha='center',fontsize=12)
if i=='PaperlessBilling':
plt.legend()
plt.show()
流失率:
- Two year < One year < Month-to-month
- 未开通电子账单 < 开通电子账单
- credit card < bank transfer < mailed check < electronic check
# MonthlyCharges 和 TotalCharges 属于离散型变量,对他们进行分组做直方图,观察分布情况。
import seaborn as sns
sns.distplot(df.query("Churn == 'Yes'")["MonthlyCharges"])
plt.title("MonthlyCharges")
plt.show()
sns.distplot(df.query("Churn == 'Yes'")["TotalCharges"])
plt.title("TotalCharges")
plt.show()
可以看出:
-
流失率较高的月支付金额区间主要在[65,105]之间,流失率较低区间主要在[20,65]
-
总支付金额越高,流失率越低
5.构建预测模型
- 对数据集的一些未流失用户个体进行预测,并绘制生存线,数字代表样本序号。
- 以个体半衰期作为预测生存时间,得到各个时间结点流失的用户占比
(图书馆闭馆了,明天再写呜呜呜)
6.总结
利用回归模型比较了不同特征对于客户流失的影响,并且预测了个体客户的生存时长,计算了各时间点用户流失的比例,结果具有一定的参考性。并对用户流失特征做了一定分析
用户属性:
流失特征:老年用户、未婚用户及经济未独立用户流失率较高。
建议:根据市场份额,考虑是否针对这类户特征喜好制订专属套餐,建议价格区间[20,65]
服务属性:
流失特征:网络使用Fiber Optic流失率高。
建议:
1、对用户进行针对性调研,调研分析老年用户,经济独立用户不选择Fiber Optic的原因
2、可对签订长期合同的客户基于价格优惠,提高长期合同份额
3、电子账单流失率较高,存在疑问,需要具体业务分析,电子账单展示是否可以进行优化
4、引导用户优先使用信用卡支付方式
5、适当下调Fiber Optic资费
消费属性:
流失特征:月付流失率较高,开通账单流失率较高,使用电子支票的用户流失率较高。
建议:
1、可对签订长期合同的客户基于价格优惠,提高长期合同份额。
2、电子账单流失率较高,存在疑问,需要具体业务分析,电子账单展示是否可以进行优化
3、引导用户优先使用信用卡支付方式