当前位置:   article > 正文

银行流失用户分析及预测模型_银行客户流失

银行客户流失

自学的一个银行流失客户预警的小项目

0.引言-银行流失用户分析

银行客户流失是指银行的客户终止在该行的所有业务,并销号。但在实际运营中,对于具体业务部门,银行客户流失可以定位为特定的业务终止行为。

商业银行的客户流失较为严重,流失率可达20%。而获得新客的成本是维护老客户的5倍。因此,从海量客户交易数据中挖掘出对流失有影响的信息,建立高效的客户流失预警体系尤为重要。

客户流失的主要原因有:价格流失、产品流失、服务流失、市场流失、促销流失、技术流失、政治流失。有些时候表面上是价格导致的客户流失,但实际上多重因素共同作用导致了客户的流失。比如说,不现实的利润目标、价格结构的不合理、业务流程过于复杂、组织结构的不合理等等。

维护客户关系的基本方法:追踪制度,产品跟进,扩大销售,维护访问,机制维护。

因此建立量化模型,合理预测客群的流失风险是很有必要的。比如:常用的风险因子,客户持有的产品数量、种类,客户的年龄、性别,地理区域的影响,产品类别的影响,交易的时间间隔,促销的手段等等。根据这些因素及客户流失的历史数据对现有客户进行流失预测,针对不同的客群提供不同的维护手段,从而降低客户的流失率。

1. 数据初探索

1.1银行客户数据变量含义统计:

从业务水平上判定用户是否为流失客户

CUST_ID

用户ID

OPEN_ACC_DUR

开户时长

AGE

年龄

GENDER_CD

性别

HASNT_HOME_ADDRESS_INF

家庭住址

HASNT_MOBILE_TEL_NUM_INF

电话信息

LOCAL_CUR_SAV_SLOPE

本币活期储蓄波动率

LOCAL_CUR_MON_AVG_BAL

本币活期月均余额

LOCAL_CUR_MON_AVG_BAL_PROP

本币活期月均月占比

LOCAL_CUR_ACCT(account)_NUM

本币活期帐户数

LOCAL_OVEONEYR_FF_MON_AVG_BAL

本币一年以上整整季日均余额

LOCAL_FIX_MON_AVG_BAL

本币定期月均余额

LOCAL_FIX_MON_AVG_BAL_PROP

本币定期月均余额比例

LOCAL_BELONEYR_FF_SLOPE

本币一年以下整整波动率

LOCAL_BELONEYR_FF_MON_AVG_BAL

本币一年以下整整季日均余额

LOCAL_OVEONEYR_FF_SLOPE

本币一年以上整整波动率

LOCAL_SAV_SLOPE

本币存款波动率

LOCAL_SAV_CUR_ALL_BAL

本币活期存款总余额

LOCAL_SAV_MON_AVG_BAL

本币存款月均余额

SAV_SLOPE

存款波动率

SAV_CUR_ALL_BAL

活期存款总余额

SAV_MON_AVG_BAL

存款月均余额

FR_SAV_CUR_ALL_BAL

 

ASSET_CUR_ALL_BAL

活期资产总余额

ASSET_MON_AVG_BAL

资产月均余额

LOCAL_CUR_TRANS_TX_AMT

本币活期转账交易笔数

LOCAL_CUR_TRANS_TX_NUM

本币活期转账交易总数

LOCAL_CUR_LASTSAV_TX_AMT

本币活期续存交易金额

LOCAL_CUR_LASTSAV_TX_NUM

本币活期续存交易笔数

LOCAL_CUR_WITHDRAW_TX_AMT

本币活期存款金额

LOCAL_CUR_WITHDRAW_TX_NUM

本币活期存款笔数

LOCAL_FIX_OPEN_ACC_TX_NUM        

本币定期开户交易笔数

LOCAL_FIX_OPEN_ACC_TX_AMT

本币定期开户交易金额

LOCAL_FIX_WITHDRAW_TX_NUM      

本币定期存款交易笔数

LOCAL_FIX_WITHDRAW_TX_AMT       

本币定期存款交易金额

LOCAL_FIX_CLOSE_ACC_TX_NUM     

本币定期销户笔数

LOCAL_FIX_CLOSE_ACC_TX_AMT      

