实验数据
本实验基于某信息公司的用户数据,使用决策树和可视化工具进行用户流失分析,从而预测哪类用户更容易流失,帮助公司制定相应的预防措施。实验所需数据保存在个人资源处;
首先读取数据:
import pandas as pd
# 读取数据
df = pd.read_csv('data.csv')
# 将顾客ID设置为索引
df.set_index(keys='customerID',inplace=True)
# 数据维度
df.shape # (7043, 20)
df.head()
可看出有以下字段:
# 展示所有字段
df.columns.tolist()
"""
['gender',
'SeniorCitizen',
'Partner',
'Dependents',
'tenure',
'PhoneService',
'MultipleLines',
'InternetService',
'OnlineSecurity',
'OnlineBackup',
'DeviceProtection',
'TechSupport',
'StreamingTV',
'StreamingMovies',
'Contract',
'PaperlessBilling',
'PaymentMethod',
'MonthlyCharges',
'TotalCharges',
'Churn']
"""
- 连续型特征:
MonthlyCharges 月消费,共计1585个取值
TotalCharges 总消费,共计6534个取值 - 有序离散型特征
tenure 入网时长,取值:1-72,表示1-72个月
Contract 合同签订期限,取值:[‘Month-to-month’, ‘One year’, ‘Two year’],表示一个月、一年、两年
对于合同签订期限这个有序离散特征需要处理成数值型变量,单位为月数:
df['Contract'] = df.Contract.map({'Month-to-month':1,'One year':12,'Two year':24})
上面展示的连续型特征、有序离散型特征均属于数值型变量
- 无序离散型特征
Dependents 是否经济独立,取值:[‘No’, ‘Yes’]
DeviceProtection 是否开通设备保护服务,取值:[‘No’, ‘Yes’, ‘No internet service’]
InternetService 互联网服务,取值:[‘DSL’, ‘Fiber optic’, ‘No’]
MultipleLines 是否开通多线业务,取值:[‘No phone service’, ‘No’, ‘Yes’]
OnlineBackup 是否开通在线备份业务,取值:[‘Yes’, ‘No’, ‘No internet service’]
OnlineSecurity 是否开通网络安全服务,取值:[‘No’, ‘Yes’, ‘No internet service’]
PaperlessBilling 是否开通电子账单,取值:[‘Yes’, ‘No’]
Partner 是否婚配,取值:[‘Yes’, ‘No’]
PaymentMethod 付款方式:[‘Electronic check’,‘Mailed check’,‘Bank transfer (automatic)’,‘Credit card (automatic)’]
PhoneService 是否开通电话服务,[‘No’, ‘Yes’]
SeniorCitizen 是否为老年人,[0, 1]
StreamingMovies 是否开通流媒体电影,取值: [‘No’, ‘Yes’, ‘No internet service’]
StreamingTV 是否开通流媒体电视,取值: [‘No’, ‘Yes’, ‘No internet service’]
TechSupport 是否开通技术支持服务,取值:[‘No’, ‘Yes’, ‘No internet service’]
gender 性别,取值:[‘Female’, ‘Male’]
特征取值为字符串格式的一般称为类别型变量,对于是否为老年人这个无序离散特征需要处理成类别型变量:
df['SeniorCitizen'] = df.SeniorCitizen.map({0:'no',1:'yes'})
- 样本标记
Churn 客户是否流失,取值:[‘Yes’, ‘No’]
数据分析
查看流失用户数量占比:
import matplotlib.pylab as plt
%matplotlib inline
# 设置画布大小
plt.figure(figsize=(8,8))
# 画饼图
plt.pie(df.Churn.value_counts(),explode=(0,0.1),labels=df.Churn.value_counts().index,autopct='%1.2f%%')
# 显示图片
plt.show()
结论:流失用户占比达 26.54%;
性别对用户流失的影响:
import seaborn as sns
plt.figure(figsize=(10,6))
gender=sns.countplot(x="gender",hue="Churn",data=df, palette="Pastel1")
结论:流失的用户中男女比例平衡,说明性别对于用户流失的影响不大;
年龄用户流失的影响:
plt.figure(figsize=(10,6))
# 使用sns.countplot()进行可视化分析
seniorcitizen=sns.countplot(x="SeniorCitizen",hue="Churn",data=df, palette="Pastel1")
结论:流失的用户中年轻人的数量超过老年人一倍之多,说明年轻人更容易流失;
是否婚配对用户流失的影响:
plt.figure(figsize=(10,6))
# 使用sns.countplot()进行可视化分析
partner=sns.countplot(x="Partner",hue="Churn",data=df, palette="Pastel1")
结论:流失的用户中未婚配的比已婚配的多,说明未婚配的用户更容易流失;
经济是否独立对于用户流失的影响:
plt.figure(figsize=(10,6))
# 使用sns.countplot()进行可视化分析
dependents=sns.countplot(x="Dependents",hue="Churn",data=df, palette="Pastel1")
结论:流失的用户中经济不独立的人数远大于经济独立的人数,说明经济不独立的人用户更容易流失;
合同签订期限对用户流失的影响:
plt.figure(figsize=(10,6))
# 使用sns.countplot()进行可视化分析
contract =sns.countplot(x="Contract",hue="Churn",data=df, palette="Pastel1")
结论:流失的用户中,合同期限为一个月的人数最多,一年的次之,两年的最少,说明签订的合同期限越短,客户越容易流失;
付款方式对用户流失的影响:
plt.figure(figsize=(10,6))
# 使用sns.countplot()进行可视化分析
PaymentMethod =sns.countplot(x="PaymentMethod",hue="Churn",data=df, palette="Pastel1")
结论:四种付款方式中,电子支票的流失用户最多,说明电子支票的付款方式需要进行优化;
计算用户流失与各变量的相关性:
# 先将数据df中的类别型变量onehot编码,然后计算相关系数并排序
correlations = pd.get_dummies(df).corr()['Churn_Yes'].sort_values(ascending = False)
# 选取和用户流失最相关的前10个变量
correlations[:11]
"""
Churn_Yes 1.000000
OnlineSecurity_No 0.342637
TechSupport_No 0.337281
InternetService_Fiber optic 0.308020
PaymentMethod_Electronic check 0.301919
OnlineBackup_No 0.268005
DeviceProtection_No 0.252481
MonthlyCharges 0.193356
PaperlessBilling_Yes 0.191825
Dependents_No 0.164221
SeniorCitizen_yes 0.150889
Name: Churn_Yes, dtype: float64
"""
如上可知,流失用户中排名前10的特征有:使用电子支票付款、合同签订期限为1个月、开通了电子账单、经济不独立、老年人等;对相关性可视化为:
plt.figure(figsize=(16,8))
# 将correlations使用柱状图进行可视化
plt.bar(range(len(correlations)), correlations)
sklearn决策树分类
数据预处理:
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split
# 取样本特征和标记值
X,y = df.iloc[:,:-1],df.iloc[:,[-1]]
# 类别型特征名
encode_columns = set(X.columns)-{'Contract','tenure','MonthlyCharges', 'TotalCharges'}
# 自然数编码函数(使用lambdab表达式)
encode = lambda x:LabelEncoder().fit(x).transform(x)
# 将类别型特征进行自然数编码
for c in encode_columns:
X[c] = encode(X[c])
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=1)
X
决策树建模:
from sklearn import tree
# 决策树建模
clf = tree.DecisionTreeClassifier(max_depth=3)
# 模型训练
clf = clf.fit(X_train, y_train)
# 导出决策树文件
tree.export_graphviz(clf,out_file=open("churn.dot", 'w'),
feature_names = list(X_train),
class_names = ['no churn', 'churn'],
rounded = True,
filled= True)
模型评估:
from sklearn.metrics import accuracy_score
# 输出测试集的准确率
y_pred=clf.predict(X_test)
acc=accuracy_score(y_test,y_pred)
acc
# 0.7932992617830777
决策树可视化需要额外的工具graphviz,链接:graphviz;记住安装路径,使用时,将安装目录的 bin 目录添加到系统环境变量 PATH 中;
决策树可视化:
# 生成决策树图片
# ! 用于在IPython中执行shell命令
!dot -Tpng churn.dot -o churn.png
# graphviz添加到环境变量中
import os
os.environ["PATH"] += os.pathsep + r'D:/Python37/User/envs/MASK/visualize/bin/'
"""
另外需安装依赖:conda install pydotplus
"""
from IPython.display import Image; Image('churn.png')
观察结果,比如可以找到一个规则:合同签订期限小于等于 6.5 个月,没有网站安全服务且入网时长小于等于 6.5 个月的用户预测结果为"流失"
事实上,sklearn的决策树属于CART,关于CART的详细内容见第二十课