银行客户流失数据分析(BP神经网络与决策树算法)

目录

  • 一、简单介绍
  • 二、BP神经网络分析预测
    • 1.python包
    • 2.数据读取与预处理
      • 属性介绍
      • 数据读取
      • 构建向量
      • 占位符定义
    • 3.神经网络模型
    • 4.训练与预测
        • 训练模型
        • 使用训练好的模型直接预测
  • 三.决策树分析预测
    • 1.导入包
    • 2.特征数值化
    • 3.数据离散化处理
    • 数据筛选
    • 4.划分训练集及测试集
    • 5.数据建模,先设置决策树参数
    • 6.创建流程图保存路径
    • 7.绘制ROC曲线
    • 8.绘制混淆矩阵
    • 9.不同折数交叉验证对比
      • 十折交叉验证
      • 五折交叉验证
      • 十五折交叉验证
      • 对比结果
    • 10.SVM分类器
    • 11.MLP(多层感知机)神经网络
  • 四.完整代码
    • 1.BP神经网络数据分析代码
    • 2.决策树数据分析代码

一、简单介绍

对之前练习项目的一个笔记(所以个人注释比较多),数据集已上传在网盘(有期限(6个月),多了一个生成对抗网络的数据集,到期后的可以评论区留言,看情况会更新),分别通过BP神经网络与决策树算法对银行客户流失分析预测,两种方法各有特点。

数据集链接:

链接:https://pan.baidu.com/s/1seFbXJISoo7MOiJGfHJrxQ?pwd=b4ly
提取码:b4ly

完整文件(包含代码与专属数据集):
https://download.csdn.net/download/piaomiaoxiaoke/89628439

BP神经网络方法需要预安装tensorflow框架(安装过程不在介绍,可以参考网上其他文章),所以准备工作比较多,比较麻烦一些。决策树算法实现(包括和MLP神经网络,SVM支持向量机算法的对比)时没有用TensorFlow框架,因此不用安装,可以自行选择用哪种方法。决策树的预处理更全一些(因为是用的原始数据集),BP神经网络用的数据集是做了一部分预处理后的数据集。

决策树算法绘制流程图需要安装 Graphviz 包,这边简单介绍一下安装过程:
第一步,访问网站,网址如下:

https://graphviz.org/download/
第二步:选择指定系统,指定版本的文件下载,我这边是2.5版本,windows64位的操作系统。
在这里插入图片描述
第三步:下载后双击此文件
在这里插入图片描述
第四步:图片展示
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这边可以自定义路径:
在这里插入图片描述
最后点安装就行,如果安装成功,在命令行窗口(win +R 然后输入 cmd)输入:dot -version。

在这里插入图片描述
出现下图,则安装成功。
在这里插入图片描述

然后在 pycharm 中安装 graphviz 包,在pycharm终端输入:

pip install graphviz

二、BP神经网络分析预测

1.python包

引入一些包,我的是TensorFlow 2.x 版本的,所以需要通过tensorflow.compat.v1等方式来调用TensorFlow 1.x一些函数,如果本身就是TensorFlow 1.x,可以适当修改一下代码:

import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' #定义输出级别,减少控制台不必要输出
#import tensorflow as tf

import tensorflow.compat.v1 as tf

tf.disable_v2_behavior()

import pandas as pd
import numpy as np
from sklearn.utils import shuffle
from sklearn.preprocessing import OneHotEncoder
import matplotlib.pyplot  as plt
from pylab import mpl
mpl.rcParams['font.sans-serif'] = ['STZhongsong']    # 指定默认字体:解决plot不能显示中文问题

2.数据读取与预处理

属性介绍

共有11个属性,包括10个条件属性,1个决策属性(Exited)

'''
客户流失预测模型
owNumber:行号 ×
CustomerID:用户编号 ×
Surname:用户姓名 ×
CreditScore:信用分数
Geography:用户所在国家/地区 ×
Gender:用户性别
Age:年龄
Tenure:当了本银行多少年用户
Balance:存贷款情况
NumOfProducts:使用产品数量
HasCrCard:是否有本行信用卡
IsActiveMember:是否活跃用户
EstimatedSalary:估计收入
Exited:是否已流失,这将作为我们的标签数据
'''

数据读取

#读取数据
df = pd.read_csv("../data/select-data.csv") #读取实验数据集
df_test = pd.read_csv("../data/scalar-test.csv") #读取测试数据集

构建向量