本币定期销户总金额

L6M_INDFINA_ALL_TX_NUM

最近六个月个人理财总交易数目

L6M_INDFINA_ALL_TX_AMT

最近六个月个人理财总交易金额

POS_CONSUME_TX_AMT

客户POS财务类交易总金额

POS_CONSUME_TX_NUM

客户POS交易总数目

ATM_ACCT_TX_NUM

ATM交易总数目

ATM_ACCT_TX_AMT

AMT交易总金额

ATM_NOT_ACCT_TX_NUM     

ATM非财务类交易数目

ATM_ALL_TX_NUM  

ATM总交易数目

COUNTER_NOT_ACCT_TX_NUM  

柜面非财务交易数目

COUNTER_ACCT_TX_AMT     

柜面财务交易总金额

COUNTER_ACCT_TX_NUM     

柜面财务交易总数目

COUNTER_ALL_TX_NUM

柜面总交易数目

NAT_DEBT_OPEN_ACC_DUR 

国债开户时长

FINA_OPEN_ACC_DUR     

委托理财开户时长

FUND_OPEN_ACC_DUR   

代理基金开户时长

TELEBANK_ALL_TX_NUM     

手机银行交易总数

CHURN_CUST_IND

流失客户

1.2数据统计性初探

1.2.1单因子分析

  1. #导包(基于python3):
  2. import pandas as pd
  3. import numbers
  4. import numpy as np
  5. import matplotlib.pyplot as plt
  6. import random
  7. from statsmodels.formula.api import ols
  8. from statsmodels.stats.anova import anova_lm#方差分析应用
  9. from scipy.stats import chisquare
  10. #读取数据:
  11. bankChurn = pd.read_csv(r'/path/bankChurn.csv', header = 0)
  12. externalData = pd.read_csv(r'/path/ExternalData.csv',header = 0)
  13. #基于CUST_ID变量字段,连接两个表
  14. AllData = pd.merge(bankChurn, externalData, on ='CUST_ID')
  15. #构建数值型统计探索函数,其主要功能为作图描述各个变量的分布特性,确定离群值,函数输入参数如下:
  16. def NumVarTracker(df, col, Target, filepath,):
  17. ‘‘‘
  18. :param df: the dataset containing numerical independent variable and dependent variable样本集
  19. :param col: independent variable with numerical type变量
  20. :param target: dependent variable, class of 0-1目标
  21. :param filepath: the location where we save the histogram图片存储路径
  22. :param truncation: indication whether we need to do some truncation for outliers判断是否需要剔除离群值
  23. :return: the descriptive statistics
  24. ’’’
  25. #数据初步筛除空值(空值具有自己不与自己相等的属性)
  26. # extract target variable and specific indepedent variable
  27. validDf = df.loc[df[col] == df[col]][[col,target]]
  28. #统计非空值占比:
  29. validRcd = validDf.shape[0]*1.0/df.shape[0]
  30. validRcdFmt = "%.2f%%"%(validRcd*100)
  31. #数值型数据统计性描述:
  32. descStats = validDf[col].describe()
  33. mu = "%.2e" % descStats['mean']
  34. std = "%.2e" % descStats['std']
  35. maxVal = "%.2e" % descStats['max']
  36. minVal = "%.2e" % descStats['min']
  37. #各变量用户流失分布情况:
  38. x = validDf.loc[validDf[target]==1][col]
  39. y = validDf.loc[validDf[target]==0][col]
  40. xweights = 100.0 * np.ones_like(x) / x.size
  41. yweights = 100.0 * np.ones_like(y) / y.size
  42. #判断是否需要剔除离群值(离群值基于0.95分位点进行剔除):
  43. if truncation == True:
  44. pcnt95 = np.percentile(validDf[col],95)
  45. x = x.map(lambda x: min(x,pcnt95))
  46. y = y.map(lambda x: min(x,pcnt95))
  47. #数据可视化探索数据:
  48. fig, ax = plt.subplots()
  49. ax.hist(x, weights=xweights, alpha=0.5,label='Attrition')#直方图
  50. ax.hist(y, weights=yweights, alpha=0.5,label='Retained')#直方图
  51. titleText = 'Histogram of '+ col +'\n'+'valid
  52. pcnt ='+validRcdFmt+', Mean ='+mu+ ', Std='+std+'\n max='+maxVal+', min='+minVal
  53. #变量指标
  54. ax.set(title = titleText, ylabel = '% of Dataset in Bin')
  55. ax.margins(0.05)
  56. ax.set_ylim(bottom=0)
  57. plt.legend(loc='upper right')
  58. figSavePath = filepath+str(col)+'.png'
  59. plt.savefig(figSavePath)
  60. plt.close(1)#画图后图片不打开

 

