目录
- 一、简单介绍
- 二、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是一个开源的图形可视化软件,它可以将数据以图形的方