为了方便数据处理,需要将列表转化为numpy数组,并且要二维,target是一维所以需要reshape转化为二维,具体如下:

# 构建向量
#定义两个列表用来存储条件属性和决策属性
train = []
target = []
for i in range(0, len(df["EstimatedSalary"])):#获得实验数据集行数,并对每一行做循环,读取条件属性和决策属性
    mid = []
    mid.append(df["Geography"][i]) #添加Geography属性列第i行的值
    mid.append(df["Gender"][i])
    mid.append(df["EB"][i])
    mid.append(df["Age"][i])
    mid.append(df["EstimatedSalary"][i])
    mid.append(df["NumOfProducts"][i])
    mid.append(df["CreditScore"][i])
    mid.append(df["Tenure"][i])
    mid.append(df["HasCrCard"][i])
    mid.append(df["IsActiveMember"][i])
    target.append(df["Exited"][i])#添加分类属性
    train.append(mid)#添加条件属性
train = np.array(train) #将列表转化为数组,便于处理
target = np.array(target) #将列表转化为数组,便于处理

#测试数据集的处理,处理数据集不一样,其他步骤同上
test = []
test_target = []
for i in range(0, len(df_test["EstimatedSalary"])):
    mid = []
    mid.append(df_test["Geography"][i])
    mid.append(df_test["Gender"][i])
    mid.append(df_test["EB"][i])
    mid.append(df_test["Age"][i])
    mid.append(df_test["EstimatedSalary"][i])
    mid.append(df_test["NumOfProducts"][i])
    mid.append(df_test["CreditScore"][i])
    mid.append(df_test["Tenure"][i])
    mid.append(df_test["HasCrCard"][i])
    mid.append(df_test["IsActiveMember"][i])
    test_target.append(df_test["Exited"][i])
    test.append(mid)
test = np.array(test)
test_target = np.array(test_target)

# 随机打乱训练集与标签
#shuffle随机打乱数据集顺序,防止模型每次都是按固有顺序提取数据,不过不同数据集相对顺序是不变的,可以用来防止过拟合训练,
train, target = shuffle(train, target, random_state=42)#random_state是随机参数,如果不需要可重复性,可不设置random_state
#print(train, target)
#改变数组形状,保持一致,前一个-1表示第一个维度大小自动计算,第二个维度大小为1,test与train本来就是二维所以不用调整
target = target.reshape(-1, 1)
test_target = test_target.reshape(-1, 1)

# One-Hot编码,将分类变量转为为数值,0,1等形式,便于机器学习处理。其实数据集之前已经处理好了,不用这一步也行
enc = OneHotEncoder()#创建一个OneHotEncoder对象
enc.fit(test_target)#使用test_target数据来“训练”或“适应”编码器。这一步是为了知道每个独特的类别应该如何被编码。
test_target = enc.transform(test_target).toarray()#使用上面训练好的编码器将test_target转换为独热编码形式,并将结果从稀疏矩阵转换为普通的NumPy数组
enc.fit(target)#步骤同上
target = enc.transform(target).toarray()
#enc.fit(test_target)

占位符定义

占位符定义的其实是后面代码中

feed_dict={
   x: train, y: target, keep: 1}

的内容,类似于预定义变量名,TensorFlow中用到

# 定义输入占位符,由于本实验实验BP神经网络来预测,因此定义的占位符参数也和此相关,具体如下
x = tf.placeholder(tf.float32, shape=(None, 10))
#x是一个形状为(None, 10)的占位符,表示输入数据的特征矩阵,每一行是一个样本,每一列是一个特征,None表示样本的数量可以是任意的(行),10表示特征的数量是固定的(列)
#二分类问题 [0,1]
y = tf.placeholder(tf.float32, shape=(None, 2))
#y是一个形状为(None, 2)的占位符,表示输入数据的标签向量,每一行是一个样本,每一列是一个类别,None表示样本的数量可以是任意的,2表示类别的数量是固定的,这是一个二分类问题,所以有两个类别
keep = tf.placeholder(tf.float32)
#keep是一个形状为标量的占位符,表示在训练时使用的dropout的保留率,即每个神经元被保留的概率,它可以用来防止过拟合,一般在训练时设置为小于1的值,比如0.5,而在测试时设置为1,表示不使用dropout

3.神经网络模型