可视化初步探索:

可视化图表判断某变量下,流失客户与非流失客户的分布情况,以ASSET_MON_AVG_BAL资产月均余额为例,该变量为行尾变量:

图1. 客户ASSET_MON_AVG_BAL变量下客户流失情况分布

可以看出,资产水平较低的客户流失率明显高于高资产水平客户的流失率。同时在图表上方可以看到该特征数据样本的缺失率,均值与标准差。

图2. 客户Age变量下客户流失情况分布

由图2,可以看出,低年龄客户的用户流失率更高。

这种分布类型的特征样本其方差过大,使得数据学习容易发生过拟合:

图3.本币活期转账交易金额变量下的客户流失情况分析

2)字符型变量数据

  1. #数据与变量输入:
  2. def CharVarPerf(df,col,target,filepath):
  3. '''
  4. :param df: the dataset containing numerical independent variable and dependent variable
  5. :param col: independent variable with numerical type
  6. :param target: dependent variable, class of 0-1
  7. :param filepath: the location where we save the histogram
  8. :return: the descriptive statistics
  9. '''
  10. #初步筛除空值:
  11. validDf = df.loc[df[col] == df[col]][[col, target]]
  12. validRcd = validDf.shape[0]*1.0/df.shape[0]
  13. recdNum = validDf.shape[0]
  14. validRcdFmt = "%.2f%%"%(validRcd*100)
  15. #统计类别变量的各个值的分布:
  16. freqDict = {}
  17. churnRateDict = {}
  18. #for each category in the categorical variable, we count the percentage and churn rate(每个值的比例与对应的流失比例)
  19. for v in set(validDf[col]):
  20. #统计不同值的个数/collections的Counter函数可计算变量与变量的个数
  21. vDf = validDf.loc[validDf[col] == v]
  22. freqDict[v] = vDf.shape[0]*1.0/recdNum #Dataframe
  23. churnRateDict[v] = sum(vDf[target])*1.0/vDf.shape[0]
  24. descStats=pd.DataFrame({'percent':freqDict,'churnrate':churn RateDict})
  25. fig = plt.figure() # Create matplotlib figure
  26. ax = fig.add_subplot(111) # Create matplotlib axes子图
  27. ax2 = ax.twinx() # Create another axes that shares the same x-axis as ax.
  28. plt.title('The percentage and churn rate for '+col+'\n valid pcnt ='+validRcdFmt)
  29. descStats['churn rate'].plot(kind='line', color='red', ax=ax)
  30. descStats.percent.plot(kind='bar', color='blue', ax=ax2, width=0.2,position = 1)
  31. ax.set_ylabel('churn rate')
  32. ax2.set_ylabel('percentage')
  33. figSavePath = filepath+str(col)+'.png'
  34. plt.savefig(figSavePath)
  35. plt.close(1)

数据可视化结果讨论(举几个变量的例子):

图5 客户买车比例与流失比例

对于新买车的用户的流失比例较低,而大多数的客户未向银行透露自己是否买车,而这部分客户流失比例较高。

图6 性别与流失客户比例的关系

对于性别变量来说,男性客户2的用户流失比例小于男性客户1,而未知性别的客户对银行的信任度较低,其流失率也较高。

2.方差检验

利用方差检验方法,来探究类别变量对于结果是否有较为显著的影响。

        例如:检验ASSET_MON_AVG_BAL与CHURN_CUST_IND之间的差异性

anova_results=anova_lm(ols('ASSET_MON_AVG_BAL~CHURN_CUST_IND',AllData).fit())

print(anova_results)

PR值越小(越接近于0),两组样本之间的差异性越小

 

1.2.2 多因子分析

