精华内容
下载资源
问答
  • 摘 要:本文简述了BP 神经网络的基本原理,提出了一种基于 BP 神经网络的客户流失 预测模型。实验表明,该模型的辨识精度高,能正确的对客户的需求进行评估,以减少客户 流失来提高企业的利润。 关键词:神经网络;...
  • 源自:数据分析不是个事儿作者:启方客户流失是所有与消费者挂钩行业都会关注的点。因为发展一个新客户是需要一定成本的,一旦客户流失,成本浪费不说,挽回一个客户的成本更大。今天分享一个用户流失...

    源自:数据分析不是个事儿

    作者:启方

    客户流失是所有与消费者挂钩行业都会关注的点。因为发展一个新客户是需要一定成本的,一旦客户流失,成本浪费不说,挽回一个客户的成本更大。

    今天分享一个用户流失预测,以电信行业为例。

    所以,电信行业在竞争日益激烈当下,如何挽留更多用户成为一项关键业务指标。为了更好运营用户,这就要求要了解流失用户的特征,分析流失原因,预测用户流失,确定挽留目标用户并制定有效方案。

    一、提出问题

    1、哪些用户可能会流失?

    2、流失概率更高的用户有什么共同特征?

    二、理解数据

    1、采集数据
    本数据集来自DF ,数据源地址:
    https://www.datafountain.cn/dataSets/35/details#

    本数据集描述了电信用户是否流失以及其相关信息,共包含7044条数据,共20个字段,介绍下各个字段:

    • customerID :用户ID。

    • gender:性别。(Female & Male)

    • SeniorCitizen :老年人 (1表示是,0表示不是)

    • Partner :是否有配偶 (Yes or No)

    • Dependents :是否经济独立 (Yes or No)

    • tenure :客户的职位(0-72,共73个职位)

    • PhoneService :是否开通电话服务业务 (Yes or No)

    • MultipleLines:是否开通了多线业务(Yes 、No or No phoneservice 三种)

    • InternetService:是否开通互联网服务 (No, DSL数字网络,fiber optic光纤网络 三种)

    • OnlineSecurity:是否开通网络安全服务(Yes,No,No internetserive 三种)

    • OnlineBackup:是否开通在线备份业务(Yes,No,No internetserive 三种)

    • DeviceProtection:是否开通了设备保护业务(Yes,No,No internetserive 三种)

    • TechSupport:是否开通了技术支持服务(Yes,No,No internetserive 三种)

    • StreamingTV:是否开通网络电视(Yes,No,No internetserive 三种)

    • StreamingMovies:是否开通网络电影(Yes,No,No internetserive 三种)

    • Contract:签订合同方式 (按月,一年,两年)

    • PaperlessBilling:是否开通电子账单(Yes or No)

    • PaymentMethod:付款方式(bank transfer,credit card,electronic check,mailed check)

    • MonthlyCharges:月费用

    • TotalCharges:总费用

    • Churn:该用户是否流失(Yes or No)

    2、导入数据


    3、查看数据集信息

    三、数据清洗

    1、查找缺失值

    数据集中有5174名用户没流失,有1869名客户流失,数据集不均衡。

    2、查看数据类型

    TotalCharges表示总费用,这里为对象类型,需要转换为float类型

    3、转换类型

    再次查找缺失值:

    这里存在11个缺失值,由于数量不多我们可以直接删除这些行

    4、处理缺失值

    5、数据归一化处理

    四、数据可视化呈现

    1、查看流失客户占比


    由图中结果可以看出,流失客户占整体客户的26.6%。

    2、性别、老年人、配偶、亲属对流客户流失率的影响

    性别、老年人占比结果

    配偶、亲属占比结果

    可以看出,男性与女性用户之间的流失情况基本没有差异,而在老年用户中流失占比明显比非老年用户更高,在所有数据中未婚与已婚人数基本持平,但未婚中流失人数比已婚中的流失人数高出了快一倍,从经济独立情况来看,经济未独立的用户流失率要远远高于经济独立的用户。

    3、提取特征

    4、构造相关性矩阵

    5、使用热地图显示相关系数

    结论:

    从上图可以看出,互联网服务、网络安全服务、在线备份业务、设备保护业务、技术支持服务、网络电视和网络电影之间存在较强的相关性,多线业务和电话服务之间也有很强的相关性,并且都呈强正相关关系。

    6、使用one-hot编码

    7、电信用户是否流失与各变量之间的相关性

    由图上可以看出,变量gender 和 PhoneService 处于图形中间,其值接近于 0 ,这两个变量对电信客户流失预测影响非常小,可以直接舍弃。

    8、网络安全服务、在线备份业务、设备保护业务、技术支持服务、网络电视、网络电影和无互联网服务对客户流失率的影响

    由上图可以看出,在网络安全服务、在线备份业务、设备保护业务、技术支持服务、网络电视和网络电影六个变量中,没有互联网服务的客户流失率值是相同的,都是相对较低。

    这可能是因为以上六个因素只有在客户使用互联网服务时才会影响客户的决策,这六个因素不会对不使用互联网服务的客户决定是否流失产生推论效应。

    9、签订合同方式对客户流失率的影响

    由图上可以看出,签订合同方式对客户流失率影响为:按月签订 > 按一年签订 > 按两年签订,这可能表明,设定长期合同对留住现有客户更有效。

    10、付款方式对客户流失率的影响

    由图上可以看出,在四种支付方式中,使用Electronic check的用户流流失率最高,其他三种支付方式基本持平,因此可以推断电子账单在设计上影响用户体验。

    五、数据预处理

    由前面结果可知,CustomerID表示每个客户的随机字符,对后续建模不影响,我这里选择删除CustomerID列;gender 和 PhoneService 与流失率的相关性低,可直接忽略。

    对客户的职位、月费用和总费用进行去均值和方差缩放,对数据进行标准化:

    使用箱线图查看数据是否存在异常值:

    由以上结果可以看出,在三个变量中不存在明显的异常值。

    查看对象类型字段中存在的值:

    综合之前的结果来看,在六个变量中存在No internet service,即无互联网服务对客户流失率影响很小,这些客户不使用任何互联网产品,因此可以将No internet service 和 No 是一样的效果,可以使用 No 替代 No internet service。

    使用Scikit-learn标签编码,将分类数据转换为整数编码:

    六、构建模型

    1、建立训练数据集和测试数据集

    2、选择机器学习算法

    3、训练模型

    4、评估模型

    召回率(recall)的含义是:原本为对的当中,预测为对的比例(值越大越好,1为理想状态)
    精确率、精度(precision)的含义是:预测为对的当中,原本为对的比例(值越大越好,1为理想状态)
    F1分数(F1-Score)指标综合了Precision与Recall的产出的结果

    F1-Score的取值范围从0到1的,1代表模型的输出最好,0代表模型的输出结果最差。

    综上所述,在10种分类算法中朴素贝叶斯(Naive Bayes)的F1分数最大为63.31%,所以使用朴素贝叶斯模型效果最好。

    七、实施方案

    八、结论

    通过上述分析,我们可以大致勾勒出容易流失的用户特征:

    老年用户与未婚且经济未独立的青少年用户更容易流失。

    电话服务对用户的流失没有直接的影响。

    提供的各项网络服务项目能够降低用户的流失率。

    签订合同越久,用户的留存率越高。

    采用electronic check支付的用户更易流失。

    针对上述诊断结果,可有针对性的对此提出建议:
    推荐老年用户与青少年用户采用数字网络,且签订2年期合同(可以各种辅助优惠等营销手段来提高2年期合同的签订率),若能开通相关网络服务可增加用户粘性,因此可增加这块业务的推广,同时考虑改善电子账单支付的用户体验。

    最后,分享源码:

    # coding: utf-8
    
    
    # # 电信客户流失预测
    
    
    # ## 1、导入数据
    
    
    # In[1]:
    
    
    import numpy as np
    import pandas as pd 
    import os
    
    
    
    
    # In[2]:
    
    
    # 导入相关的包
    import matplotlib.pyplot as plt
    import seaborn as sns
    from pylab import rcParams
    import matplotlib.cm as cm
    
    
    import sklearn
    from sklearn import preprocessing
    from sklearn.preprocessing import LabelEncoder               # 编码转换
    from sklearn.preprocessing import StandardScaler
    from sklearn.model_selection import StratifiedShuffleSplit
    
    
    from sklearn.ensemble import RandomForestClassifier          # 随机森林
    from sklearn.svm import SVC, LinearSVC                       # 支持向量机
    from sklearn.linear_model import LogisticRegression          # 逻辑回归
    from sklearn.neighbors import KNeighborsClassifier           # KNN算法
    from sklearn.naive_bayes import GaussianNB                   # 朴素贝叶斯
    from sklearn.tree import DecisionTreeClassifier              # 决策树分类器
    from xgboost import XGBClassifier
    from catboost import CatBoostClassifier
    from sklearn.ensemble import AdaBoostClassifier
    from sklearn.ensemble import GradientBoostingClassifier     
    
    
    from sklearn.metrics import classification_report, precision_score, recall_score, f1_score
    from sklearn.metrics import confusion_matrix
    from sklearn.model_selection import GridSearchCV
    from sklearn.metrics import make_scorer
    from sklearn.ensemble import VotingClassifier
    
    
    from sklearn.decomposition import PCA
    from sklearn.cluster import KMeans
    from sklearn.metrics import silhouette_score
    
    
    import warnings
    warnings.filterwarnings('ignore')
    
    
    get_ipython().magic('matplotlib inline')
    
    
    
    
    # In[3]:
    
    
    # 读取数据文件
    telcom=pd.read_csv(r"F:\data\WA_Fn-UseC_-Telco-Customer-Churn.csv")
    
    
    
    
    # ## 2、查看数据集信息
    
    
    # In[4]:
    
    
    telcom.head(10)
    
    
    
    
    # In[5]:
    
    
    # 查看数据集大小
    telcom.shape
    
    
    
    
    # In[6]:
    
    
    # 获取数据类型列的描述统计信息
    telcom.describe()
    
    
    
    
    # ## 3、数据清洗
    
    
    # In[7]:
    
    
    # 查找缺失值
    pd.isnull(telcom).sum()
    
    
    
    
    # In[8]:
    
    
    telcom["Churn"].value_counts()
    
    
    
    
    # 数据集中有5174名用户没流失,有1869名客户流失,数据集不均衡。
    
    
    # In[9]:
    
    
    telcom.info()
    
    
    
    
    # TotalCharges表示总费用,这里为对象类型,需要转换为float类型  
    
    
    # In[10]:
    
    
    telcom['TotalCharges']=telcom['TotalCharges'].convert_objects(convert_numeric=True) # convert_numeric=True表示强制转换数字(包括字符串),不可转换的值变为NaN
    telcom["TotalCharges"].dtypes
    
    
    
    
    # In[11]:
    
    
    # 再次查找是否存在缺失值
    pd.isnull(telcom["TotalCharges"]).sum()
    
    
    
    
    # 这里存在11个缺失值,由于数量不多我们可以直接删除这些行
    
    
    # In[12]:
    
    
    # 删除缺失值所在的行
    telcom.dropna(inplace=True)
    telcom.shape
    
    
    
    
    # In[13]:
    
    
    # 数据归一化处理
    # 对Churn 列中的值 Yes和 No分别用 1和 0替换,方便后续处理
    telcom['Churn'].replace(to_replace = 'Yes', value = 1,inplace = True)
    telcom['Churn'].replace(to_replace = 'No', value = 0,inplace = True)
    telcom['Churn'].head()
    
    
    
    
    # In[14]:
    
    
    telcom['Churn'].replace(to_replace='Yes', value=1, inplace=True)
    telcom['Churn'].replace(to_replace='No',  value=0, inplace=True)
    telcom['Churn'].head()
    
    
    
    
    # ## 4、数据可视化呈现
    
    
    # In[15]:
    
    
    # 查看流失客户占比
    """
    画饼图参数:
    labels  (每一块)饼图外侧显示的说明文字
    explode  (每一块)离开中心距离
    startangle  起始绘制角度,默认图是从x轴正方向逆时针画起,如设定=90则从y轴正方向画起
    shadow   是否阴影
    labeldistance label  绘制位置,相对于半径的比例, 如<1则绘制在饼图内侧
    autopct   控制饼图内百分比设置,可以使用format字符串或者format function
         '%1.1f'指小数点前后位数(没有用空格补齐)
    pctdistance 类似于labeldistance,指定autopct的位置刻度
    radius   控制饼图半径
    """
    churnvalue=telcom["Churn"].value_counts()
    labels=telcom["Churn"].value_counts().index
    
    
    rcParams["figure.figsize"]=6,6
    plt.pie(churnvalue,labels=labels,colors=["whitesmoke","yellow"], explode=(0.1,0),autopct='%1.1f%%', shadow=True)
    plt.title("Proportions of Customer Churn")
    plt.show()
    
    
    
    
    # In[16]:
    
    
    # 性别、老年人、配偶、亲属对流客户流失率的影响
    f, axes = plt.subplots(nrows=2, ncols=2, figsize=(10,10))
    
    
    plt.subplot(2,2,1)
    gender=sns.countplot(x="gender",hue="Churn",data=telcom,palette="Pastel2") # palette参数表示设置颜色,这里设置为主题色Pastel2
    plt.xlabel("gender")
    plt.title("Churn by Gender")
    
    
    plt.subplot(2,2,2)
    seniorcitizen=sns.countplot(x="SeniorCitizen",hue="Churn",data=telcom,palette="Pastel2")
    plt.xlabel("senior citizen")
    plt.title("Churn by Senior Citizen")
    
    
    plt.subplot(2,2,3)
    partner=sns.countplot(x="Partner",hue="Churn",data=telcom,palette="Pastel2")
    plt.xlabel("partner")
    plt.title("Churn by Partner")
    
    
    plt.subplot(2,2,4)
    dependents=sns.countplot(x="Dependents",hue="Churn",data=telcom,palette="Pastel2")
    plt.xlabel("dependents")
    plt.title("Churn by Dependents")
    
    
    
    
    # In[17]:
    
    
    # 提取特征
    charges=telcom.iloc[:,1:20]
    # 对特征进行编码
    """
    离散特征的编码分为两种情况:
    1、离散特征的取值之间没有大小的意义,比如color:[red,blue],那么就使用one-hot编码
    2、离散特征的取值有大小的意义,比如size:[X,XL,XXL],那么就使用数值的映射{X:1,XL:2,XXL:3}
    """
    corrDf = charges.apply(lambda x: pd.factorize(x)[0])
    corrDf .head()
    
    
    
    
    # In[18]:
    
    
    # 构造相关性矩阵
    corr = corrDf.corr()
    corr
    
    
    
    
    # In[19]:
    
    
    # 使用热地图显示相关系数
    '''
    heatmap    使用热地图展示系数矩阵情况
    linewidths 热力图矩阵之间的间隔大小
    annot      设定是否显示每个色块的系数值
    '''
    plt.figure(figsize=(20,16))
    ax = sns.heatmap(corr, xticklabels=corr.columns, yticklabels=corr.columns, 
                     linewidths=0.2, cmap="YlGnBu",annot=True)
    plt.title("Correlation between variables")
    
    
    
    
    # 结论:从上图可以看出,互联网服务、网络安全服务、在线备份业务、设备保护业务、技术支持服务、网络电视和网络电影之间存在较强的相关性,多线业务和电话服务之间也有很强的相关性,并且都呈强正相关关系。
    
    
    # In[20]:
    
    
    # 使用one-hot编码
    tel_dummies = pd.get_dummies(telcom.iloc[:,1:21])
    tel_dummies.head()
    
    
    
    
    # In[21]:
    
    
    # 电信用户是否流失与各变量之间的相关性
    plt.figure(figsize=(15,8))
    tel_dummies.corr()['Churn'].sort_values(ascending = False).plot(kind='bar')
    plt.title("Correlations between Churn and variables")
    
    
    
    
    # 由图上可以看出,变量gender 和 PhoneService 处于图形中间,其值接近于 0 ,这两个变量对电信客户流失预测影响非常小,可以直接舍弃。
    
    
    # In[22]:
    
    
    # 网络安全服务、在线备份业务、设备保护业务、技术支持服务、网络电视、网络电影和无互联网服务对客户流失率的影响
    covariables=["OnlineSecurity", "OnlineBackup", "DeviceProtection", "TechSupport", "StreamingTV", "StreamingMovies"]
    fig,axes=plt.subplots(nrows=2,ncols=3,figsize=(16,10))
    for i, item in enumerate(covariables):
        plt.subplot(2,3,(i+1))
        ax=sns.countplot(x=item,hue="Churn",data=telcom,palette="Pastel2",order=["Yes","No","No internet service"])
        plt.xlabel(str(item))
        plt.title("Churn by "+ str(item))
        i=i+1
    plt.show()
    
    
    
    
    # 由上图可以看出,在网络安全服务、在线备份业务、设备保护业务、技术支持服务、网络电视和网络电影六个变量中,没有互联网服务的客户流失率值是相同的,都是相对较低。
    # 
    # 这可能是因为以上六个因素只有在客户使用互联网服务时才会影响客户的决策,这六个因素不会对不使用互联网服务的客户决定是否流失产生推论效应。
    
    
    # In[23]:
    
    
    # 签订合同方式对客户流失率的影响
    sns.barplot(x="Contract",y="Churn", data=telcom, palette="Pastel1", order= ['Month-to-month', 'One year', 'Two year'])
    plt.title("Churn by Contract type")
    
    
    
    
    # 由图上可以看出,签订合同方式对客户流失率影响为:按月签订 > 按一年签订 > 按两年签订,这可能表明,设定长期合同对留住现有客户更有效。
    
    
    # In[24]:
    
    
    # 付款方式对客户流失率的影响
    plt.figure(figsize=(10,5))
    sns.barplot(x="PaymentMethod",y="Churn", data=telcom, palette="Pastel1", order= ['Bank transfer (automatic)', 'Credit card (automatic)', 'Electronic check','Mailed check'])
    plt.title("Churn by PaymentMethod type")
    
    
    
    
    # 由图上可以看出,在四种支付方式中,使用Electronic check的用户流流失率最高,其他三种支付方式基本持平,因此可以推断电子账单在设计上影响用户体验。
    
    
    
    
    
    
    
    
    # ## 5、数据预处理
    
    
    # 由前面结果可知,CustomerID表示每个客户的随机字符,对后续建模不影响,我这里选择删除CustomerID列;gender 和 PhoneService 与流失率的相关性低,可直接忽略。
    
    
    # In[26]:
    
    
    telcomvar=telcom.iloc[:,2:20]
    telcomvar.drop("PhoneService",axis=1, inplace=True)
    
    
    # 提取ID
    telcom_id = telcom['customerID']
    
    
    telcomvar.head()
    
    
    
    
    # In[27]:
    
    
    # 对客户的职位、月费用和总费用进行去均值和方差缩放,对数据进行标准化
    """
    标准化数据,保证每个维度的特征数据方差为1,均值为0,使得预测结果不会被某些维度过大的特征值而主导。
    """
    scaler = StandardScaler(copy=False)
    # fit_transform()的作用就是先拟合数据,然后转化它将其转化为标准形式
    scaler.fit_transform(telcomvar[['tenure','MonthlyCharges','TotalCharges']])
    
    
    
    
    # In[28]:
    
    
    # tranform()的作用是通过找中心和缩放等实现标准化
    telcomvar[['tenure','MonthlyCharges','TotalCharges']]=scaler.transform(telcomvar[['tenure','MonthlyCharges','TotalCharges']])
    
    
    
    
    # In[29]:
    
    
    # 使用箱线图查看数据是否存在异常值
    plt.figure(figsize = (8,4))
    numbox = sns.boxplot(data=telcomvar[['tenure','MonthlyCharges','TotalCharges']], palette="Set2")
    plt.title("Check outliers of standardized tenure, MonthlyCharges and TotalCharges")
    
    
    
    
    # 由以上结果可以看出,在三个变量中不存在明显的异常值
    
    
    # In[30]:
    
    
    # 查看对象类型字段中存在的值
    def uni(columnlabel):
        print(columnlabel,"--" ,telcomvar[columnlabel].unique())  # unique函数去除其中重复的元素,返回唯一值
    
    
    telcomobject=telcomvar.select_dtypes(['object'])
    for i in range(0,len(telcomobject.columns)):
        uni(telcomobject.columns[i])
    
    
    
    
    # 综合之前的结果来看,在六个变量中存在No internet service,即无互联网服务对客户流失率影响很小,这些客户不使用任何互联网产品,因此可以将No internet service 和 No 是一样的效果,可以使用 No 替代 No internet service
    
    
    # In[31]:
    
    
    telcomvar.replace(to_replace='No internet service', value='No', inplace=True)
    telcomvar.replace(to_replace='No phone service', value='No', inplace=True)
    for i in range(0,len(telcomobject.columns)):
        uni(telcomobject.columns[i])
    
    
    
    
    # In[32]:
    
    
    # 使用Scikit-learn标签编码,将分类数据转换为整数编码
    def labelencode(columnlabel):
        telcomvar[columnlabel] = LabelEncoder().fit_transform(telcomvar[columnlabel])
    
    
    for i in range(0,len(telcomobject.columns)):
        labelencode(telcomobject.columns[i])
    
    
    for i in range(0,len(telcomobject.columns)):
        uni(telcomobject.columns[i])
    
    
    
    
    # ## 6、构建模型
    
    
    # ### (1)建立训练数据集和测试数据集
    
    
    # In[33]:
    
    
    """
    我们需要将数据集拆分为训练集和测试集以进行验证。
    由于我们所拥有的数据集是不平衡的,所以最好使用分层交叉验证来确保训练集和测试集都包含每个类样本的保留人数。
    交叉验证函数StratifiedShuffleSplit,功能是从样本数据中随机按比例选取训练数据(train)和测试数据(test)
    参数 n_splits是将训练数据分成train/test对的组数,可根据需要进行设置,默认为10
    参数test_size和train_size是用来设置train/test对中train和test所占的比例
    参数 random_state控制是将样本随机打乱
    """
    X=telcomvar
    y=telcom["Churn"].values
    
    
    sss=StratifiedShuffleSplit(n_splits=5, test_size=0.2, random_state=0)
    print(sss)
    print("训练数据和测试数据被分成的组数:",sss.get_n_splits(X,y))
    
    
    
    
    # In[34]:
    
    
    # 建立训练数据和测试数据
    for train_index, test_index in sss.split(X, y):
        print("train:", train_index, "test:", test_index)
        X_train,X_test=X.iloc[train_index], X.iloc[test_index]
        y_train,y_test=y[train_index], y[test_index]
    
    
    
    
    # In[35]:
    
    
    # 输出数据集大小
    print('原始数据特征:', X.shape,
          '训练数据特征:',X_train.shape,
          '测试数据特征:',X_test.shape)
    
    
    print('原始数据标签:', y.shape,
          '   训练数据标签:',y_train.shape,
          '   测试数据标签:',y_test.shape)
    
    
    
    
    # ### (2)选择机器学习算法
    
    
    # In[36]:
    
    
    # 使用分类算法,这里选用10种分类算法
    Classifiers=[["Random Forest",RandomForestClassifier()],
                 ["Support Vector Machine",SVC()],
                 ["LogisticRegression",LogisticRegression()],
                 ["KNN",KNeighborsClassifier(n_neighbors=5)],
                 ["Naive Bayes",GaussianNB()],
                 ["Decision Tree",DecisionTreeClassifier()],
                 ["AdaBoostClassifier", AdaBoostClassifier()],
                 ["GradientBoostingClassifier", GradientBoostingClassifier()],
                 ["XGB", XGBClassifier()],
                 ["CatBoost", CatBoostClassifier(logging_level='Silent')]  
    ]
    
    
    
    
    # ### (3)训练模型
    
    
    # In[37]:
    
    
    Classify_result=[]
    names=[]
    prediction=[]
    for name,classifier in Classifiers:
        classifier=classifier
        classifier.fit(X_train,y_train)
        y_pred=classifier.predict(X_test)
        recall=recall_score(y_test,y_pred)
        precision=precision_score(y_test,y_pred)
        class_eva=pd.DataFrame([recall,precision])
        Classify_result.append(class_eva)
        name=pd.Series(name)
        names.append(name)
        y_pred=pd.Series(y_pred)
        prediction.append(y_pred)
    
    
    
    
    # ### (4)评估模型
    
    
    # In[38]:
    
    
    # 评估模型
    """
    召回率(recall)的含义是:原本为对的当中,预测为对的比例(值越大越好,1为理想状态)
    精确率、精度(precision)的含义是:预测为对的当中,原本为对的比例(值越大越好,1为理想状态)
    F1分数(F1-Score)指标综合了Precision与Recall的产出的结果
    F1-Score的取值范围从0到1的,1代表模型的输出最好,0代表模型的输出结果最差。
    """
    
    
    names=pd.DataFrame(names)
    names=names[0].tolist()
    result=pd.concat(Classify_result,axis=1)
    result.columns=names
    result.index=["recall","precision","f1score"]
    result
    
    
    
    
    # 综上所述,在10种分类算法中朴素贝叶斯(Naive Bayes)的F1分数最大为63.31%,所以使用朴素贝叶斯模型效果最好。
    
    
    # ## 7、实施方案
    
    
    # 预测数据集特征(由于没有提供预测数据集,这里选取后10行作为需要预测的数据集)
    pred_X = telcomvar.tail(10)
    
    
    # 提取customerID
    pre_id = telcom_id.tail(10)
    
    
    # 使用朴素贝叶斯方法,对预测数据集中的生存情况进行预测
    model = GaussianNB()
    model.fit(X_train,y_train)
    pred_y = model.predict(pred_X)
    
    
    # 预测结果
    predDf = pd.DataFrame({'customerID':pre_id, 'Churn':pred_y})
    predDf
    

         精 彩 文 章 

    END
    最后说个题外话,相信大家都知道视频号了,随着灰度范围扩大,越来越多的小伙伴都开通了视频号。小詹也开通了一个视频号,会分享互联网那些事、读书心得与副业经验,欢迎扫码关注,和小詹一起向上生长!「没有开通发布权限的尽量多互动,提升活跃度可以更快开通哦」
    
    
    展开全文
  • 1 商业理解流失客户是指那些曾经...通过评估客户流失的风险倾向来预测客户流失,对于潜在的高概率流失客户,可以有效地实施客户保留营销计划。2 数据理解分析数据来自于统计自某电信公司一段时间内的消费数据。共有7...

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

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

    通过评估客户流失的风险倾向来预测客户流失,对于潜在的高概率流失客户,可以有效地实施客户保留营销计划。

    2 数据理解

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

    3 数据读入和概览

    3.1 查看缺失值

    3.2 查看重复值

    3.3 错误值处理

    4 探索性分析

    对指标进行归纳梳理,分用户画像指标,消费产品指标,消费信息指标。探索影响用户流失的关键因素。

    4.1 标签分布

    4.2 用户性别与是否流失

    流失客户在性别方面基本没有显著性差异。

    4.3 用户年龄与是否流失

    4.4 用户婚姻与是否流失

    4.5 用户经济与死否流失

    4.6 用户付款与是否流失

    4.7 数值型特征的分布

    5 数据预处理与特征工程

    5.1 字符型数据编码

    5.2 特征选择

    6 模型构建与评估对于客户流失预测的分类问题,本次选择集成学习Baging下的随机森林算法和Boosting下的Xgboost算法分别进行建模和分析。

    6.2 Xgboost

    展开全文
  • 客户流失预测

    2020-08-19 15:23:52
    根据五月数据,对六月客户是否流失做一个预测 五月数据 部分操作举例 五月数据九十万条,74个特征 数据筛选 导入数据,查看缺失值 data5.isnull().sum() 删除其中一列对结果影响并不大的四行缺失值 用众数填充另一...

    根据五月数据,对六月客户是否流失做一个预测

    五月数据 部分操作举例

    五月数据九十万条,74个特征

    数据筛选

    导入数据,查看缺失值

    data5.isnull().sum()
    

    删除其中一列对结果影响并不大的四行缺失值
    用众数填充另一列的缺失值

    data5=data5.dropna(subset=["ZHU_OFFER_ID"])
    #宽带接入方式CONSOLIDATE_CONNET_MODE
    import numpy as np
    from scipy.stats import mode
    print("# Print mode(list):", mode(data5['CONSOLIDATE_CONNET_MODE']))
    print("# CONSOLIDATE_CONNET_MODE中最常见的成员为:{},出现了{}次。".format(mode(data5['CONSOLIDATE_CONNET_MODE'])[0][0], mode(data5['CONSOLIDATE_CONNET_MODE'])[1][0]))
    #把缺失的4730个数据填充为“FTTH接入”
    data5['CONSOLIDATE_CONNET_MODE'] = data5['CONSOLIDATE_CONNET_MODE'].fillna('FTTH接入')
    

    在这里插入图片描述

    #Print mode(list): ModeResult(mode=array([‘FTTH接入’], dtype=object), count=array([852397]))
    #CONSOLIDATE_CONNET_MODE中最常见的成员为:FTTH接入,出现了852397次。

    查看热力图

    plt.figure(figsize=(30, 30), dpi=120)
    sns.heatmap(data5.corr())
    plt.savefig('res.png')
    

    在这里插入图片描述
    对某些列做直方图、箱线图分析,判断是否为可用特征
    (其实是带有人为主观的去判断,不是很准确吧)
    举例:

    #是否二路宽带
    sns.countplot(x='IS_SECOND_KD',hue='IF_FALG',data=data5)
    

    在这里插入图片描述

    #宽带速率
    sns.boxplot(y='CONSOLIDATE_SPEND', x='IF_FALG', data=data5,order=[1,0])
    plt.ylim(0,700)
    

    在这里插入图片描述
    根据热力图进行分析,哪些数据可能会对结果有影响,将相关性太高太低的部分进行散点图绘制,找出某些特征中间的关联,仅保留个别特征。
    绘制散点图,找出关系
    在这里插入图片描述

    数据处理

    删除某些行数过小不会对结果造成太大影响的行

    data5.drop(data5[data5['CONSOLIDATE_CONNET_MODE'] == "PON专线"].index, inplace=True)
    data5.drop(data5[data5['CONSOLIDATE_CONNET_MODE'] == "EOC接入"].index, inplace=True)
    

    独热编码

    data5 = data5.join(pd.get_dummies(data5.CONSOLIDATE_CONNET_MODE))
    data5 = data5.join(pd.get_dummies(data5.BILLING_MODE_ID))
    data5 = data5.join(pd.get_dummies(data5.STATE_NAME))
    data5 = data5.join(pd.get_dummies(data5.COUNTRY_FLAG))
    

    分箱处理

    ONLINE_LEN=list(data5['ONLINE_LEN'])
    ONLINE_LEN_cats=pd.qcut(ONLINE_LEN,3,duplicates="drop")
    ONLINE_LEN_dummies=pd.get_dummies(ONLINE_LEN_cats)
    ONLINE_LEN_dummies
    
    data5["ONLINE_LEN_(3.999, 25.0]"]=ONLINE_LEN_dummies.values[:,0]
    data5["ONLINE_LEN_(25.0, 53.0]"]=ONLINE_LEN_dummies.values[:,1]
    data5["ONLINE_LEN_(53.0, 782.0]"]=ONLINE_LEN_dummies.values[:,2]
    

    建模

    将筛选出的最终的特征提取出来,形成一个单独的表格

    from sklearn.naive_bayes import GaussianNB
    
    from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
    
    from sklearn.tree import DecisionTreeClassifier
    from sklearn.linear_model import LogisticRegression as LR
    from sklearn.metrics import recall_score
    from sklearn.metrics import f1_score
    
    X = feature_5.drop(['IF_FALG'],1)
    y = feature_5['IF_FALG']
    

    将五月数据分为训练集、测试集进行检测

    from sklearn.model_selection import train_test_split
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42)
    
    dtc = DecisionTreeClassifier()
    dtc.fit(X,y)
    y_pred_dtc = dtc.predict(X_test)
    print("决策树模型训练集的正确率:%s" % dtc.score(X,y))
    print("决策树模型测试集的正确率:%s" % dtc.score(X_test,y_test))
    
    # pred_array = np.array(dtc.predict_proba(features_test))
    # pred_array
    
    r_dtc = recall_score(y_test, y_pred_dtc, average='binary')
    print("决策树模型的召回率:%s" % r_dtc)
    f1score_dtc = f1_score(y_test, y_pred_dtc, average='binary')
    print("决策树模型的f1值:%s" % f1score_dtc)
    

    结果:
    决策树模型训练集的正确率:0.9854719499671242
    决策树模型测试集的正确率:0.9853323422951915
    决策树模型的召回率:0.9479498152821976
    决策树模型的f1值:0.9395471930683199

    from sklearn.ensemble import RandomForestClassifier     #随机森林
    forest = RandomForestClassifier(n_estimators=1000, random_state=0, n_jobs=-1)
    forest.fit(X_train, y_train)
    
    y_pred_forest = forest.predict(X_test)
    print("随机森林算法训练集评分:%s" % forest.score(X_train,y_train))
    print("随机森林算法测试集评分:%s" % forest.score(X_test,y_test))
    pred_array = np.array(forest.predict_proba(X_test))
    pred_array
    
    #print(accuracy_score(y_test,y_pred_forest),roc_auc_score(y_test,y_pred_forest))
    print("随机森林模型的召回率:%s" % recall_score(y_test,y_pred_forest),"随机森林模型的f1值:%s" % f1_score(y_test,y_pred_forest))
    

    结果:
    随机森林算法训练集评分:0.985750119848529
    随机森林算法测试集评分:0.9821305267602288
    随机森林模型的召回率:0.9377811917041589 随机森林模型的f1值:0.9265798080919424

    六月

    六月份数据太过庞大,因此进行了数据拆分,仅用了60万数据
    选择的特征和五月完全一致,处理方式基本相同
    将六月的处理后的特征提取出来
    进行预测

    X = feature_5.drop(['IF_FALG'],1)
    y = feature_5['IF_FALG']
    X_test_6 = feature_6.drop([ 'BILLING_ARRIVE_FLAG'],1)
    y_test_6 = feature_6['BILLING_ARRIVE_FLAG']
    
    dtc = DecisionTreeClassifier()
    dtc.fit(X,y)
    y_pred_dtc = dtc.predict(X_test_6)
    print("决策树模型训练集的正确率:%s" % dtc.score(X,y))
    print("决策树模型测试集的正确率:%s" % dtc.score(X_test_6,y_test_6))
    
    # pred_array = np.array(dtc.predict_proba(features_test))
    # pred_array
    
    r_dtc = recall_score(y_test_6, y_pred_dtc, average='binary')
    print("决策树模型的召回率:%s" % r_dtc)
    f1score_dtc = f1_score(y_test_6, y_pred_dtc, average='binary')
    print("决策树模型的f1值:%s" % f1score_dtc)
    

    结果:
    决策树模型训练集的正确率:0.9854719499671242
    决策树模型测试集的正确率:0.9870322310729746
    决策树模型的召回率:0.8396955786421841
    决策树模型的f1值:0.641177013190665

    from sklearn.metrics import classification_report
    
    print(classification_report(y_test_6, y_pred_dtc))
    

    在这里插入图片描述

    from sklearn.ensemble import RandomForestClassifier     #随机森林
    forest = RandomForestClassifier(n_estimators=1000, random_state=0, n_jobs=-1)
    forest.fit(X_train, y_train)
    
    y_pred_forest = forest.predict(X_test_6)
    print("随机森林算法训练集评分:%s" % forest.score(X_train,y_train))
    print("随机森林算法测试集评分:%s" % forest.score(X_test_6,y_test_6))
    # pred_array = np.array(forest.predict_proba(X_test_6))
    # pred_array
    
    #print(accuracy_score(y_test_6,y_pred_forest),roc_auc_score(y_test_6,y_pred_forest))
    print("随机森林模型的召回率:%s" % recall_score(y_test_6,y_pred_forest),"随机森林模型的f1值:%s" % f1_score(y_test_6,y_pred_forest))
    

    结果:
    随机森林算法训练集评分:0.985750119848529
    随机森林算法测试集评分:0.9869738927808864
    随机森林模型的召回率:0.852017395506161 随机森林模型的f1值:0.6434925413986587

    print(classification_report(y_test_6, y_pred_forest))
    

    在这里插入图片描述

    查看所选特征的相关性

    #互信息法及特征相关性
    plt.figure(figsize=(50,50))
    sns.heatmap(feature_6.corr(),annot=True,cmap='CMRmap_r')
    

    在这里插入图片描述
    小结:对特征的处理方式问题,导致结果并不是非常的好,加入的人为主观因素过多。特征处理其实还有很多种方法,后面也会再仔细想一想,面对特征时应该要发散思维想到更多直接的处理方式。有些简单粗暴的处理方式可能会更好。还是对业务数据的不熟练。建模也只是那些很普遍的建模方式,并没有根据实际的数据特征去思考最佳的建模方案。

    展开全文
  • 点击上方“AI公园”,关注公众号,选择加“星标“或“置顶”作者:Carl Dawson编译:ronghuaiyang导读借用生存分析的方法来进行用户流失预测,用到了Cox Propor...

    点击上方“AI公园”,关注公众号,选择加“星标“或“置顶”


    作者:Carl Dawson

    编译:ronghuaiyang

    导读

    借用生存分析的方法来进行用户流失的预测,用到了Cox Proportional Hazards模型。

    客户流失率很难预测。在你能做一些事情来阻止客户离开之前,你需要知道,谁将离开,什么时候离开,这将在多大程度上影响你的业务。在这篇文章中,我将解释使用生存分析来预测和预防流失的技术。

    客户会不会流失

    许多数据分析师试图用黑白分明的方式来模拟这个问题:客户流失vs客户没有流失。我们很容易用这种方式来看待这个问题,因为它是一种我们都知道的模型 —— 监督分类。

    但是这样做忽略了客户流失预测问题的许多细微之处 —— 风险、时间线、客户离开的成本等等。

    不管怎样,让我们从一个分类模型开始,看看我们最终的结果。

    我们的数据集

    我们使用的数据集是Kaggle Telco Churn dataset:https://www.kaggle.com/c/telco-churn/data,它包含超过7000个客户的记录,包括特征,比如客户的每月费用,成为客户的时长(几个月),是否有各种附加互联网服务等等。

    以下是前5行:

    首先你会注意到有很多类别变量为文本值(' Yes ', ' No ',等等),我们使用pd.get_dummies来修复这些:

    dummies = pd.get_dummies(
        data[[ 'gender', 'SeniorCitizen', 'Partner', 'Dependents', 'tenure', 'PhoneService', 'MultipleLines', 'InternetService', 'OnlineSecurity', 'OnlineBackup', 'DeviceProtection', 'TechSupport', 'StreamingTV', 'StreamingMovies', 'Contract', 'PaperlessBilling', 'PaymentMethod', 'Churn' ]]
    ) 
    data = dummies.join(data[['MonthlyCharges', 'TotalCharges']])
    

    如果你按照下面的步骤去做,你还需要修复total charge列中的一些缺失值,这些值使整列变成了文本而不是数字:

    data['TotalCharges'] = data[['TotalCharges']].replace([' '], '0') 
    data['TotalCharges'] = pd.to_numeric(data['TotalCharges'])
    

    现在我们有了一个可用的数据格式,我们把它可视化一下:

    from matplotlib import pyplot as plt 
    plt.scatter( data['tenure'], data['MonthlyCharges'], c=data['Churn_Yes']) 
    plt.xlabel('Customer Tenure (Months)') 
    plt.ylabel('Monthly Charges')
    

    很难从这张图中得出任何结论,这个图将客户的tenure(我们正在努力改进的东西)与他们的月费进行了比较。我们继续去训练一个逻辑回归模型,看看我们是否可以使用这些虚拟的特征来预测客户的流失。

    逻辑回归

    from sklearn.linear_model import LogisticRegression 
    from sklearn.model_selection import train_test_split 
    from sklearn.metrics import confusion_matrix, accuracy_score 
    X_train, X_test, y_train, y_test = train_test_split(data[x_select], data['Churn_Yes']) 
    clf = LogisticRegression(solver='lbfgs', max_iter=1000) clf.fit(X_train, y_train)
    

    如果我们训练一个模型,不做任何类间平衡或样本的加权,我们可以达到79.9%的准确率。这对于第一次尝试来说还不错。

    下面是Logistic回归模型的混淆矩阵:

    你在这里看到的是,虽然总体的准确性是相当高的,但是这个模型只识别出流失用户中的55%,这比我们想要的更接近于随机。

    我们的目标是什么?

    在这个过程中,大多数数据科学家(包括我自己)会加倍努力,通过设计新特征、尝试不同的算法、平衡数据集等等来提高模型的准确性。但是最好停下来问问自己你的最终目标是什么。

    了解每一位将要流失的客户固然很好,但这些信息究竟能带来多少真正有用的信息呢?如果你想留住他们,你怎么知道该关注什么?在他们成为你的亏损客户之前,你需要花多少钱才留住他们?

    让我们试着从不同的角度看问题。

    生存分析

    逻辑回归所做的是为每个描述它属于正类的可能性的样本分配一个概率。

    在预测流失vs不流失的这种情况下,对于任何类型的分类,都有一个小烦恼,我们必须选择一个阈值(比如0.5,<0.5就是0, >=0.5 就是1)。然而,如果你仔细想想,其实这个概率才是我们想要的。

    在任何足够大的客户群体中,都会有具有相同属性/特征的人(这就是鸽子洞原理)。有些会流失,有些不会,理想情况下,你想知道的是每个组的流失概率。这就是Logistic回归所给出的结果,但是在这种情况下,使用Logistic回归确实有一个问题 —— 不清楚它预测的时间范围。所以我们现在进入生存分析。

    生存分析是一套用于生命科学(主要是流行病学和药物研究)的方法,用于确定患者随时间的生存概率。这是一个非常大的问题,有许多复杂的统计工具,但我们将只使用其中之一 —— Cox比例风险模型。

    Cox比例风险模型

    Cox PH模型是一种基于回归的模型,它分析数据集关于病人(或客户)生存时间的协变量(特征)。它被称为比例风险模型,因为它描述了每个特征如何在基线存活率上按比例增加风险的。

    由于Python中有一个lifelines包,具有很好的文档,所以很容易使用Cox PH模型。

    使用CoxPH模型

    在大多数情况下,你需要做的第一件事,你需要用数据集准备好Cox回归模型的两个特征:

    1. “age”(病人开始服药和最近一次观察他们的状态之间的时间差异,在我们的例子中,为顾客加入服务的时间和最近一次观察他们是否流失之间的时间差异)

    2. “event”(表示事件是否发生的二进制标志,如死亡或流失)

    幸运的是,telco数据集已经在tenureChurn列中设计了这两个特征。

    在进行任何类型的基于矩阵的回归时,需要注意的一件重要事情是,在Python中,奇异矩阵(行列式不为0,也就是说有两列变量是线性相关的)会抛出一个错误。所有这一切意味着,当你创建虚拟变量(one-hot编码)时,你必须扔掉其中的一列。

    以下是我们的简化数据集的前5行:

    可以看到,Gender_Male已经消失,Partner_No、Dependents_No等等也消失了。

    现在我们有了正确格式的数据集,让我们来拟合Cox模型:

    from lifelines import CoxPHFitter
    
    cph_train, cph_test = train_test_split(data[x_select], test_size=0.2) 
    cph.fit(cph_train, 'tenure', 'Churn_Yes')
    

    lifelines包有一些独特之处,可能会给使用惯了Scikit-Learn的用户带来一些麻烦,首先,包含churn的列需要包含在传递给fit调用的数据集中。因此,我们不能像在逻辑回归中那样将数据集分成四份(对X和y进行训练和测试),我们必须将其分成两份。这与R语法非常相似,你可以在单个数据集中指定相关的列,而算法会负责将它们从训练数据中删除。

    cph.fit调用的时候,你需要传入三个不同的参数。第一个是我们使用train_test_split创建的数据集,第二个是‘age’列(在我们的例子中是tenure),第三个是'event'列(在我们的例子中是Churn_Yes)。

    lifelines包的下一个独特之处是可以在模型上使用的.print_summary方法(另一个从R借鉴的方法)。

    下面是我们的模型summary:

    关于这个输出,有几件重要的事情需要注意。

    1. 我们可以看到在输出的顶部列出了n=5634的样本数量,在其旁边是我们的event数量(流失的客户)。

    2. 我们得到了模型的系数。这些是非常重要的,它们告诉我们每个特征是如何“增加”风险的,因此,如果系数是一个正数,那么该特征使客户更有可能流失,如果是负数,那么拥有该特征的客户就不太可能流失。

    3. 我们可以得到特征的显著性值,一个非常好的补充!

    4. 我们得到了一致性。

    一致性

    与使用准确性来比较逻辑回归模型类似,你可以使用一致性比较不同的Cox PH模型。

    简单地说,一致性是对模型内部一致性的评估 —— 如果它说某个特征增加了风险,那么具有该特征的观测结果应该风险会高。如果它们是这样的,那么一致性会上升,如果不是,那么一致性会下降。

    我们的模型的一致性是0.929,总分是1,所以它是一个很好的Cox模型。

    Cox模型绘图

    在模型上调用基础的.plot可以得到:

    一个方便的特征重要性的可视化和各种特征的风险的影响。在这一点上,我们还可以做的是调查这些特征是如何影响生存的,就像这样:

    cph.plot_covariate_groups('TotalCharges', groups=[0,4000])
    

    .plot_covariate_groupslifelines 中的一个方法,第一个输入是特征的名字,第二个是组的范围。所以,这里我们看的是客户的Total Charges接近0以及Total Charges接近4000的生存曲线的对比,看起来是这样:

    你可以看到,总开销接近于零的客户比总开销接近于4000的客户面临更高的风险(生存曲线下降)。

    流失预测

    我们有一个好的,有效的模型,现在呢?

    这个练习的目的是获得一些有用的信息,帮助我们做出关于如何进行干预以减少和防止客户流失的决策。我们来做一些预测。

    不幸的是,对于已经流失的客户,我们能做的不多,所以让我们从数据集中只选择剩下的客户:

    censored_subjects = data.loc[data['Churn_Yes'] == 0]
    

    我们选择所有那些尚未流失的客户。现在我们用简便的方法来预测它们的生存曲线。

    unconditioned_sf = cph.predict_survival_function(censored_subjects)
    

    你可以看到,我们将这个称为“无条件”生存函数,这是因为我们知道,其中一些曲线会在客户当前的留存期之前预测为客户会流失。我们必须在收集数据时知道客户还在的基础上设定预测条件:

    conditioned_sf = unconditioned_sf.apply(lambda c: (c / c.loc[data.loc[c.name, 'tenure']]).clip_upper(1))
    
    

    现在,我们可以调查个别顾客,看看这个调节如何影响他们的存活率,可以超过基线:

    subject = 12 
    unconditioned_sf[subject].plot(ls="--", color="#A60628", label="unconditioned") 
    conditioned_sf[subject].plot(color="#A60628", label="conditioned on $T>58$") plt.legend()
    
    

    正如你所看到的,我们知道客户12在58个月后仍然是客户,这一事实意味着他的生存曲线下降的速度慢于与他相似的没有这种情况的客户的基线。

    非常方便的predict_survival_function方法创建了一个矩阵,其中包含每个剩余客户在每个时间点的生存概率。接下来我们需要做的是选择一个单一的数字作为预测客户将留存多久,我们可以使用它来确定干预值。

    根据用例,你可以选择任何百分比,但是对于我们的用例,我们将使用中位数。

    from lifelines.utils import median_survival_times, qth_survival_times 
    
    predictions_50 = median_survival_times(conditioned_sf) 
    # This is the same, but you can change the fraction to get other 
    # %tiles.  
    # predictions_50 = qth_survival_times(.50, conditioned_sf)
    
    

    我们在Dataframe中得到一个单个行,其中包含月的数量(留存期),其中客户有50%的可能性会进行交易。

    我们可以使用这一行,通过将它与我们的数据DataFrame相连接,可以调查客户对业务的预期剩余价值:

    values = predictions_50.T.join(data[['MonthlyCharges','tenure']])
    values['RemainingValue'] = values['MonthlyCharges'] * (values[0.5] - values['tenure'])
    
    

    下面是这个新DataFrame的前5行:

    名为0.5的列是我们从median_survival_times调用中接收到的单个行。如果你选择了不同的百分比,则此列的名称将有所不同。

    我们在这里看到的是,通过将每月的费用乘以客户当前的tenure与他们的取消日期中值之间的差值,我们可以了解到哪些客户会对我们的top line造成最大的损害。

    流失预防

    好了,现在我们知道了哪些客户的客户流失风险最高,但我们能做些什么来留住他们呢?如果我们回到之前的系数图我们可以看到对存活率有积极影响的最重要的特征是:

    1. 有2年的合同

    2. 有一年的合同

    3. 用信用卡付款

    4. 银行转帐付款

    超过了这四种,存活率的增加就变得微乎其微,而且结果也不显著。我们来看看这四个。

    我们需要做的是了解我们可以花多少钱来留住客户,是比较他们类似的客户的存活率,而不是他们的这四个特征:

    upgrades = ['PaymentMethod_Credit card (automatic)', 'PaymentMethod_Bank transfer (automatic)', 'Contract_One year', 'Contract_Two year'] 
    
    results_dict = {} 
    
    for customer in values.index: 
        actual = data.loc[[customer]] change = data.loc[[customer]]     
        results_dict[customer] = [cph.predict_median(actual)] 
        for upgrade in upgrades: 
            change[upgrade] = 1 if list(change[upgrade]) == [0] else 0    
            results_dict[customer].append(cph.predict_median(change))      
            change[upgrade] = 1 if list(change[upgrade]) == [0] else 0  
            
    results_df = pd.DataFrame(results_dict).T 
    results_df.columns = ['baseline'] + upgrades 
    actions = values.join(results_df).drop([0.5], axis=1)
    
    

    我们在这里所做的是循环遍历客户,每次更改一个特征,并存储有此更改的客户的预期生存期中值。最后我们剩下的是:

    我们可以看到,如果我们设法让第一个客户使用信用卡支付,我们可以增加4个月的生存时间(25-21基线),等等。

    这是一个非常好的结果,它确实帮助我们看到我们如何才能在留住客户方面取得进展,但让我们更进一步,看看这在财务上有什么影响:

    actions['CreditCard Diff'] = ( 
        actions['PaymentMethod_Credit card (automatic)'] -     
        actions['baseline']
    ) * actions['MonthlyCharges'] 
    
    actions['BankTransfer Diff'] = ( 
        actions['PaymentMethod_Bank transfer (automatic)'] - 
        actions['baseline']
    ) * actions['MonthlyCharges'] 
    
    actions['1yrContract Diff'] = ( 
        actions['Contract_One year'] - actions['baseline']
    ) * actions['MonthlyCharges'] 
    
    actions['2yrContract Diff'] = ( 
        actions['Contract_Two year'] - actions['baseline']
    ) * actions['MonthlyCharges']
    
    

    现在我们可以看到,将第一排的顾客转移到使用信用卡支付,价值可能高达119.40英镑。这比简单地数月的数量有用多了。

    准确率以及校准

    好了,快好了。我们有了货币价值,我们可以用它来判断特定的客户流失干预是否可行,以及关于“何时”客户会流失的可靠预测。但所有这些到底有多准确呢?

    我们知道我们的Cox模型是一个很好的模型(92.9%的一致性),但这在实际中意味着什么呢?它有多精确?

    当你从概率的角度看待像流失(或欺诈或盗窃)这样的事件时,检查校准性比检查准确性更重要。校准性是模型获得概率随时间变化的倾向。

    就像这样,一个天气预报服务是经过校准的话,如果在所有的时间里它说有40%的可能性下雨,实际上就有40%的可能性下雨。

    在Scikit-Learn中,我们可以使用calibration_curve方法从概率预测和数据集的真实值中获得这个值:

    from sklearn.calibration import calibration_curve 
    
    plt.figure(figsize=(10, 10))
     
    ax1 = plt.subplot2grid((3, 1), (0, 0), rowspan=2) 
    ax1.plot([0, 1], [0, 1], "k:", label="Perfectly calibrated")
    
    probs = 1-np.array(cph.predict_survival_function(cph_test).loc[13])
    
    actual = cph_test['Churn_Yes'] 
    
    fraction_of_positives, mean_predicted_value = \ 
    calibration_curve(actual, probs, n_bins=10, normalize=False) 
    
    ax1.plot(mean_predicted_value, fraction_of_positives, "s-", label="%s" % ("CoxPH",)) 
    
    ax1.set_ylabel("Fraction of positives") 
    ax1.set_ylim([-0.05, 1.05]) ax1.legend(loc="lower right") 
    ax1.set_title('Calibration plots (reliability curve)')
    
    

    可以得到这个:

    通过检查数据集(在我们的例子中是测试集)中出现的分数的各种概率,你可以看下这个图表。

    你可以看到它非常接近对角线,代表完美的校准。然而,我们的模型似乎在低端低估了风险(<50%的流失率)和在高端轻微高估了风险(>50%的客户流失率)。

    为了从数字上了解距离完美校准有多远,我们可以使用Scikit-Learn包中的brier_score_loss

    brier_score_loss( 
        cph_test['Churn_Yes'], 1 - 
        np.array(cph.predict_survival_function(cph_test).loc[13]), pos_label=1 
    )
    
    

    敏锐的读者可能已经注意到,我的索引保持在tenure= 13。由于我们的模型在一定的时间范围内工作,我们必须在每一步都检查校准性,以获得准确的校准性:

    loss_dict = {} 
    for i in range(1,73): 
        score = brier_score_loss( 
            cph_test['Churn_Yes'], 1 -    
            np.array(cph.predict_survival_function(cph_test).loc[i]),   
            pos_label=1 ) 
        loss_dict[i] = [score] 
        
    loss_df = pd.DataFrame(loss_dict).T 
    
    fig, ax = plt.subplots() 
    ax.plot(loss_df.index, loss_df) 
    ax.set(xlabel='Prediction Time', ylabel='Calibration Loss', title='Cox PH Model Calibration Loss / Time') 
    ax.grid() 
    
    plt.show()
    
    

    我们得到这个:

    所以我们可以看到,我们的模型在5到25个月之间校准得很好,然后越来越差。为了使我们的分析更真实,剩下要做的唯一事情就是解释这种糟糕的校准性。

    让我们为让客户做出改变所带来的预期投资回报创建一个上界和下界:

    loss_df.columns = ['loss'] 
    temp_df = actions.reset_index().set_index('PaymentMethod_Credit card (automatic)').join(loss_df) 
    temp_df = temp_df.set_index('index') 
    actions['CreditCard Lower'] = temp_df['CreditCard Diff'] - (temp_df['loss'] * temp_df['CreditCard Diff']) 
    actions['CreditCard Upper'] = temp_df['CreditCard Diff'] + (temp_df['loss'] * temp_df['CreditCard Diff']) 
    temp_df = actions.reset_index().set_index('PaymentMethod_Bank transfer (automatic)').join(loss_df) 
    temp_df = temp_df.set_index('index') 
    actions['BankTransfer Lower'] = temp_df['BankTransfer Diff'] - (.5 * temp_df['loss'] * temp_df['BankTransfer Diff']) actions['BankTransfer Upper'] = temp_df['BankTransfer Diff'] + (.5 * temp_df['loss'] * temp_df['BankTransfer Diff']) 
    
    temp_df = actions.reset_index().set_index('Contract_One year').join(loss_df) 
    temp_df = temp_df.set_index('index') 
    actions['1yrContract Lower'] = temp_df['1yrContract Diff'] - (.5 * temp_df['loss'] * temp_df['1yrContract Diff']) actions['1yrContract Upper'] = temp_df['1yrContract Diff'] + (.5 * temp_df['loss'] * temp_df['1yrContract Diff']) 
    
    temp_df = actions.reset_index().set_index('Contract_Two year').join(loss_df) 
    temp_df = temp_df.set_index('index') 
    actions['2yrContract Lower'] = temp_df['2yrContract Diff'] - (.5 * temp_df['loss'] * temp_df['2yrContract Diff']) actions['2yrContract Upper'] = temp_df['2yrContract Diff'] + (.5 * temp_df['loss'] * temp_df['2yrContract Diff'])
    
    

    这里我们对之前的值打了个折来考虑校准的不确定性。我们查看模型在每个时间段的校准情况,我们预测会有一个特定的提升,并产生和创建一个投资回报的上下界。

    这就得到了这样的结果:

    至此,我们结束了生存分析、一致性和校准性之旅。我们的努力所得到的是一组可操作的数据,我们可以使用这些数据使客户注册时间更长——这就是客户流失预测的要点!

    —END—

    英文原文:https://towardsdatascience.com/churn-prediction-and-prevention-in-python-2d454e5fd9a5?gi=df0e635db665

    请长按或扫描二维码关注本公众号

    喜欢的话,请给我个好看吧

    展开全文
  • Python 银行信用卡客户流失预测(kaggle)

    千次阅读 多人点赞 2020-12-08 08:08:00
    1.背景越来越多的客户不再使用信用卡服务,银行的经理对此感到不安。如果有人能为他们预测哪些客户即将流失,他们将不胜感激,因为这样他们可以主动向客户提供更好的服务,并挽回这些即将流失客户...
  • 【摘 要】  为减少用户流失,提高用户保有率,文章介绍一种基于智慧运营平台,将大数据技术和数据挖掘技术相结合,对电信客户流失进行预测的模型。该模型利用大数据技术处理用户离网前的海量数据信息,分析流失...
  • 基于数据挖掘的电商客户流失预测建模方法研究.pdf
  • 通过分析银行客户流失的原因,提出了建立客户流失预测模型的方法。利用模型,发现预测流失 群体,预测流失趋势,进而制定有效的控制策略,最大限度地降低客户流失率。为客户流失预测提供了一种新的研究思路和分析...
  • Customer_Churn_PySpark 根据客户使用的电信服务预测客户流失
  • 本文采用来自kaggle平台的电信客户数据集,来分析人们对电信服务的使用情况,以及帮助电信运营商找出客户流失的原因,并建立流失预测模型,从而降低客户流失率。数据集链接如下:...
  • 客户生存与流失预测 客户流失率是评估不断增长的业务的最重要指标之一。 虽然这不是最幸福的衡量标准,但它可以使您的公司了解保留客户的事实。 Heroku应用程序My Heroku应用程序: : 生存分析 生存分析是统计的一...
  • 应用反向传播神经网络预测电信行业的客户流失和非流失率%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% SOM_COUNTER_PROP_DEMO-传播神经网络演示剧本%%Igor Kuzmanovski(*)和...
  • 如何利用CRM系统软件防止客户流失?客户对于每个企业来说都是关键,所以客户管理和维护也是企业生存发展的基础,如果企业失去库就会影响到企业的生存发展。那么如何利用CRM系统软件防止客户流失,提升企业的销售业绩...
  • 企业在客户销售数据的保存、处理、分析的基础上,可以利用客户关系管理系统进行客户关系维系及客户流失预警与管理工作。 客户关系管理系统(CRM系统)最大的优势之一就是收集和分析客户数据,突出原来和现有的客户...
  • 电信用户流失分析与预测

    千次阅读 2020-08-05 16:16:20
    电信用户流失分析与预测一. 研究背景二. 分析结论与建议三. 任务与实现四. 数据集解析五. 数据分析套餐1.准备工作导入相关的库导入数据集2.数据预处理类型转换缺失值处理重复值处理3.查看流失情况4.类别特征的描述性...
  • 本文讨论了 2019 年第二季度电信行业的客户流失分析。 机器学习是数据挖掘的高级发展,用于从大量数据中提取特征。 论文讨论了监督机器学习模型。 通过支持向量机(SVM)分类步骤设计的监督模型,用于将流失客户和...
  • 贷中策略除了跟调额、营销相关外,与客户流失相关及营销相关的还有一个客户流失预测模型,是我们全流程中必不可少的一个客群分析。 目前,银行都面临着极大的优质客户流失的危险。这将对银行经营和效益产生极大的...
  • 电信客户流失数据分析

    千次阅读 2020-08-21 14:24:32
    这里写自定义目录标题电信客户流失数据分析研究背景提出问题数据集描述特征工程1、数据预处理1.1、特征类型处理1.2、缺失值处理1.3、异常值处理1.4、分类变量标签整理2、特征选择2.1、方差过滤2.2、卡方检验过滤2.3...
  • 客户挽留:信用卡客户流失管理

    千次阅读 2019-08-04 16:11:45
    业务目标:预测客户流失的概率和挽留的价值--> 数据准备:数据决定结果--> 流失预警:哪些客户即将流失--> 客户价值:哪些客户更值得挽留--> 分客群挽留策略:收益和成本的平衡-->业务目标 二...
  • 这涉及使用数据分析系统,该系统使用实时集成和动态实时响应数据来检测流失风险。 订阅者越来越多地通过移动号码携带 (MNP) 终止与电信公司的会员协议,以便订阅另一家竞争对手的公司。 为了对客户预测建模,将使用...
  • smote的matlab代码电信客户流失分析 客户流失是指客户(玩家、订阅者、用户等)停止与公司的关系。 自从客户上次与网站或服务交互以来,企业通常会将客户视为流失客户。 客户流失的全部成本包括收入损失和用新客户...
  • 现在银行产品同众化现象普遍存在,客户选择产品和服务的途径越来越多,客户对产品的忠诚度越来越低,所以客户流失已经成为银行业最关注的问题之一。而获得新客的成本远高于维护老客户成本。因此,从海量客户交易数据...
  • 银行业客户群体 1.银行的个人客户 银行对个人客户的主要业务是:为个人客户合理安排个人财务,具体有 (1)存款,取款 (2)小额贷款 (3)代理投资理财 (4)信息咨询 (5)其他各类中介服务 目的:为客户取得收益...
  • 这种模式包括: · 决策树分类器 · KNeighbors分类器 · 逻辑回归 · 随机森林分类器 · 投票分类器 控件在历史数据上运行的结果表明流失预测的准确率高达97%。我们计划用额外的人工数据来丰富模型,并用它来...
  • 在激烈竞争的市场,企业一旦发生客户流失,特别是大客户的流失,企业业绩会受到严重影响。客户流失后再进行挽救工作,企业不仅要消耗大量的资源,而且挽救结果也是未知的。所以,在客户关系维系方面,客户流失预警与...
  • 感知机模型二、神经网络在流失预警模型中的应用1.数据预处理2.参数设置3.代码部分 一、神经网络模型概述   人工神经网络(ANN),它的基本特点是试图模仿大脑的神经元之间传递、处理信息的模式。其具有以下两个...
  • 客户流失预测【Churn prediction】的研究有利于提前做出挽留动作,降低客户流失对利润增长造成的负面影响。客户流失预测在电芯、银行、保险等行业备受关注。 预测过程是基于数据驱动,通常是利用机器学习技术。在这...
  • 这种网络依靠系统的复杂程度,通过调整内部大量节点之间相互连接的关系,从而达到处理信息的目的。 简单理解就是它试图模仿人类大脑信息在神经元上的传递,以及信息处理的方式。 一个计算模型要被称为神经网络,需要...
  • 客户流失Big Data Analytics within a real-life example of digital music service 数字音乐服务真实示例中的大数据分析 Customer churn is a key predictor of the long term success or failure of a business. ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,948
精华内容 2,379
关键字:

客户流失预测系统