定义神经网络结构,包括几个隐藏层,隐藏层几个神经元,初始权重,初始偏移量等等。具体几个隐藏层不一定是2,我只是以2作为例子,说不定1个隐藏层或者三个隐藏层效果更好,可以自己慢慢调试看看。
第一个隐藏层的第一维是10,是和条件属性数量对应的,输出成的2是和决策属性类别对应的(二分类,所以是2),具体如下,有注释说明(也包含了其他的一些定义,如准确率,优化器函数等等):

# 定义网络结构,这边定义了两个隐藏层,一个输出,具体几个隐藏层以及隐藏层的维数可自定义调整
# layer1,定义第一个隐藏层
var1 = tf.Variable(tf.truncated_normal([10, 256], stddev=0.1))
#定义初始权重矩阵,随机选取均值为0、标准差为0.1的截断正态分布(之所以要截断正态分布,主要是避免异常值影响,因为用的sigmoid激活函数,所以要避免偏离的值)
bias1 = tf.Variable(tf.zeros([256]))#初始化偏移值,都设为0
hc1 = tf.add(tf.matmul(x, var1), bias1)
#tf.matmul(x, var1) 表示矩阵 x 和 var1 之间的矩阵乘法。然后,我们将偏置 bias1 加到乘积上,得到 hc1,x的定义在前面给出
h1 = tf.sigmoid(hc1)
#使用sigmoid激活函数,对函数非线性转化
h1 = tf.nn.dropout(h1, keep_prob=keep)
# 为了避免过拟合对 h1 进行 dropout 正则化,其中 keep 是 dropout 的保留概率。这意味着在训练过程中,h1 中的每个元素都有 1 - keep 的概率被设置为0。

# layer2 定义第二个隐藏层,具体和上面步骤差不多,不过初始权重矩阵不同,因为进行矩阵乘法,所以要保持前后层 行列对应
var2 = tf.Variable(tf.truncated_normal([256, 256], stddev=0.1))
bias2 = tf.Variable(tf.zeros([256]))
hc2 = tf.add(tf.matmul(h1, var2), bias2)
h2 = tf.sigmoid(hc2)
h2 = tf.nn.dropout(h2, keep_prob=keep)

# layer3
var3 = tf.Variable(tf.truncated_normal([256, 2], stddev=0.1))
bias3 = tf.Variable(tf.zeros([2]))#二分类,所以是2个偏移量
hc3 = tf.add(tf.matmul(h2, var3), bias3)
h3 = tf.nn.softmax(hc3)
#输出层,因为是二分类,所以要用激活函数转化为分类问题
#使用 softmax 激活函数对 hc3 进行非线性转换。softmax 函数通常用于多分类问题的输出层,因为它可以将任意实数值转换为介于0和1之间的概率分布。

#定义损失函数:交叉熵损失函数
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(logits=h3, labels=y))
#logits=h3, labels=y,h3为预测的标签,y为真实的标签,先得到一个损失值,然后用reduce_mean获得平均损失值
tf.summary.scalar('loss', loss)#可视化写入

# 定义正确率
ac = tf.cast(tf.equal(tf.argmax(h3, 1), tf.argmax(y, 1)), tf.float32)
#tf.argmax(h3, 1),沿着列寻找最大值,即[0.8,0.2]=0,[0.2,0.8]=1,equal得到布尔值类型,所以需要转为浮点型以便进行准确率求和与平均
acc = tf.reduce_mean(ac)#求平均值,获得平均准确率
tf.summary.scalar('accuracy', acc)

# 定义优化器,一个学习率的优化方法,动态调整学习率
optimzer = tf.train.AdamOptimizer(1e-3).minimize(loss)
merge_summary = tf.summary.merge_all()
#isTrain判断是训练还是测试
isTrain = 0

4.训练与预测

按照预定义模型进行训练与预测,并给出准确率,这个设计了一个isTrain来决定是训练还是直接用训练好的模型测试,一般是先把 isTrain=1,然后训练出一个最优模型,然后将模型参数保存起来,后面就可以直接用这个模型参数,不用再训练了(将isTrain=0)。不过保存参数与调用的时候主要路径别弄错了。

训练模型

当isTrain等于1时,会先训练模型然后再进行预测,并画出准确率与损失值曲线,然后将模型参数保存起来,具体如下,黄色的是测试集准确率变化,绿色为训练集准确率变化,红色为损失值变化(模型我没有仔细调整,所以准确率不是特别高,有兴趣的可以自己调看看,比如增加神经网络层数,神经元数量,换个激活函数等等,效果应该是可以更好的):