随机抽取8个变量探究变量两两间的关系

图4.随机抽取8个变量,探究两两之间关系

由图4可以看出,该图体现了两两变量之间的关系,及两个变量对预测结果的影响情况。本项目变量较多,且变量之间的关系较为复杂,有些变量对预测结果的可解释性影响较大。具体的特征工程还需要进一步的研究与讨论。如果两指标之间有较强的正相关或负相关的关系,则适当的删除冗余特征。

2. 数据预处理及指标去重

2.1数据预处理

        对于某些算法,例如lightgbm、xgboost算法,可以将数据空值作为类别或值进行预测,但有些算法无法根据空值进行训练,因此还需要进一步处理,对于缺失比例不大的数据可以应用均值或中值进行填充,如果数据缺失比例较大,应用回归填充或将空值作为一个统一的数值(结合具体的业务)进行填充。类别型变量预处理,则可根据最频繁模式与随机模型进行填补。其中较为特别的是将日期转化为开户持续时长duration:

import time

import datetime

#基准值获取,base为参考基准值

base2 = time.strptime(base,'%Y/%m/%d')

base3 = datetime.datetime(base2[0],base2[1],base2[2])

base4 = time.strptime(str(dateORI),'%m/%d/%Y')#日期字段匹配

date2 = datetime.datetime(base4[0],base4[1],base4[2])

daysGap = (date2-base3).days#得当前日期值与初始值之间的差值

 

2.2指标去重

1.指标合并

        将本币活期类与定期类指标相加,可以得到总指标(比如将本币活期余额与本币定期余额相加,得到的本币总余额):

modelData['TOTAL_LOCAL_MON_AVG_BAL'] = modelData['LOCAL_CUR_MON_AVG_BAL','LOCAL_FIX_MON_AVG_BAL'].apply(sum, axis = 1)

       

2.比例计算

        由月均余额各类指标与年度指标相除,得到各个比例指标(Ratio)

3. 模型与参数调节

选择用GBDT进行预测,将所有特征样本输入训练模型会造成非常严重的过拟合,因此需要进行特征选择,

 

3.1特征选择(和降维的区别是什么???)

1.方差过滤法

        首先查看所有特征样本的方差:

        由于我想保留OPEN_ACC_DUR字段,因此设置方差过滤阈值为(阈值设定方法较为主观,可以基于具体的统计特征筛选方差/有些金额分布过于悬殊的值,可以设定阈值将其划分为几个等级):100

       

  1. from sklearn.feature_selection import VarianceThreshold
  2. varianceThreshold = VarianceThreshold(threshold = 100)
  3. varianceThreshold.fit_transform(modelData[allFeatures])
  4. NumV=varianceThreshold.get_support()#大于阈值threshold的特征位置为True,否则为False
  5. SeleFeatures = []#基于方差筛选特征
  6. for i in range(len(NumV)):
  7. if NumV[i] == False:
  8. SeleFeatures.append(allFeatures[i])

2.相关系数法(皮尔逊)

        先计算各个特征对目标值的相关系数,选择更加相关的特征。

  1. selectKBest = SelectKBest(f_regression,k=15)#找出与客户流失水平相关系数最大的15个特征找出来
  2. selectKBest.fit_transform(modelData[SeleFeatures],modelData['CHURN_CUST_IND'])#在前十五范围内为True,不在为False
  3. NumV2 = selectKBest.get_support()
  4. print(NumV2)
  5. SeleFeatures2 = []
  6. for i in range(len(NumV2)):
  7. if NumV2[i] == True:
  8. SeleFeatures2.append(SeleFeatures[i])
  9. print(len(SeleFeatures2))
  10. print(SeleFeatures2)

 

3.卡方检验

检验变量对结果影响的显著性与否

检验性别是否对客户流失具有显著影响。

探究所筛选出的15个变量是否对客户流失具有显著影响

卡方检验值越大,拒绝假设的可能性越大

 

3.2模型选择

        GBDT的介绍:梯度提升决策树

        采用逻辑回归决策树CART Tree进行分类,应用梯度提升方法求解模型参数。

  1. 逻辑回归

