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

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单因子分析

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

可视化初步探索:

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

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

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

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

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

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

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

2)字符型变量数据

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

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

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

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

selectKBest = SelectKBest(f_regression,k=15)#找出与客户流失水平相关系数最大的15个特征找出来
selectKBest.fit_transform(modelData[SeleFeatures],modelData['CHURN_CUST_IND'])#在前十五范围内为True,不在为False
NumV2 = selectKBest.get_support()
print(NumV2)
SeleFeatures2 = []
for i in range(len(NumV2)):if NumV2[i] == True:SeleFeatures2.append(SeleFeatures[i])
print(len(SeleFeatures2))
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:节点划分最小不纯度

X_train,X_test,y_train,y_test = train_test_split(modelData[allFeatures2],modelData['CHURN_CUST_IND'],test_size = 0.3,random_state=9)
gbm0 = GradientBoostingClassifier(max_depth=1,random_state = 1)
gbm0.fit(X_train,y_train)
y_pred = gbm0.predict(X_test)
y_predprob = gbm0.predict_proba(X_test)[:,1]#参数调节过程:
### tunning max_features
param_test4 = {'max_features':range(5,31,2)}
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)
gsearch4.fit(X_train,y_train)
gsearch4.grid_scores_, gsearch4.best_params_, gsearch4.best_score_## tunning subsample
param_test5 = {'subsample':[0.6,0.7,0.75,0.8,0.85,0.9]}
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)
gsearch5.fit(X_train,y_train)
gsearch5.grid_scores_, gsearch5.best_params_, gsearch5.best_score_# tunning the learning rate
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)
gbm2.fit(X_train,y_train)

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

银行流失用户分析及预测模型相关推荐

  1. 流失用户分析(Ⅰ)_流失用户定义

    流失用户通俗的讲就是:用户多少天没来用产品后,就算流失了,这里需要分析同学根据业务的实际情况对流失用户进行定义,目前常用的定义流失用户的方式主要有:拐点法和分位数法.本文主要对上述两法进行阐述,不足之 ...

  2. 游戏数据分析 | 用户流失原因分析

    流失用户分析的方法有很多,常见的方法有流失等级分布. 等级停滞率.分渠道和平台的留存率对比.主线任务持有率.本文将从合理定义流失用户.客户端卸载原因和5W1H分析法来分析流失用户,并且用聚类分析对活跃 ...

  3. 音乐平台Sparkify流失用户预测

    Sparkify 流失用户分析 Sparkify是一个国外的音乐平台,本文将介绍预测Sparkify流失用户的过程.我们使用的数据是Sparkify的用户使用log,其中包含用户听的歌曲,时长,艺术家 ...

  4. 网站的活跃用户与流失用户

    网站用户管理的目标是发掘新用户,保留老用户.但仅仅吸引新用户还不错,还需要保持新用户的活跃度,使其能持久地为网站创造价值:而一旦用户的活跃度下降,很可能用户就会渐渐地远离网站,进而流失.所以基于此,我 ...

  5. 利用逻辑回归进行用户流失预测分析

    1.项目背景 客户流失是所有与消费者挂钩行业都会关注的点.因为发展一个新客户是需要一定成本的,一旦客户流失,除了浪费拉新成本,还需要花费更多的用户召回成本. 所以,电信行业在竞争日益激烈当下,如何挽留 ...

  6. Python数据分析高薪实战第十二天 网络服务用户流失预测分析和国产电视剧评分预测分析

    29 综合实战:网络服务用户流失预测与分析 绝大多数互联网公司都面临一个非常重要的问题:用户流失问题.随着互联网和移动互联网的充分发展,发展新用户(也就是一般所说的拉新)的成本越来越高,往往要几块或者 ...

  7. 基于用户乘车行为大数据的客流分析及预测模型

    资源下载地址:https://download.csdn.net/download/sheziqiong/73094563 资源下载地址:https://download.csdn.net/downl ...

  8. 详解用户流失原因分析该如何入手?

    来源:CPDA数据说 转自:CPDA数据说 大家好,我是小z 关于用户流失分析,总有几个问题是绕不过去的: 用户流失原因调研时不知如何入手? 不知如何才能找到用户真正的流失原因? 不知如何把调研结果应 ...

  9. 客户流失预测模型python_教你用Python快速上手构建客户流失模型分析

    为什么做客户流失模型分析? 1.企业再发展新用户成本很高 2.客户的流失会给企业造成很大的损失,一个老客户的价值相当于三个新客户的价值 3.客户的流失不仅给企业带来经济上的损失,同时也给企业的名誉和口 ...

最新文章

  1. 【Paddy】数据库监控系列(一) - 监控理念
  2. Python爬虫介绍及实战入门
  3. 解决执行go get时报错的问题:dial tcp: lookup xxx.com on 8.8.8.8:53: no such host
  4. c语言里的%p的作用,C语言中geiwei=m%10什么意思,求解!
  5. js 正则 显示千分号 支持整数和小数
  6. C++实例讲解Binder通信
  7. 洛谷P1014 [NOIP1999 普及组] Cantor 表
  8. 1982:【19CSPJ普及组】数字游戏 方法二
  9. tableau两个不同的图合并_【书稿摘要】Tableau地图函数(下)
  10. FreeNAS 安装与用户指导页
  11. Hibernate简易BaseDao演示单例
  12. mpls 保留标签值_MPLS的前世今生11
  13. 语音信号预加重及matlab实现
  14. java read dxf xdata_dxf结构解析及读取坐标 | 学步园
  15. matlab输入二项分布函数,MATLAB如何使用binornd函数生成二项分布随机数
  16. android 百度定位 封装,百度定位SDK使用V4.0
  17. 动态规划之01背包问题讲解
  18. Android各种大内存脚本对比(app2sd,a2sd,a2sd+,d2sd,CronMod,Mound2SD)
  19. Juju-maas 环境搭建
  20. mysql 主备切换关于虚拟ip理解

热门文章

  1. 从头开始学习->JVM(三):类加载器(上)
  2. 2018级《程序设计基础(B)II》期末上机考试 重现--SDUT
  3. Blueprint Framemaker介绍
  4. 计算机开机按f1f2,电脑开机总是提示按f1 f2问题的解决办法
  5. ad域推送软件_如何在域管理环境中进行软件的推送安装
  6. 1698无法登录mysql服务器_一,问题描述:MysqlERROR1698(28000)解决,新装了mysql-server-5.7,登录为这一问题,普通用户不能进mysql,只有root用...
  7. 为什么国外程序员的创造力比中国程序员强?
  8. 抖音直播前需要准备什么,抖音直播带货详细流程步骤丨国仁网络资讯
  9. 洛谷 P1919 模板】A*B Problem升级版(FFT快速傅里叶)
  10. 1919获阿里20亿投资,独角兽如何搅动酒饮业格局