python 数据分析 电信_实例 | 教你用Python写一个电信客户流失预测模型

原标题:实例 | 教你用Python写一个电信客户流失预测模型

8de7e531747745fdbda002e1bc49413d.jpeg

CDA数据分析师 出品

作者:真达、Mika

数据:真达

【导读】

今天教大家如何用Python写一个电信用户流失预测模型。公众号后台,回复关键字“电信”获取完整数据。

之前我们用Python写了员工流失预测模型,这次我们试试Python预测电信用户的流失。

👇👇👇员工一言不合就离职怎么办?我用Python写了个员工流失预测模型

01

532c3ce3c1c34d148700f54727fe59ac.gif

商业理解

流失客户是指那些曾经使用过产品或服务,由于对产品失去兴趣等种种原因,不再使用产品或服务的顾客。

电信服务公司、互联网服务提供商、保险公司等经常使用客户流失分析和客户流失率作为他们的关键业务指标之一,因为留住一个老客户的成本远远低于获得一个新客户。

预测分析使用客户流失预测模型,通过评估客户流失的风险倾向来预测客户流失。由于这些模型生成了一个流失概率排序名单,对于潜在的高概率流失客户,他们可以有效地实施客户保留营销计划。

下面我们就教你如何用Python写一个电信用户流失预测模型,以下是具体步骤和关键代码。

02

9e949ad3a64c4153ac26d2c8325a75e6.gif

数据理解

此次分析数据来自于IBM Sample Data Sets,统计自某电信公司一段时间内的消费数据。共有7043笔客户资料,每笔客户资料包含21个字段,其中1个客户ID字段,19个输入字段及1个目标字段-Churn(Yes代表流失,No代表未流失),输入字段主要包含以下三个维度指标:用户画像指标、消费产品指标、消费信息指标。字段的具体说明如下:

42fc94c6126f47cf8ab3be3a8d6798a5.png

回复关键字“电信”

获取本期详细数据和代码

03

数据读入和概览

首先导入所需包。

# 数据处理

importnumpy asnp

importpandas aspd

# 可视化

importmatplotlib.pyplot asplt

importseaborn assns

importplotly aspy

importplotly.graph_objs asgo

importplotly.figure_factory asff

# 前处理

fromsklearn.preprocessing importLabelEncoder

fromsklearn.preprocessing importStandardScaler

# 建模

fromsklearn.linear_model importLogisticRegression

fromsklearn.neighbors importKNeighborsClassifier

fromsklearn.tree importDecisionTreeClassifier

fromsklearn importtree

fromsklearn.ensemble importRandomForestClassifier

fromsklearn.naive_bayes importGaussianNB

fromsklearn.neural_network importMLPClassifier

fromsklearn.svm importSVC

fromlightgbm importLGBMClassifier

fromxgboost importXGBClassifier

# 模型评估

fromsklearn.model_selection importtrain_test_split, GridSearchCV

fromsklearn.metrics importconfusion_matrix, accuracy_score, classification_report

fromsklearn.metrics importroc_auc_score, roc_curve, scorer

fromsklearn.metrics importrecall_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

f73072898197490586b8d31a56727210.png

04

数据初步清洗

首先进行初步的数据清洗工作,包含错误值和异常值处理,并划分类别型和数值型字段类型,其中清洗部分包含:

OnlineSecurity、OnlineBackup、DeviceProtection、TechSupport、StreamingTV、StreamingMovies:错误值处理

TotalCharges:异常值处理

tenure:自定义分箱

定义类别型和数值型字段

# 错误值处理

repl_columns = [ 'OnlineSecurity', 'OnlineBackup', 'DeviceProtection',

'TechSupport', 'StreamingTV', 'StreamingMovies']

fori inrepl_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

deftransform_tenure(x):

ifx <= 12:

return'Tenure_1'

elifx <= 24:

return'Tenure_2'

elifx <= 36:

return'Tenure_3'

elifx <= 48:

return'Tenure_4'

elifx <= 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 fori indf.columns ifi notincat_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分布

d88aff82b70942c193c475749a83f6ed.png