在这里插入图片描述
这是控制台的输出结果,第一列为批次,第二列为训练集预测准确率,第二列为测试预测准确率比训练集低一些,不过也是正常的,最后一列是损失值

在这里插入图片描述

使用训练好的模型直接预测

当isTrain=1,代码已经训练好并保存了模型参数,如果想直接用此模型进行预测,省去训练步骤,则可以直接调用,将isTrain=0,可以直接得到预测结果,给出预测的类别。使用时注意模型的保存路径别弄错。
在这里插入图片描述

代码如下:

# 定义训练
print("正在训练.....")
saver = tf.train.Saver(max_to_keep=1)
#创建一个saver对象,用于保存和恢复模型的参数,max_to_keep参数表示最多保留一个模型文件

with tf.Session() as sess:
    #创建一个session对象,用于执行计算图中的操作和变量
    if isTrain:#判断是否是训练模式,如果是,执行以下的代码
        init_op = tf.global_variables_initializer()#创建一个初始化操作,用于初始化所有的变量
        sess.run(init_op)#执行初始化操作,给所有的变量赋予初始值
        summary_writer = tf.summary.FileWriter('../logs/', sess.graph)
        #创建一个summary_writer对象,用于将计算图和汇总信息写入日志文件,方便在TensorBoard中可视化
        nepoch=[]#创建一个空列表,用于存储训练的轮数
        trainacc=[]#创建一个空列表,用于存储训练集的准确率
        testacc=[]#创建一个空列表,用于存储测试集的准确率
        loss1=[] #创建一个空列表,用于存储训练集的损失值
        for i in range(0, 10001):#训练轮数
            sess.run(optimzer, feed_dict={
   x: train, y: target, keep: 0.5})
            #执行优化器的minimize操作(梯度下降法之类的,之前定义的optimzer),更新模型的参数,feed_dict参数表示给占位符提供输入数据,x是训练集的特征,y是训练集的标签,keep是dropout的保留率,设置为0.5表示每个神经元有50%的概率被保留
            train_summary = sess.run(merge_summary, feed_dict={
   x: train, y: target, keep: 1})
            #汇总信息
            summary_writer.add_summary(train_summary, i)
            #汇总信息
            if i % 50 == 0:
                accu = sess.run(acc, feed_dict={
   x: train, y: target, keep: 1})#训练集准确率
                accuT = sess.run(acc, feed_dict={
   x: test, y: test_target, keep: 1})#测试集准确率
                losss = sess.run(loss, feed_dict={
   x: train, y: target, keep: 1})#损失值

                print("epoch:" + str(i) + "   train_acc:" + str(accu) + "   test_acc:" + str(accuT) + "   loss:" + str(
                    losss))

                nepoch.append(i)
                trainacc.append(accu)
                testacc.append(accuT)
                loss1.append(losss)

        plt.title("BP神经网络训练性能曲线")
        plt.xlabel('训练次数')
        plt.ylabel('训练样本和检验样本的准确度')
        plt.plot(nepoch,trainacc,nepoch,testacc)#绘制两条曲线,分别表示训练集和测试集的准确率随训练次数的变化。
        plt.plot(nepoch,trainacc,nepoch,loss1)#绘制两条曲线,分别表示训练集的准确率和损失值随训练次数的变化
        plt.show()
        saver.save(sess, '../model/bank.ckpt', global_step=i)
        #保存模型的参数到’./model/bank.ckpt’文件中,并在文件名后面添加当前的训练步数
    #使用训练好的模型参数文件进行预测,预测时用不到y,所以y其实可以省略,具体用不用到得看使用的函数用没用到y
    else:
        f = open("../result/target.txt", "w")#预测结果写入此文件
        model_file = tf.train.latest_checkpoint('../model/')#saver.save保存的路径
        saver.restore(sess, model_file)#使用saver对象恢复模型的参数,需要一个session对象和一个模型文件的路径,这里使用sess和model_file作为参数
        tar = sess.run(h3, feed_dict={
   x: test, y: test_target, keep: 1})
        #h3为模型输出层,由此可以得到模型预测值,y: test_target可以去掉,因为预测时候用不到
        tar = sess.run(tf.argmax(tar, 1))
        for i in range(0, len(tar)):
            f.write(str(tar[i]) + " ")
        f.close()
        print(tar)#显示预测结果

三.决策树分析预测

1.导入包

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from graphviz import Source
#Graphviz是一个开源的图形可视化软件,它可以将数据以图形的方
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值