假设有一个二分类问题,输出为y∈{0,1},而线性回归模型产生的预测值为z=wTx+bz=wTx+b是实数值,我们希望有一个理想的阶跃函数来帮我们实现z值到0/1值的转化:

然而该函数不连续,我们希望有一个单调可微的函数来供我们使用,于是便找到了Sigmoid function来替代。

 

 

有了Sigmoid fuction之后,由于其取值在[0,1],我们就可以将其视为类11的后验概率估计p(y=1|x)。说白了,就是如果有了一个测试点x,那么就可以用Sigmoid fuctionSigmoid fuction算出来的结果来当做该点x属于类别1的概率大小。于是,非常自然地,我们把Sigmoid fuction计算得到的值大于等于0.5的归为类别1,小于0.5的归为类别0。

2)梯度下降法

为确定逻辑回归中z的各参数,需要确定损失函数,使得损失函数最小的各w值。

        损失函数定义(由误差平方和结合最大似然估计法求得)为:(损失函数的选取各不相同)

        而利用梯度下降法,不断迭代求得最低点的wT,此时的wT即为使得损失函数最小的权重值。

        将样本输入即可得出判断目标结果所属的分类结果。

3.3参数调节

n_estimators:分类树的个数

learning rate:每个弱分类器的权重缩减系数v,也称之为步长。

Subsample:(不放回)抽样率,推荐在[0.5,0.8]之间,默认为1.0

init:即初始化的弱学习器,多用于对数据有先验知识,且在之前做过一定的拟合的时候

loss:算法的损失函数

max_features:划分时考虑的最大特征数

max_depth:决策树最大深度

min_samples_split:内部节点再划分所需的最小样本数,默认为2,样本量如果较大,则可以扩大该数。

min_simples_leaf: 叶子节点最少样本数

min_weight_fraction_leaf:叶子节点最小的样本权重

max_leaf_nodes:最大叶子节点数,通过限制最大叶子节点数,可以防止过拟合

min_impurity_split:节点划分最小不纯度

 

  1. X_train,X_test,y_train,y_test = train_test_split(modelData[allFeatures2],modelData['CHURN_CUST_IND'],test_size = 0.3,random_state=9)
  2. gbm0 = GradientBoostingClassifier(max_depth=1,random_state = 1)
  3. gbm0.fit(X_train,y_train)
  4. y_pred = gbm0.predict(X_test)
  5. y_predprob = gbm0.predict_proba(X_test)[:,1]
  6. #参数调节过程:
  7. ### tunning max_features
  8. param_test4 = {'max_features':range(5,31,2)}
  9. gsearch4 = GridSearchCV(estimator = GradientBoostingClassifier(learning_rate=0.1, n_estimators=70,max_depth=9, min_samples_leaf =70,min_samples_split =500, subsample=0.8, random_state=10), param_grid = param_test4, scoring='roc_auc',iid=False, cv=5)
  10. gsearch4.fit(X_train,y_train)
  11. gsearch4.grid_scores_, gsearch4.best_params_, gsearch4.best_score_
  12. ## tunning subsample
  13. param_test5 = {'subsample':[0.6,0.7,0.75,0.8,0.85,0.9]}
  14. gsearch5 = GridSearchCV(estimator = GradientBoostingClassifier(learning_rate=0.1, n_estimators=70,max_depth=9, min_samples_leaf =70, min_samples_split =500, max_features=28, random_state=10), param_grid = param_test5, scoring='roc_auc',iid=False, cv=5)
  15. gsearch5.fit(X_train,y_train)
  16. gsearch5.grid_scores_, gsearch5.best_params_, gsearch5.best_score_
  17. # tunning the learning rate
  18. gbm2 = GridSearchCV(estimator = GradientBoostingClassifier(learning_rate=0.05, n_estimators=70,max_depth=9, min_samples_leaf =70, min_samples_split =1000, max_features=28, random_state=10,subsample=0.8), param_grid = param_test5, scoring='roc_auc',iid=False, cv=5)
  19. gbm2.fit(X_train,y_train)

 

针对具体的业务问题,关键在于迭代更新方案(不断优化泛化性能),发现数据的新的特性,最终设计出合适于具体业务的模型。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/天景科技苑/article/detail/746501
推荐阅读
相关标签
  

闽ICP备14008679号