经过初步清洗之后的数据集大小为7032条记录,其中流失客户为1869条,占比26.6%,未流失客户占比73.4%。

df['Churn'].value_counts

No5163

Yes1869

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.性别

392e4f85dc7d4c82bc94f4631e9e03a2.png

分析可见,男性和女性在客户流失比例上没有显著差异。

plot_bar(input_col= 'gender', target_col= 'Churn', title_name= '性别与是否流失的关系')

3. 老年用户

3d08674de9824113b79c0a6bfb34698a.png

老年用户流失比例更高,为41.68%,比非老年用户高近两倍,此部分原因有待进一步探讨。

plot_bar(input_col= 'SeniorCitizen', target_col= 'Churn', title_name= '老年用户与是否流失的关系')

4. 是否有配偶

2635715d9d5c49c4b9758d24f55f9ca0.png

从婚姻情况来看,数据显示,未婚人群中流失的比例比已婚人数高出13%。

plot_bar(input_col= 'Partner', target_col= 'Churn', title_name= '是否有配偶与是否流失的关系')

5. 上网时长

5c97208fabef44ec8313dde594deb068.png

经过分析,这方面可以得出两个结论:

用户的在网时长越长,表示用户的忠诚度越高,其流失的概率越低;

新用户在1年内的流失率显著高于整体流失率,为47.68%。

plot_bar(input_col= 'tenure_group', target_col= 'Churn', title_name= '在网时长与是否流失的关系')

6. 付款方式

867d66443d4b4f2ea7f06074f2d988e2.png

支付方式上,支付上,选择电子支票支付方式的用户流失最高,达到45.29%,其他三种支付方式的流失率相差不大。

pd.crosstab( df['PaymentMethod'], df['Churn'])

8cc402d48bbb415b9a020424cc61900d.png

plot_bar(input_col= 'PaymentMethod', target_col= 'Churn', title_name= '付款方式与是否流失关系')

7. 月费用

437a58bdf6ab4befbadd93449b8fed2f.png

整体来看,随着月费用的增加,流失用户的比例呈现高高低低的变化,月消费80-100元的用户相对较高。

plot_histogram(input_col= 'MonthlyCharges', title_name= '月费用与是否流失关系')

8. 数值型属性相关性

ef1bc812c41a49869cdc9bce7f4de135.png

从相关性矩阵图可以看出,用户的往来期间和总费用呈现高度相关,往来期间越长,则总费用越高。月消费和总消费呈现显著相关。

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 selectsuccess!

Afterselectattr: [ 'DeviceProtection', 'MultipleLines', 'OnlineSecurity', 'TechSupport', 'tenure_group', 'PaperlessBilling', 'InternetService', 'PaymentMethod', 'SeniorCitizen', 'MonthlyCharges', 'Dependents', 'Partner', 'Contract', 'StreamingTV', 'TotalCharges', 'StreamingMovies', 'OnlineBackup']

经过特征筛选,gender和PhoneService字段被去掉。

07

建模前处理

在python中,为满足建模需要,一般需要对数据做以下处理:

对于二分类变量,编码为0和1;

对于多分类变量,进行one_hot编码;

对于数值型变量,部分模型如KNN、神经网络、Logistic需要进行标准化处理。

# 筛选变量

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

aab68371210249d7b783bb2ea41745a8.png

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)

#修正索引

fori 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)

然后建立一系列基准模型并比较效果。

c7ba51c831c6451e9c2c69ffb0c6d873.png

假如我们关注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))

测试集:

precisionrecallf1-scoresupport

0 0 .860 .860 .861033

1 0 .610 .610 .61374

accuracy0 .791407

macroavg0 .730 .730 .731407

weightedavg0 .790 .790 .791407

将这颗树绘制出来。

importgraphviz

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)

c684549a0435463dad31b5fb31d417ce.png

输出决策树属性重要性排序:

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)

a2509a4563df438782a864d715323cba.png

后续优化方向:

数据:分类技术应用在目标类别分布越均匀的数据集时,其所建立之分类器通常会有比较好的分类效能。针对数据在目标字段上分布不平衡,可采用过采样和欠采样来处理类别不平衡问题;

