决策树系列(三)——基于决策树算法实现⽤户流失预测
仓库文员⽂章⽬录
基于决策树算法实现电信⽤户流失预测任务
任务描述:
随着电信⾏业的不断发展,运营商们越来越重视如何扩⼤其客户群体。据研究,获取新客户所需的成本远⾼于保留现有客户的成本,因此为了满⾜在激烈竞争中的优势,保留现有客户成为⼀⼤挑战。对电信⾏业⽽⾔,可以通过数据挖掘等⽅式来分析可能影响客户决策的各种因素,以预测他们是否会产⽣流失(停⽤服务、转投其他运营商等)。
数据集:
本案例所使⽤数据集来⾃Kaggle平台,。数据集⼀共提供了7043条⽤户样本,每条样本包含21列属性,由多个维度的客户信息以及⽤户是否最终流失的标签组成,客户信息具体如下: 基本信息:包括性别、年龄、经济情况、⼊⽹时间等; 开通业务信息:包括是否开通电话业务、互联⽹业务、⽹络电视业务、技术⽀持业务等; 签署的合约信息:包括合同年限、付款⽅式、每⽉费⽤、总费⽤等。
⼀、引⼊⼯具包
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import aborn as sns
import DecisionTreeClassifier
del_lection import train_test_split
ics import confusion_matrix质量宣传标语
from imblearn.over_sampling import SMOTE
import graphviz
from sklearn import tree
⼆、数据加载
汉族的习俗data = pd.read_csv('../data/WA_Fn-UC_-Telco-Customer-Churn.csv')
pd.t_option('display.max_columns',None)
data.head()
特征含义:
变量名描述数据类型取值
customerID⽤户ID string7043个不重复值
gender性别string Male,Female
变量名描述数据类型取值SeniorCitizen是否为⽼年⼈int0,1
Partner是否有配偶string Yes,NO
Dependents是否有家属string Yes,No
tenure⼊⽹⽉数int0~72
PhoneService是否开通电话业务string Yes,NO
MultipleLines是否开通多线业务string Yes,No,No phone rvice
InternetService是否开通互联⽹业务string DSL, Fiber optic, No
OnlineSecurity是否开通在线安全业务string Yes,No,No internet rvice
OnlineBackup是否开通在线备份业务string Yes,No,No internet rvice
DeviceProtection是否开通设备保护业务string Yes,No,No internet rvice
TechSupport是否开通技术⽀持业务string Yes,No,No internet rvice
StreamingTV是否开通⽹络电视业务string Yes,No,No internet rvice
StreamingMovies是否开通⽹络电影业务string Yes,NO,No internet rvice
Contract合约期限String Month-to-Month,One Year,Two Year
PaperlessBilling是否采⽤电⼦结算string YEs,NO
PaymentMethod付款⽅式string check,Mailed check
MonthlyCharges每⽉费⽤float18.25~118.75
TotalCharges总费⽤string18.80~8684.80
Churn客户是否流失string Yes,No
三、数据预处理
3.1 重复值处理
print("原数据集样本数量:{}".format(data.shape[0]))
print("数据集去重后样本数量:{}".format(data.drop_duplicates().shape[0]))
原数据集样本数量:7043
数据集去重后样本数量:7043
可以得出,该数据集⽆缺失值。
3.2 缺失值处理
missingDf = data.isnull().sum().sort_values(ascending=Fal).ret_index()
君要臣死lumns =['feature','missing_num']
missingDf['missing_percentage']= missingDf['missing_num']/ data.shape[0]
missingDf.head()
统计结果告诉我们数据集中应该没有缺失值,但是可能存在这样的情况:采⽤ ‘Null’、‘NaN’、’ ’ 等字符(串)表⽰缺失。数据集中就有这样⼀列TotalCharges特征,存在如下所⽰的11条样本,其特征值为空格字符(’ '):旅行句子
data[data['TotalCharges']==' ']
对于TotalCharges这列原本为字符串类型的特征,由于其特征值含有数值意义,应该⾸先将其特征值转换为数值形式(浮点数)。此外,对其中不可转换的空格字符,可以⽤to_numeric()函数中的coerce参数将其转换为NaN。
# 将特征TotalCharges转为数值型
data['TotalCharges']= pd.to_numeric(data['TotalCharges'],errors='coerce')
⼀般我们常使⽤固定值(均值、中位数等)来进⾏数值型特征的缺失值填充,但通过观察缺失样本可知,tenure特征(表⽰客户的⼊⽹时间)均为0,,且在整个数据集中tenure为0与TotalCharges为缺失值是⼀⼀对应的。
结合实际业务分析,这些样本对应的客户可能⼊⽹当⽉就流失了,但仍然要收取当⽉的费⽤,因此总费⽤即为该⽤户的每⽉费⽤(MonthlyCharges)。因此本案例最终采⽤MonthlyCharges的数值对TotalCharges进⾏填充。
# 使⽤MonthlyCharges填充TotalCharges
data['TotalCharges']= data['TotalCharges'].fillna(data['MonthlyCharges'])
3.3 异常值处理
1. 数值类特征
fig = plt.figure(figsize=(10,10))
# tenure
ax1 = fig.add_subplot(3,1,1)
sns.boxplot(data = data['tenure'],orient='h',ax=ax1).t(xlabel='tenure')
# MonthlyCharges
ax2 = fig.add_subplot(3,1,2)
sns.boxplot(data = data['MonthlyCharges'],orient='h',ax=ax2).t(xlabel='MonthlyCharges')
# TotalCharges
ax3 = fig.add_subplot(3,1,3)
sns.boxplot(data = data['TotalCharges'],orient='h',ax=ax3).t(xlabel='TotalCharges')
由箱型图直观可见,这三列数值特征均不含离群点。同时,其他类别特征的取值也未见异常,因此不需要进⾏异常值处理。
四、特征选择
4.1 相关性分析
4.1 基本特征对客户流失影响
### 性别、是否⽼年⼈、是否有配偶、是否有家属等特征对客户流失的影响
baCols =['gender','SeniorCitizen','Partner','Dependents']
for i in baCols:
cnt = pd.crosstab(data[i], data['Churn'])# 构建特征与⽬标变量的列联表
cnt.plot.bar(stacked=True)# 绘制堆叠条形图,便于观察不同特征值流失的占⽐情况
plt.show()# 展⽰图像
由图可知:团员的自我批评
性别对客户流失基本没有影响
最重要的小事年龄对客户流失有影响,⽼年⼈流失占⽐⾼于年轻⼈
是否有配偶对客户流失有影响,⽆配偶客户流失占⽐⾼于有配偶客户是否有家属对客户流失有影响,⽆家属客户流失占⽐⾼于有家属客户4.2 业务特征对客户流失影响
# 电话业务
posDf = data[data['PhoneService']=='Yes']
negDf = data[data['PhoneService']=='No']
fig = plt.figure(figsize=(10,4))# 建⽴图像
ax1 = fig.add_subplot(121)
p1 = posDf['Churn'].value_counts()
ax1.pie(p1,labels=['No','Yes'],autopct='%1.2f%%',explode=(0,0.1))
ax1.t_title('Churn of (PhoneService = Yes)')
ax2 = fig.add_subplot(122)
p2 = negDf['Churn'].value_counts()
ax2.pie(p2,labels=['No','Yes'],autopct='%1.2f%%',explode=(0,0.1))
ax2.t_title('Churn of (PhoneService = No)')
plt.tight_layout(pad=0.5)# 设置⼦图之间的间距
plt.show()# 展⽰饼状图
>多头月季