精华内容
下载资源
问答
  • 电信客户流失预测

    2021-02-03 10:27:09
    CustomerID 客户ID Gender 性别 partneratt 配偶是否也为att用户 dependents_att 家人是否也是att用户 landline 是否使用att固话服务 internet_att/internet_other 是否使用att的互联网...

    案例 电信客户流失预测

    • 案例简介

      • AT&T数据,用户个人,通话,上网等信息数据

      • 充分利用数据预测客户的流失情况

      • 帮助挽留用户,保证用户基数和活跃程度

    • 数据说明

      • CustomerID 客户ID

      • Gender 性别

      • partneratt 配偶是否也为att用户

      • dependents_att 家人是否也是att用户

      • landline 是否使用att固话服务

      • internet_att/internet_other 是否使用att的互联网服务

      • Paymentbank/creditcard/electroinc 付款方式

      • MonthlyCharges 每月话费

      • TotalCharges 累计话费

      • Contract_month/1year 用户使用月度/年度合约

      • StreamingTv/streamingMovies 是否使用在线视频或者电影app

      • Churn 客户转化的flag

    • 处理流程

      • 分析流程:数据概况分析->单变量分析->相关性分析与可视化->回归模型

        • 数据概况分析

          • 数据行/列数量

          • 缺失值分布

        • 单变量分析

          • 数字型变量的描述指标(平均值,最大最小值,标准差)

          • 类别型变量(多少个分类,各自占比)

          • 正负样本占比

        • 相关性分析与可视化

          • 按类别交叉对比

          • 变量之间的相关性分析

          • 散点图/热力图

        • 逻辑回归分析

                            》 模型建立

                            》模型评估与优化 

    代码

    import pandas as pd
    import seaborn as sns
    import matplotlib.pyplot as plt
    %matplotlib inline 
    churn=pd.read_csv('churn.csv')
    churn.info()
    #显示结果
    <class 'pandas.core.frame.DataFrame'>
    RangeIndex: 7043 entries, 0 to 7042
    Data columns (total 16 columns):
     #   Column             Non-Null Count  Dtype  
    ---  ------             --------------  -----  
     0   Churn              7043 non-null   object 
     1   gender             7043 non-null   object 
     2   Partner_att        7043 non-null   int64  
     3   Dependents_att     7043 non-null   int64  
     4   landline           7043 non-null   int64  
     5   internet_att       7043 non-null   int64  
     6   internet_other     7043 non-null   int64  
     7   StreamingTV        7043 non-null   int64  
     8   StreamingMovies    7043 non-null   int64  
     9   Contract_Month     7043 non-null   int64  
     10  Contract_1YR       7043 non-null   int64  
     11  PaymentBank        7043 non-null   int64  
     12  PaymentCreditcard  7043 non-null   int64  
     13  PaymentElectronic  7043 non-null   int64  
     14  MonthlyCharges     7043 non-null   float64
     15  TotalCharges       7043 non-null   float64
    dtypes: float64(2), int64(12), object(2)
    memory usage: 880.5+ KB
    #预测目标是churn,是类别型变量  gender也是类别型变量 需要对类别型变量进行处理
    
    churn.head()
    #显示结果
      Churn gender Partner_att Dependents_att landline internet_att internet_other StreamingTV StreamingMovies Contract_Month Contract_1YR PaymentBank PaymentCreditcard PaymentElectronic MonthlyCharges TotalCharges
    0 No Female 1 0 0 1 0 0 0 1 0 0 0 1 29.85 29.85
    1 No Male 0 0 1 1 0 0 0 0 1 0 0 0 56.95 1889.50
    2 Yes Male 0 0 1 1 0 0 0 1 0 0 0 0 53.85 108.15
    3 No Male 0 0 0 1 0 0 0 0 1 1 0 0 42.30 1840.75
    4 Yes Female 0 0 1 0 1 0 0 1 0 0 0 1 70.70 151.65
    churn.describe()
    #显示结果
      Partner_att Dependents_att landline internet_att internet_other StreamingTV StreamingMovies Contract_Month Contract_1YR PaymentBank PaymentCreditcard PaymentElectronic MonthlyCharges TotalCharges
    count 7043.000000 7043.000000 7043.000000 7043.000000 7043.000000 7043.000000 7043.000000 7043.000000 7043.000000 7043.000000 7043.000000 7043.000000 7043.000000 7043.000000
    mean 0.483033 0.299588 0.903166 0.343746 0.439585 0.384353 0.387903 0.550192 0.209144 0.219225 0.216101 0.335794 64.761692 2275.929881
    std 0.499748 0.458110 0.295752 0.474991 0.496372 0.486477 0.487307 0.497510 0.406726 0.413751 0.411613 0.472301 30.090047 2266.920469
    min 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 18.250000 18.800000
    25% 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 35.500000 392.575000
    50% 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 70.350000 1389.850000
    75% 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0.000000 0.000000 0.000000 1.000000 89.850000 3778.525000
    max 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 118.750000 8684.800000
    #需要把churn和gender转变为数字型变量,使用get_dummies
    churn=pd.get_dummies(churn)
      Partner_att Dependents_att landline internet_att internet_other StreamingTV StreamingMovies Contract_Month Contract_1YR PaymentBank PaymentCreditcard PaymentElectronic MonthlyCharges TotalCharges Churn_No Churn_Yes gender_Female gender_Male
    0 1 0 0 1 0 0 0 1 0 0 0 1 29.85 29.85 1 0 1 0
    1 0 0 1 1 0 0 0 0 1 0 0 0 56.95 1889.50 1 0 0 1
    2 0 0 1 1 0 0 0 1 0 0 0 0 53.85 108.15 0 1 0 1
    3 0 0 0 1 0 0 0 0 1 1 0 0 42.30 1840.75 1 0 0 1
    4 0 0 1 0 1 0 0 1 0 0 0 1 70.70 151.65 0 1 1 0
    ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
    7038 1 1 1 1 0 1 1 0 1 0 0 0 84.80 1990.50 1 0 0 1
    7039 1 1 1 0 1 1 1 0 1 0 1 0 103.20 7362.90 1 0 1 0
    7040 1 1 0 1 0 0 0 1 0 0 0 1 29.60 346.45 1 0 1 0
    7041 1 0 1 0 1 0 0 1 0 0 0 0 74.40 306.60 0 1 0 1
    7042 0 0 1 0 1 1 1 0 0 1 0 0 105.65 6844.50 1 0 0 1

    7043 rows × 18 columns

    #数据整理,将churn_yes保留,将female保留,drop不需要的数据
    churn.drop(['Churn_No','gender_Male'],axis=1,inplace=True)
    #churn_No。churn_Yes留一个即可,任何一个都可表达数值,本案例讲的是从训练数据中得出是否流失,churn_Yes中的1代表流失,0代表没有。
    #留下gender_female,此时的1为女,0为难。需要在下面修改变量命名
    
    churn
    #显示结果
    Partner_att Dependents_att landline internet_att internet_other StreamingTV StreamingMovies Contract_Month Contract_1YR PaymentBank PaymentCreditcard PaymentElectronic MonthlyCharges TotalCharges Churn_Yes gender_Female
    0 1 0 0 1 0 0 0 1 0 0 0 1 29.85 29.85 0 1
    1 0 0 1 1 0 0 0 0 1 0 0 0 56.95 1889.50 0 0
    2 0 0 1 1 0 0 0 1 0 0 0 0 53.85 108.15 1 0
    3 0 0 0 1 0 0 0 0 1 1 0 0 42.30 1840.75 0 0
    4 0 0 1 0 1 0 0 1 0 0 0 1 70.70 151.65 1 1
    ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
    7038 1 1 1 1 0 1 1 0 1 0 0 0 84.80 1990.50 0 0
    7039 1 1 1 0 1 1 1 0 1 0 1 0 103.20 7362.90 0 1
    7040 1 1 0 1 0 0 0 1 0 0 0 1 29.60 346.45 0 1
    7041 1 0 1 0 1 0 0 1 0 0 0 0 74.40 306.60 1 0
    7042 0 0 1 0 1 1 1 0 0 1 0 0 105.65 6844.50 0 0

    7043 rows × 16 columns

    #变量大小写不规则,统一变成小写
    churn.columns=churn.columns.str.lower()  #把所有的列名改为小写
    churn.columns
    #显示结果
    Index(['partner_att', 'dependents_att', 'landline', 'internet_att',
           'internet_other', 'streamingtv', 'streamingmovies', 'contract_month',
           'contract_1yr', 'paymentbank', 'paymentcreditcard', 'paymentelectronic',
           'monthlycharges', 'totalcharges', 'churn_yes', 'gender_female'],
          dtype='object')
    #将churn_yes重命名,方便后续的变量编写,修改列名,传入columns={"要被修改的列名";‘修改后的列名’}
    churn=churn.rename(columns={'churn_yes':'flag'})
    churn=churn.rename(columns={'gender_female':'gender'})
    
    churn
    #显示结果;此时列名已经改变。
      partner_att dependents_att landline internet_att internet_other streamingtv streamingmovies contract_month contract_1yr paymentbank paymentcreditcard paymentelectronic monthlycharges totalcharges flag gender
    0 1 0 0 1 0 0 0 1 0 0 0 1 29.85 29.85 0 1
    1 0 0 1 1 0 0 0 0 1 0 0 0 56.95 1889.50 0 0
    2 0 0 1 1 0 0 0 1 0 0 0 0 53.85 108.15 1 0
    3 0 0 0 1 0 0 0 0 1 1 0 0 42.30 1840.75 0 0
    4 0 0 1 0 1 0 0 1 0 0 0 1 70.70 151.65 1 1
    ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
    7038 1 1 1 1 0 1 1 0 1 0 0 0 84.80 1990.50 0 0
    7039 1 1 1 0 1 1 1 0 1 0 1 0 103.20 7362.90 0 1
    7040 1 1 0 1 0 0 0 1 0 0 0 1 29.60 346.45 0 1
    7041 1 0 1 0 1 0 0 1 0 0 0 0 74.40 306.60 1 0
    7042 0 0 1 0 1 1 1 0 0 1 0 0 105.65 6844.50 0 0

    7043 rows × 16 columns

    #二分类模型,查看样本分布情况,分析flag 1和0的占比
    churn.flag.value_counts() #流失共有1869个,未流失5174个
    #显示结果
    0    5174
    1    1869
    Name: flag, dtype: int64
    
    #大多数是未流失用户,流失用户占26.5%
    churn.flag.value_counts(normalize=True)
    #显示结果
    0    0.73463
    1    0.26537
    Name: flag, dtype: float64
    
    #churn.flag.value_counts(1)  #value_counts(1) 查看比例 
    #等同churn.flag.value_counts(normalize=True)
    #value_counts()  把每個值分別有多少展示一下.在 python 当中 除了 0 其他數字都是 true。所以在这里,括号里可以用任何数字表示。
    summary=churn.groupby('flag') 
    summary.mean()           #按流失率求各个部门占比,这几个数据流失比较明显 ~~~ internet_other	contract_month  paymentelectronic
    #显示结果
      partner_att dependents_att landline internet_att internet_other streamingtv streamingmovies contract_month contract_1yr paymentbank paymentcreditcard paymentelectronic monthlycharges totalcharges gender
    flag                              
    0 0.528218 0.344801 0.901044 0.379204 0.347700 0.365868 0.369927 0.429068 0.252609 0.248550 0.249324 0.250097 61.265124 2545.918081 0.492656
    1 0.357945 0.174425 0.909042 0.245586 0.693954 0.435527 0.437667 0.885500 0.088818 0.138042 0.124131 0.573034 74.441332 1528.514714 0.502408

    结论:观察flag在0和1的情况下,所有自变量的差别 internet_other变量,在0的分组中,均值是0.35,在1的分组中,均值是0.69。数据显示如果使用别的公司的互联网,用户流失的概率就越高(拿0.35跟0.69对比,流失的数据占了没流失的近2倍。)

    sns.countplot(y='contract_month',hue='flag',data=churn) #hue目标值是什么target
    <matplotlib.axes._subplots.AxesSubplot at 0x232eef53fd0>

    结论:contract_month为1的客户流失的概率更高,即与非按月付费客户相比,按月付费客户流失比例高

    #围绕flag变量,分析其他变量与flag的相关关系;ascending=False降序
    churn.corr()[['flag']].sort_values('flag',ascending=False)
    
    #显示结果
      flag
    flag 1.000000
    contract_month 0.405103
    internet_other 0.308020
    paymentelectronic 0.301919
    monthlycharges 0.193356
    streamingtv 0.063228
    streamingmovies 0.061382
    landline 0.011942
    gender 0.008612
    paymentbank -0.117937
    internet_att -0.124214
    paymentcreditcard -0.134302
    partner_att -0.150448
    dependents_att -0.164221
    contract_1yr -0.177820
    totalcharges -0.198175

    结论:contract_month,internet_other,paymentelectronic与flag相关性高。

    逻辑回归模型,

    选择不同的数据进行建模,以下是对模型测试,并进行不断优化。

    第一次,随机选取可用x数据

    #设定因变量与自变量, y是 flag, x根据刚才的相关分析挑选contract_month,internet_other与streamingtv
    #自变量可以分为几类,partner/dependents,internet,streaming,contract,payment,charges,后续可以自己挑选进行建模
    #确定目标值和特征值
    y=churn['flag']
    x=churn[['contract_month','internet_other','streamingtv']]
    
    #调用sklearn模块,随机抽取训练集与测试集
    from sklearn.model_selection import train_test_split
    x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.3,random_state=100)
    
    #使用LR预测
    from sklearn import linear_model
    lr=linear_model.LogisticRegression()
    lr.fit(x_train,y_train)
    #LogisticRegression()
    
    lr.intercept_
    #array([-3.25029156])
    
    lr.coef_
    #array([[2.2229613 , 1.15089043, 0.24559832]])
    
    模型的评估
    y_pred_train=lr.predict(x_train)
    y_pred_test=lr.predict(x_test)
    import sklearn.metrics as metrics
    metrics.accuracy_score(y_train,y_pred_train)
    #0.7697768762677485
    
    metrics.accuracy_score(y_test,y_pred_test)
    #0.7453857075248462
    
    from sklearn.metrics import roc_curve,auc
    fpr,tpr,threshold=roc_curve(y_train,y_pred_train)
    roc_auc=auc(fpr,tpr)
    roc_auc
    #0.7247770357096229

    第二次,将是否使用在线视频 改为电子支付 测试对数据的影响

    #设定因变量与自变量, y是 flag, x经过模型优化改变为contract_month,internet_other,将streamingtv调整为paymentelectronic
    y=churn['flag']
    x=churn[['contract_month','internet_other','paymentelectronic']]
    
    #调用sklearn模块,随机抽取训练集与测试集
    from sklearn.model_selection import train_test_split
    x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.3,random_state=100)
    
    #使用LR预测
    from sklearn import linear_model
    lr=linear_model.LogisticRegression()
    lr.fit(x_train,y_train)
    #LogisticRegression()
    
    lr.intercept_
    #array([-3.21842661])
    
    lr.coef_
    #array([[2.01264249, 1.05076404, 0.64248053]])
    
    #模型的评估
    y_pred_train=lr.predict(x_train)
    y_pred_test=lr.predict(x_test)
    import sklearn.metrics as metrics
    metrics.accuracy_score(y_train,y_pred_train)
    #0.7776876267748478
    metrics.accuracy_score(y_test,y_pred_test)
    #0.7624230951254141
    
    from sklearn.metrics import roc_curve,auc
    fpr,tpr,threshold=roc_curve(y_train,y_pred_train)
    roc_auc=auc(fpr,tpr)
    roc_auc
    #0.6669635362478181

    第三次,改变测试集和训练集的分布

    #模型优化,测试集与训练集对半分.
    y=churn['flag']
    x=churn[['contract_month','internet_other','paymentelectronic']]
    
    #调用sklearn模块,随机抽取训练集与测试集
    from sklearn.model_selection import train_test_split
    x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.5,random_state=100)
    
    #使用LR预测
    from sklearn import linear_model
    lr=linear_model.LogisticRegression()
    lr.fit(x_train,y_train)
    #LogisticRegression()
    
    lr.intercept_
    #array([-3.22833942])
    
    lr.coef_
    #array([[2.03292538, 1.04095427, 0.62567014]])
    
    #模型的评估
    y_pred_train=lr.predict(x_train)
    y_pred_test=lr.predict(x_test)
    import sklearn.metrics as metrics
    metrics.accuracy_score(y_train,y_pred_train)
    #0.7779040045441636
    metrics.accuracy_score(y_test,y_pred_test)
    #0.768313458262351
    
    from sklearn.metrics import roc_curve,auc
    fpr,tpr,threshold=roc_curve(y_train,y_pred_train)
    roc_auc=auc(fpr,tpr)
    roc_auc
    #0.666251219518281

    结论:auc 的选择如果为0.5-1是推荐的。 风控0.6, 0.7, 0.8,很少有超过0.85的情况.(零点六几基本就可以用了,所以这里的数据为有效数据)

    AUC的物理意义为任取一对例和负例,正例得分大于负例得分的概率,AUC越大,表明方法效果越好

    电信客户流失预测:系数1*特征1+系数2*特征2+系数3*特征3.。。。=流失概率

     

    1,要针对沉默会员做会员重新激活,应该挑选具有什么特征的会员?

         按月付费的流失率比较高,想办法让用户办按年付费的套餐,可以给按月付费的老用户发广告,老用户回馈,充值返现。满减优惠。

    2,商品A库存积压严重,现在要通过促销活动清仓,选择哪些类型的促销活动更容易实现该目标?

         根据类别找到更感兴趣的用户。不断换用户特征,测试出一批用户后,找出更可能买的用户特征。哪些用户更可能买。

    3,网站需要大流量广告位来满足VIP商家的精准广告投放,具有哪些特征的广告位更符合VIP商家的客户需求?

         测试出的这一批用户,可以反过来看下用户所拥有的特征。

    展开全文
  • 针对数据挖掘方法在电信客户流失预测中的局限性,提出将信息融合与数据挖掘相结合,分别从数据层、特征层、决策层构建客户流失预测模型。确定客户流失预测指标;根据客户样本在特征空间分布的差异性对客户进行划分,...
  • 基于粒子分类优化的BP网络在电信客户流失预测中的应用
  • 结合过滤式和封装式特征选择方法的优点及组合分类器的较高预测能力,提出了一种基于Fisher比率与预测风险准则的分步特征选择方法结合组合分类器的电信客户流失预测模型。首先,基于Fisher比率从原始特征集合中提取...
  • 针对电信领域客户流失的问题,提出了改进聚类的客户流失预测模型。...通过实际电信客户数据集测试,与传统的预测算法比较,证明这种算法适合解决大数据集和不平衡数据,具有更高的精确度,能够取得较好的客户流失预测效果。
  • 电信客户流失预测模型设计与实现,工作中总结的
  • 基于贝叶斯网络的电信客户流失预测分析 很好
  • 针对客户流失数据集的非平衡性问题和错分代价的差异性问题,将代价敏感学习应用于Veropoulos提出的采用不同惩罚系数的支持向量机,建立客户流失预测模型,对实际的电信客户流失数据进行验证。通过与传统SVM、C4.5和...
  • 许多公司经历了不同的技术,这些技术可以预测客户流失率并帮助设计有效的客户保留计划,因为获取新客户的成本远高于保留现有客户的成本。 在本文中,已使用三种机器学习算法通过两个基准数据集IBM Watson数据集来...
  • CDA数据分析师 出品 作者:真达、Mika ...电信服务公司、互联网服务提供商、保险公司等经常使用客户流失分析和客户流失率作为他们的关键业务指标之一,因为留住一个老客户的成本远远低于获得一个新客户。 ...

     

     CDA数据分析师 出品  

    作者:真达、Mika

    数据:真达  

    【导读】

    今天教大家如何用Python写一个电信用户流失预测模型。之前我们用Python写了员工流失预测模型,这次我们试试Python预测电信用户的流失。

    01、商业理解

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

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

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

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

    02、数据理解

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

    03、数据读入和概览

    首先导入所需包。

    # 数据处理
    import numpy as np 
    import pandas as pd 
    
    # 可视化
    import matplotlib.pyplot as plt 
    import seaborn as sns 
    import plotly as py 
    import plotly.graph_objs as go 
    import plotly.figure_factory as ff 
    
    # 前处理
    from sklearn.preprocessing import LabelEncoder
    from sklearn.preprocessing import StandardScaler
    
    # 建模
    from sklearn.linear_model import LogisticRegression
    from sklearn.neighbors import KNeighborsClassifier
    from sklearn.tree import DecisionTreeClassifier
    from sklearn import tree 
    from sklearn.ensemble import RandomForestClassifier
    from sklearn.naive_bayes import GaussianNB
    from sklearn.neural_network import MLPClassifier
    from sklearn.svm import SVC
    from lightgbm import LGBMClassifier
    from xgboost import XGBClassifier
    
    # 模型评估
    from sklearn.model_selection import train_test_split, GridSearchCV
    from sklearn.metrics import confusion_matrix, accuracy_score, classification_report
    from sklearn.metrics import roc_auc_score, roc_curve, scorer
    from sklearn.metrics import recall_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()  

    04、数据初步清洗

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

    • OnlineSecurity、OnlineBackup、DeviceProtection、TechSupport、StreamingTV、StreamingMovies:错误值处理
    • TotalCharges:异常值处理
    • tenure:自定义分箱
    • 定义类别型和数值型字段
    # 错误值处理
    repl_columns = ['OnlineSecurity', 'OnlineBackup', 'DeviceProtection', 
                    'TechSupport','StreamingTV', 'StreamingMovies']
    
    for i in repl_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
    def transform_tenure(x):
        if x <= 12:
            return 'Tenure_1'
        elif x <= 24:
            return 'Tenure_2'
        elif x <= 36:
            return 'Tenure_3'
        elif x <= 48:
            return 'Tenure_4'
        elif x <= 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 for i in df.columns if i not in cat_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分布

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

    df['Churn'].value_counts() 
    No     5163
    Yes    1869
    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.性别

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

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

    3. 老年用户

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

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

    4. 是否有配偶

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

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

    5. 上网时长

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

    • 用户的在网时长越长,表示用户的忠诚度越高,其流失的概率越低;
    • 新用户在1年内的流失率显著高于整体流失率,为47.68%。
    plot_bar(input_col='tenure_group', target_col='Churn', title_name='在网时长与是否流失的关系') 

    6. 付款方式

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

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

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

    7. 月费用

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

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

    8. 数值型属性相关性

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

    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 select success!
    After select attr: ['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() 

    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) 
    
    #修正索引
    for i 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) 

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

    假如我们关注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)) 
    测试集:
                   precision    recall  f1-score   support
    
               0       0.86      0.86      0.86      1033
               1       0.61      0.61      0.61       374
    
        accuracy                           0.79      1407
       macro avg       0.73      0.73      0.73      1407
    weighted avg       0.79      0.79      0.79      1407

    将这棵树绘制出来。

    import graphviz
    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) 

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

    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)  

    后续优化方向:

    • 数据:分类技术应用在目标类别分布越均匀的数据集时,其所建立之分类器通常会有比较好的分类效能。针对数据在目标字段上分布不平衡,可采用过采样和欠采样来处理类别不平衡问题;
    • 属性:进一步属性筛选方法和属性组合;
    • 算法:参数调优;调整预测门槛值来增加预测效能。

     

    展开全文
  • 【摘 要】  为减少用户流失,提高用户保有率,文章介绍一种基于智慧运营平台,将大数据技术和数据挖掘技术相结合,对电信客户流失进行预测的模型。该模型利用大数据技术处理用户离网前的海量数据信息,分析流失...

    【摘 要】  为减少用户流失,提高用户保有率,文章介绍一种基于智慧运营平台,将大数据技术和数据挖掘技术相结合,对电信客户流失进行预测的模型。该模型利用大数据技术处理用户离网前的海量数据信息,分析流失用户特征,建立用户流失预测,提前锁定流失风险较高的用户,有针对性地制定维挽策略,精准开展维系挽留活动,能够有效降低用户离网率。

    【关键词】  大数据;流失预测;数据挖掘;客户流失;维系挽留

    引言

    随着移动通信成本逐步下降,移动用户渗透率超过100%,新增市场趋于饱和,面对新增市场的激烈竞争,存量用户的保有显得越来越重要。一项调查数据表明,争取1位新客户的成本是保住1位老客户的5倍。面对新的竞争形势,运营商需要从传统只重视增量发展模式向“增存并重”发展模式转变。如何最大限度地降低客户的流失并挽留客户,成为决策者关注的话题。

    客户流失给运营商带来了巨大损失,成功挽留一个即将流失的客户比重新发展一个客户节约大量成本。减少客户流失的关键是提前预测潜在的流失客户,采取相关措施提高客户的满意度,实现该预测的关键是数据挖 掘[1]和大数据技术。基于大数据技术的数据挖掘就是从海量的客户资料、使用行为、消费行为、上网轨迹等信息中提取有用的信息进行组合关联,准确判断客户流失的现状或倾向,可以让企业及时并有针对性的对客户进行挽留[2];因此,利用大数据技术进行数据挖掘,预测客户流失、减少客户流失的发生成为电信行业研究的重点。

    1 国内外研究现状

    在数据挖掘方面,国外有很多案例和做法值得学习,比如:文献[3]中运用决策树、Logistic回归、 人工神经网络等算法建立了移动用户流失预测模型。 Lightbridge[4]公司运用CART算法分析了新英格兰的一 家移动服务商的数据并建立了客户流失模型AT&T 公司很早就开始在大数据上的探索[5],2009年开始与 Teradata公司合作引进天睿公司的大数据解决方案。

    在过去的几十年中,中国企业都扮演着技术跟随者的角色,现阶段我国互联网企业在数据挖掘、大数据处理以及人工智能、云计算等领域都有了巨大的发展。 比如文献[6]中使用K-means聚类算法对电信客户进行细分,在此基础上探索了客户细分在营销中的实际应用。 文献[7]中利用神经网络算法建立用户流失预测模型,分析用户流失特征。文献[8]中利用Spark平台实现了多种神经网络算法,对用户流失问题提出了快速精确的模型。国内的电信企业虽然都建立了客户流失预测、客户 分群等模型,但大多都是基于数据挖掘软件如SPSS、SAS等应用,使用的数据量有限,不能全面分析用户流失行为。

    2 大数据平台及技术

    安徽联通构建基于B域、O域和M域数据融合的大数据平台——智慧运营平台,实现数字化转型及全业务流程的智慧运营。智慧运营平台通过企业级大数据平台 实现企业全量数据的接入及治理,当前包括Hadoop、 Universe、实时流处理三大资源池,共计140多个节 点,存储容量3PB、2200核CPU、8T内存计算资源,实现资源动态管理;流处理平台具备百万级别消息并发 处理能力,支持1分钟级别提供用户位置能力(见图1)。

    在这里插入图片描述

    智慧运营平台接入BSS、CBSS、OSS、SEQ、上 网等全网多种数据源,利用BDI(Big Data Integration, 数据集成套件)和Flume进行离线数据及日志数据的抽取、转换、加载等数据采集功能,实现高性能海量数 据处理和存储。利用Hadoop、Universe、实时流处理三大资源池,有效支撑上层各种应用的开发和运行。利用基于大数据分析平台构建的新一代智能数据挖掘系统 SmartMiner进行自动化数据挖掘,实现各种算法模型的训练和预测。借助智慧运营平台强大的大数据分析和处理能力,结合现网客户运营的经验,建立有效的用户流失预测模型,实现用户的流失预警、维系策略匹配、客户反馈优化等一整套流程,能够有效降低用户流失。

    3 离网预测模型构建

    3.1 离网预测原理

    离网预测模型[9]主要是根据历史数据特征,通过数据挖掘算法,建立预测模型,并将模型应用于现网用户,预测出离网概率高的用户。其主要包括数据准备、 模型训练和验证、离网预测三大部分[10]。如图2所示,数据准备阶段,根据出账和充值规律定义离网规则,通过对电信业务和用户行为的理解,从运营商各域数据里提取数据,并筛选离网预测特征字段,构建离网预测特征库。模型训练和验证阶段,选取数据挖掘算法,进行模型训练、评估和调优,训练出最佳模型。离网预测阶段,将训练的最佳模型应用于现网数据,实现准确的流失预测。进一步通过有效的维系手段,对预测流失用户进行精准维系,减少用户离网,提升在网用户价值。

    在这里插入图片描述

    3.2 随机森林算法

    传统数据挖掘中进行流失预测多采用决策树算法[11],它的特点有训练时间复杂度低、预测的过程比较快、模型容易展示等。但是单决策树容易过拟合,虽然可以通过剪 枝等方法减少这种情况的发生,但仍有不足。2001年Leo Breiman在决策树的基础上提出了随机森林算法[12]。
    想学习的同学欢迎加入大数据学习扣群:805127855,有大量干货(零基础以及进阶的经典实战)分享给大家,并且有清华大学毕业的资深大数据讲师给大家免费授课,给大家分享目前国内最完整的大数据高端实战实用学习流程体系

    随机森林是由多个决策树构成的森林,算法分类结果由这些决策树投票得到,决策树在生成过程中分别在行方向和列方向上添加随机过程,行方向上构建决策树 时采用有放回抽样(bootstrapping)得到训练数据,列方向上采用无放回随机抽样得到特征子集,并据此得到其 最优切分点。从图3中可以看到,通过K次训练,得到K棵不同的决策树{T1,T2,…,TK},再将这些树组合成一个分类模型系统,随机森林是一个组合模型,内部仍然是基于决策树,同单一的决策树分类不同的是,随机森林通过多个决策树投票结果进行分类,算法不容易出现过度拟合问题。

    在这里插入图片描述

    3.3 数据准备

    3.3.1 离网定义及数据需求

    为了进一步提前锁定离网倾向用户,经过历史数据的比对,结合用户使用行为的分析,决定将过缴费期10天未缴费的用户定义为流失用户。根据传统数据挖掘实现的离网预测案例的经验,考虑到大数据系统的处理能力,通过对连续3个月内离网的用户进行离网打标,增加离网用户的样本量,提高离网预测的准确率;通过对目标用户中隔月后离网的用户进行打标,预留1个月的 预测结果干预期,进行维系挽留。如图4所示,采用连续7个月的历史数据,对第N-6月的数据进行隔月后的连 续3个月(N-4月、N-3月、N-2月)离网用户打标,取N-6 月、N-5月、N-4月连续3个月的正负样本并集,解决了传统打标负样本量不足和维系干预期太短等问题。

    在这里插入图片描述

    3.3.2 数据特征提取

    根据业务经验,选取与用户流失可能存在相关性的所有属性,进行数据审查,筛选存在相关性较大的特 征属性。本次建模数据特征主要采用B域用户通信及消 费行为等基本属性、衍生属性(汇总、比例、趋势和波动)、挖掘属性等,增加O域样本数据,如上网行为、 终端属性指标(换机、应用偏好、掉话率、上网协议响 应成功率等)。如表1所示,数据维度包括基础信息维度、通信行为信息、账务信息、消费行为变化维度、交往圈信息、呼叫异网维度、投诉维度、通信行为维度及上网轨迹、掉话率等。根据这些维度数据合并汇总成数据挖掘特征宽表,用于模型训练和验证。

    在这里插入图片描述

    3.4 建立模型

    流失客户预测模型的建立,具体包括原始数据处理、特征宽表构建、模型训练、模型评估和模型调优五个部分。如图5所示,智慧运营平台通过连接全网数 据的接口,获取建模所需的BSS系统(业务支持系统)数 据和OSS系统(运营支持系统)数据。BSS系统是运营商 向用户开展业务的主要IT组成部分,OSS系统是电信服务提供商用来管理通信网络的主要系统。BSS数据包括 CRM(客户关系)、Billing(账单数据)、详单数据及投诉数据,OSS数据包括分组交换数据(Package Switch, PS)、测量报告数据(Measurement Report,MR)和电路交换数据(Circuit Switch,CS)。其中PS数据描述了用户连接网络的情况,如上网速度、掉线率和移动搜索文本 信息;MR数据可以用来给用户定位,获取用户运动轨迹;CS数据描述的是用户的通话质量,如掉话率等。

    我们将获取的原始数据存储到Hadoop分布式文 件系统中(HDFS),然后再利用Hive进行特征生成和处理工作。HDFS可以处理PB级别的超大文件,Hive可 以提供简单的SQL查询功能,并能将SQL语句转化为 MapReduce任务分布式运行。

    在这里插入图片描述

    特征宽表生成后,我们利用Spark的高效计算能 力,在SmartMiner中选取随机森林算法进行流失预测模型的训练,经过训练结果的多次验证和评估,我们将 随机森林设置为200颗树,SQR采样方法,树的最大深 度为15层,叶子最小样本数100个,最大分箱数32,进行模型建立。将分类器训练出来的模型应用到现网数据,可以预测未来3个月有离网倾向的用户,按照离网倾向的高低排名,锁定维系挽留的目标客户。

    3.5 模型评估

    训练模型的好坏可以通过对历史流失数据的检验来验证,模型评估参数一般包括准确率和覆盖率,准确率越高、覆盖率越大,模型效果越好,其中:准确率=预测流失准确的客户数 / 预测为流失的客户数;覆盖率=预测流失准确的客户数 / 实际流失的客户数。

    如图6所示,我们根据建模训练数据的规则,可以在第N月预测第N+2月、N+3月、N+4月的流失用户, 第N+1月为我们的维系窗口期。

    我们选取2016年16月数据进行训练,对710月数据进行模型预测,如图7所示,经过2016年9月至 2017年2月数据的验证,可以得到7~10月的预测数据 TOP50000中查准率基本在80%,查全率40%。

    在这里插入图片描述

    4 离网根因分析

    通过对离网用户的特征属性进行聚类分析,离网用户大致原因可以分为:资费原因、合约感知原因、社会交往影响原因、终端换机原因、地域变更原因、服务质量原因、通信质量原因、弃卡原因、新入网质量原因及其他原因等。如表2所示,提取2016年11月数据预测2017年1~3月离网概率top400000用户,对其离网情况进行验证,其准确率达到52%以上。

    在这里插入图片描述

    5 应用

    5.1 策略匹配

    通过对流失用户的根因分析,结合现有维系业务,将预测的离网用户,根据业务特征进行分类,匹配相应策略指导市分VIP维系客户经理进行外呼维系。如表3所示,将离网倾向较高的用户分为话务异常、业务异常和服务异常三类,针对话务异常用户,重点进行优惠活动介绍,增加用户黏性;对于业务异常用户,推荐合约 续约及更换SIM卡;对于服务异常用户,进行及时安抚并给予一定赠送。

    在这里插入图片描述

    5.2 维系效果

    针对三星级以上用户,我们利用在网维系系统进行了针对性的维系挽留。从2017年1月开始,我们将大数据系统预测出的离网倾向较高的高价值用户通过在网维系系统下发到市分VIP客户经理处,根据匹配的策略进行精准维系。如图8所示,2015年9月至12月,高价值 用户准离网率平均值为2.04%,全网准离网率为3.6%。 模型应用后,高价值离网率从2017年2月开始持续降低,如图9所示,截至2017年7月下降到1.35%,平均准离网率为1.49%,相比应用前的2.04%下降了0.55%, 每月多挽留客户8230户,高价值户均ARPU按90元计算,月均减少损失74万元,年减少损失888万元。

    在这里插入图片描述

    6 总结

    本文阐述了利用智慧运营大数据平台,对流失客户的特征进行的分析和研究,利用SmartMiner分析系统选取随机森林算法,建立客户流失预测模型,通过多次的训练和优化,逐步提高流失预测模型的准确性。通过对离网用户的根因分析,制定相应维系策略,匹配到相应的离网倾向用户,在全网进行了系统化的精准维系,有效提升了用户保有率。下一步将结合维系效果,继续优化模型参数,完善训练模型,进一步提升流失预测的准确率和覆盖率,继续研究用户流失根因,根据离网根因匹配维系策略,进一步降低用户流失,增强用户黏性,提升客户价值。
    想学习的同学欢迎加入大数据学习扣群:805127855,有大量干货(零基础以及进阶的经典实战)分享给大家,并且有清华大学毕业的资深大数据讲师给大家免费授课,给大家分享目前国内最完整的大数据高端实战实用学习流程体系

    展开全文
  • 作者:真达、Mika数据:真达【导读】今天教大家如何用Python写一个电信用户流失预测模型。公众号后台,回复关键字“电信”获取完整数据。之前我们用Python写了员工流失预测模型,...

    作者:真达、Mika

    数据:真达  

    【导读】

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

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

    ????????????

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

    01

    商业理解

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

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

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

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

    02

    数据理解

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

    03

    数据读入和概览

    首先导入所需包。

    # 数据处理
    import numpy as np 
    import pandas as pd 
    
    # 可视化
    import matplotlib.pyplot as plt 
    import seaborn as sns 
    import plotly as py 
    import plotly.graph_objs as go 
    import plotly.figure_factory as ff 
    
    # 前处理
    from sklearn.preprocessing import LabelEncoder
    from sklearn.preprocessing import StandardScaler
    
    # 建模
    from sklearn.linear_model import LogisticRegression
    from sklearn.neighbors import KNeighborsClassifier
    from sklearn.tree import DecisionTreeClassifier
    from sklearn import tree 
    from sklearn.ensemble import RandomForestClassifier
    from sklearn.naive_bayes import GaussianNB
    from sklearn.neural_network import MLPClassifier
    from sklearn.svm import SVC
    from lightgbm import LGBMClassifier
    from xgboost import XGBClassifier
    
    # 模型评估
    from sklearn.model_selection import train_test_split, GridSearchCV
    from sklearn.metrics import confusion_matrix, accuracy_score, classification_report
    from sklearn.metrics import roc_auc_score, roc_curve, scorer
    from sklearn.metrics import recall_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()  
    

    04

    数据初步清洗

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

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

    • TotalCharges:异常值处理

    • tenure:自定义分箱

    • 定义类别型和数值型字段

    # 错误值处理
    repl_columns = ['OnlineSecurity', 'OnlineBackup', 'DeviceProtection', 
                    'TechSupport','StreamingTV', 'StreamingMovies']
    
    for i in repl_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
    def transform_tenure(x):
        if x <= 12:
            return 'Tenure_1'
        elif x <= 24:
            return 'Tenure_2'
        elif x <= 36:
            return 'Tenure_3'
        elif x <= 48:
            return 'Tenure_4'
        elif x <= 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 for i in df.columns if i not in cat_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分布

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

    df['Churn'].value_counts() 
    No     5163
    Yes    1869
    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.性别

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

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

    3. 老年用户

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

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

    4. 是否有配偶

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

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

    5. 上网时长

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

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

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

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

    6. 付款方式

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

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

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

    7. 月费用

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

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

    8. 数值型属性相关性

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

    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 select success!
    After select attr: ['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() 
    

    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) 
    
    #修正索引
    for i 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) 
    

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

    假如我们关注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)) 
    
    测试集:
                   precision    recall  f1-score   support
    
               0       0.86      0.86      0.86      1033
               1       0.61      0.61      0.61       374
    
        accuracy                           0.79      1407
       macro avg       0.73      0.73      0.73      1407
    weighted avg       0.79      0.79      0.79      1407
    

    将这颗树绘制出来。

    import graphviz
    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) 
    

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

    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)  
    

    后续优化方向:

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

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

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

    本文出品:CDA数据分析师(ID: cdacdacda)

    近期开班情况

    课程详情请扫码咨询

    展开全文
  • 对于上述观点,我采用了以下的数学模型来做分析依据: 其中由于决策树更加直观可以看到客户流失与哪些相关因素有关,下面是对上述分析的佐证。 2、代码实现 数据集分类: 数据划分处理:将数据分为3类 1、二分类...
  • 上一part,构建了好多模型对数据集进行分类预测。 这一趴将模型表现指标进行汇总和集中展示。
  • 数据集来自kaggle社区,电信客户流失数据分析与预测。 此部分包括数据导入、简单处理、描述性统计分析等内容。 设计饼图、柱状图、组合散点图和表格等的绘制技术。
  • 本趴主要使用各种模型来对数据进行训练和预测。 数据选取技术包含过抽样计数、单变量特征选取; 模型构建技术包含基本线性模型、决策树、随机森林、朴素贝叶斯、支持向量机、LightGBM和Xboost,以及相关指标可视化...
  • 继续之前电信客户流失分析与预测的内容,第二趴。 此趴主要是对数据进行标准化、相关分析、主成分分析和二元变量雷达图等可视化展现。 比较重要的内容哦,雷达图真的很炫酷。

空空如也

空空如也

1 2 3 4 5 ... 11
收藏数 209
精华内容 83
关键字:

电信客户流失预测