属性:进一步属性筛选方法和属性组合;

算法:参数调优;调整预测门槛值来增加预测效能。

关注CDA数据分析师公众号

回复关键字“电信”

获取详细数据代码

CDA数据分析师

本文出品:CDA数据分析师(ID: cdacdacda)返回搜狐,查看更多

责任编辑:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/488537.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

人机融合智能与深度态势感知

来源&#xff1a;人机与认知实验室【“常无欲以观其妙&#xff0c;常有欲以观其徼。”&#xff0c;意思是身处物外可以以旁观者的身份来看待事物&#xff0c;身处事内则要考虑各种极限。】0 引言伴随着深度学习[1]、强化学习[2]等新一代人工智能技术的发展&#xff0c;智能化已…

java大数模板_java大数模板

这几天做了几道用大数的题&#xff0c;发现java来做大数运算十分方便。对acmer来说是十分实用的1.valueOf(parament); 将参数转换为制定的类型比如 int a3;BigInteger bBigInteger.valueOf(a);则b3;String s”12345”;BigInteger cBigInteger.valueOf(s);则c12345&#xff1b;2…

20162317 2016-2017-2 《程序设计与数据结构》第8周学习总结

20162317 2016-2017-2 《程序设计与数据结构》第8周学习总结 教材学习内容总结 1.异常的定义&#xff08;中断正常指令的事件&#xff09; 2.异常的特点&#xff08;异常是对象&#xff09; 3.异常的分类&#xff08;CheckedExcception 和 UncheckedException&#xff09; 4.异…

sql return的用法_【实用技能】Seacms 8.7版本SQL注入分析

有些小伙伴刚刚接触SQL编程&#xff0c;对SQL注入表示不太了解。其实在Web攻防中&#xff0c;SQL注入就是一个技能繁杂项&#xff0c;为了帮助大家能更好的理解和掌握&#xff0c;今天小编将要跟大家分享一下关于Seacms 8.7版本SQL注入分析的内容&#xff0c;一定要认真学习哦。…

国科大UCAS胡包钢教授《信息论与机器学习》课程第二讲:信息论基础一

来源&#xff1a;专知信息论中最为基本的概念就是香农熵&#xff08;第8页&#xff09;&#xff0c;由此可以导出信息论中其它各种定义&#xff0c;以至我们常规应用的其它经验式定义&#xff08;以后会提到&#xff09;。学习信息论基础知识时要避免仅是概念与定义的简单记忆&…

java 翻转句子_Java编程-句子反转

题目描述给定一个句子(只包含字母和空格)&#xff0c; 将句子中的单词位置反转&#xff0c;单词用空格分割, 单词之间只有一个空格&#xff0c;前后没有空格。 比如&#xff1a; (1) “hello xiao mi”-> “mi xiao hello”输入描述:输入数据有多组&#xff0c;每组占一行&a…

通讯录分组名称大全简单_公司起名取名:建筑公司名称大全简单大气

阅读本文前&#xff0c;请您先点击上面的“蓝色字体”再点击关注&#xff0c;这样您就可以继续免费收取到文章了&#xff0c;每天都有分享&#xff0c;完全是免费订阅&#xff0c;请放心关注。时代在变迁&#xff0c;人们的生活节奏在加快&#xff0c;各类楼盘高低错落&#xf…

java ssl 无证书_java – 如何修复SSL – 没有可用的证书

我想使用以下代码建立服务器SSL套接字连接&#xff1a;int port 12000;ServerSocketFactory ssocketFactory SSLServerSocketFactory.getDefault();ServerSocket ssocket ssocketFactory.createServerSocket(port);// Listen for connectionsSocket socket ssocket.accept(…

美国发布《量子网络战略愿景》

来源&#xff1a;国防科技要闻背景探索如何建立量子网络将促进新兴技术的发展&#xff0c;从而加速当前互联网的发展&#xff0c;提高通信的安全性&#xff0c;并大幅推动计算技术的进步。美国将利用其在量子网络领域的领先地位&#xff0c;加速在国家和金融安全、病人隐私、药…

[bzoj2127]happiness

来自FallDream的博客&#xff0c;未经允许&#xff0c;请勿转载&#xff0c;谢谢。 高一一班的座位表是个n*m的矩阵&#xff0c;经过一个学期的相处&#xff0c;每个同学和前后左右相邻的同学互相成为了好朋友。这学期要分文理科了&#xff0c;每个同学对于选择文科与理科有着自…

python错误代码翻译查询_完成自动查找翻译单词的python源代码

下面这段代码需要完成的是关于完成自动查找翻译单词的python源代码&#xff0c;找到目标单词在网上词典完成翻译的过程。 #!/usr/bin/python #codingutf-8 import urllib import sys #import xml.dom.minidom import re #是否输出例句 egTrue def main(): if len(sys.argv) 2:…

mysql sql实现原理_Mysql的数据库原理

首先要了解原理。不得不说说。mysql的执行流程。Mysql是一个单进程的服务&#xff0c;对于每一个请求都是用线程来相应的。这就需要一个连接器来处理新用户的请求、相应&#xff0c;以及销毁。1.客户端请求&#xff0c;服务端(连接器)开辟线程相应用户2.用户发起SQL语句查询数据…

Jürgen Schmidhuber眼中的深度学习十年,以及下一个十年展望

大数据文摘出品来源&#xff1a;Medium作者&#xff1a;Jrgen Schmidhuber编译&#xff1a;张秋玥、马莉2020年是充满科幻的一年&#xff0c;曾经我们畅想飞行汽车、智能洗碗机器人以及能自动写代码的程序&#xff0c;然而这一切都没有发生。2020迎接我们的是澳洲大火、新冠病毒…

AC日记——数据流中的算法 51nod 1785

数据流中的算法 思路&#xff1a; 线段树模拟&#xff1b; 时间刚刚卡在边界上&#xff0c;有时超时一个点&#xff0c;有时能过&#xff1b; 来&#xff0c;上代码&#xff1a; #include <cstdio> #include <cstring> #include <iostream> #include <alg…

docker pidfile_Zabbix5监控Docker

zabbix_agent配置Zabbix 监控Docker 时 agent 需要使用 zabbix_agent2&#xff0c;而不是zabbix_agent主要模式时配置如下&#xff1a;[rootlocalhost#] cat /etc/zabbix/zabbix_agent2.conf |grep -v ^#|grep -v ^$ PidFile/var/run/zabbix/zabbix_agent2.pidLogFile/var/log…

6种java垃圾回收算法_被说烂了的Java垃圾回收算法,我带来了最“清新脱俗”的详细图解...

一、概况理解Java虚拟机垃圾回收机制的底层原理&#xff0c;是系统调优与线上问题排查的基础&#xff0c;也是一个高级Java程序员的基本功&#xff0c;本文就针对Java垃圾回收这一主题做一些整理与记录。Java垃圾回收器的种类繁多&#xff0c;它们的设计要在吞吐量(内存空间)与…

Gartner:2020 年 AI 平台魔力象限:意外多多

来源&#xff1a;云头条众多企业决策者向市场研究公司Gartner寻求企业软件堆栈方面的建议。魔力象限报告是Gartner发布的最可信、最真实、最权威的研究报告之一。由于它影响企业的采购决策&#xff0c;因此诸多供应商竭力想在报告中占有一席之地。Gartner最近发布了数据科学和机…

CentOS6.9编译安装LNMP环境

CentOS6.9编译安装LNMP环境 今天尝试一下用编译的方式来搭建lnmp运行环境。所有软件都采用当前最新版本&#xff0c;除了CentOS。这是由于目前企业大多数应该都还在使用CentOS6的缘故&#xff0c;并且CentOS7目前还在迭代中。虽说不会有大的改动&#xff0c;但也算不上完全稳定…

python实现号码簿_使用Python进行号码簿的格式转换

今天碰到一个问题&#xff0c;如何将功能机的号码簿转换到智能机中。但是 这款BBK手机没有对应的电脑端软件&#xff0c;所以备份号码簿并不方便。我的解决方案是将功能机的电话簿导出成.csv格式的文件。导出的格式如下&#xff1a; --------------- 姓名&#xff0c;电话&…