2022福大数学建模赛题B题-BP神经网络多分类Tensorflow-附python代码
题目3:请根据附件 2 所提供的部分食物寒热属性(分为三类:性平、性温热、性凉寒),对附 件 1 中的食物进行分类,判断这些食物是属于性平、性温热或性凉寒中哪一类,并说明你分类的合理性;
BP神经网络:外部输入信号经输入层、隐含层的神经元的逐层处理,并向前传播至输出层从而获得结果。如果在输出层无法得到期望输出,则转入误差的反向传播过程,将网络输出实际值之间的误差沿原连接通路原路返回,通过修改各层神经元的连接权重,减小误差,然后转入正向传播过程,经过多次迭代,直至到达最大迭代次数或误差小于给定值为止。
过程:
1、数据预处理。附件 1中 1284种食物,有 549种食物是已知其寒热属性,另外 735种食物的寒热属性未知。提取数据并归一化处理。
2、构建模型。此时将食物各成分看成 BP神经网络模型的输入层,将 Y(寒热属性)当作模型的输出层。这里损失函数用的是均方误差。
3、正交实验设计。要考虑学习率、迭代次数、和神经元个数三个因素。各设置3个水平,采用正交实验的好处是,考虑了 3个因素彼此之间的交互作用,且减少实验的次数。
4、BP神经网络训练。得出的模型效果良好,但受参数影响较大。且训练时间随着问题规模以及神经元个数的增加而增加。
5、未知类别数据分类。利用训练出来的模型进行分类,并将分类结果标注在表中,并输出一个新的excel表。
python源代码:
注意:因变量Y需要映射为数值变量。因为后面的one-hot编码不能对字符串型状态编码,这点不同于哑变量(dummy)的处理。另外数据类型的转换也需要注意,因为这里面调用了一些已有的库,它们输入数据有些是array数组,dataframe表格,tensor张量等。还有就是神经网络训练时需要对已知数据集分成训练集和测试集,选择时尽量随机选择数据,避免训练集和测试集数据差异过大。
-
import pandas as pd
-
import numpy as np
-
from sklearn import preprocessing
-
import re
-
import random
-
import tensorflow as tf
-
-
df1 = pd.read_excel(r'食物成分表.xlsx', index_col=0).reset_index(drop=True)
-
df3 = df1.drop(['可食部分(%)'], axis=1)
-
scaler = preprocessing.MinMaxScaler() # 标准化
-
df33 = scaler.fit_transform(df3[df3.columns[1:17]]) # 训练和导出结果
-
df33 = pd.DataFrame(df33, columns=df3.columns[1:17]) # 数据格式转换
-
df3 = pd.concat([df3['名 称'], df33], axis=1)
-
df3['catef'] = '' # 添加分类列
-
print(df3.head()) # 查看前5条数据
-
-
-
# 根据附件2分类标注数据
-
def TagCategory(datastr, f, tap):
-
for line in f:
-
a = re.split('。|、|;|(|)|\\n| ', line) # 分割字符串保存到a
-
a = [x.strip() for x in a if x.strip() != ''] # 去除空字符串
-
for ss in a:
-
index0 = datastr.str.find(ss) # 找到则返回所要找字符串在指定字符串位置,没有则返回-1
-
ind = index0[index0.values != -1].index # 不为-1的即表示有
-
df3['catef'][ind] = tap # 标注
-
-
-
mingcheng = df3['名 称'].astype(str) # 提取名称所在列
-
f0 = open(r'性平.txt', encoding='utf-8')
-
f1 = open(r'性凉寒.txt', encoding='utf-8')
-
f2 = open(r'性温热.txt', encoding='utf-8')
-
TagCategory(mingcheng, f0, '性平') # 性平标
-
TagCategory(mingcheng, f1, '性凉寒') # 性凉寒标
-
TagCategory(mingcheng, f2, '性温热') # 性温热标
-
print(df3.head()) # 查看前5行
-
-
NonNulldf = df3[(df3['catef'].notnull()) & (df3['catef'] != "")] # 找到所有已知类数据
-
IsNulldf = df3[(df3['catef'] == "")] # 找到未知类数据
-
kongindex = df3[(df3['catef'] == "")].index # 找到未知类数据的索引
-
print(NonNulldf.head())
-
-
# 取数据方法:
-
data_train = NonNulldf
-
# 在初始数据划分训练集与测试集时直接将数据打乱:
-
data_train['catef']=data_train.catef.map({'性平':0,'性凉寒':1,'性温热':2})#分类列映射
-
DataIndex = [i for i in range(len(NonNulldf))]#产生索引
-
random.shuffle(DataIndex)#打算排序
-
data_train.index = [DataIndex]#新的排序
-
-
x_train = data_train.iloc[0:round(0.95 * len(NonNulldf)), 1:17] # 取16个特征变量
-
y_train = data_train.iloc[0:round(0.95 * len(NonNulldf)), 17] # 后三列是因变量标签
-
x_test = data_train.iloc[round(0.95 * len(NonNulldf)):, 1:17] # 取16个特征变量
-
y_test = data_train.iloc[round(0.95 * len(NonNulldf)):, 17] #
-
-
# 转换x的数据类型,否则后面矩阵相乘时会因数据类型不一致报错
-
x_train = tf.cast(x_train, tf.float32)
-
x_test = tf.cast(x_test, tf.float32)
-
# from_tensor_slices函数使输入特征和标签值一个一个地对应。(把数据集分批次,每个批次batch组数据)
-
train_db = tf.data.Dataset.from_tensor_slices((x_train, y_train)).batch(32)
-
test_db = tf.data.Dataset.from_tensor_slices((x_test, y_test)).batch(32)
-
-
# 生成神经网络的参数,16个输入特征,输入层为16个输入节点;因为3分类,故输出层为3个神经元
-
# 用tf.Variable()标记参数可训练
-
w1 = tf.Variable(tf.random.truncated_normal([16, 3], stddev=0.1)) # 16行三列,方差为0.1
-
b1 = tf.Variable(tf.random.truncated_normal([3], stddev=0.1)) # 一行三列,方差为0.1
-
-
-
a = 0.4 # 学习率为0.4
-
epoch = 1000 # 循环1000轮
-
# 训练部分
-
for epoch in range(epoch): # 数据集级别的循环,每个epoch循环一次数据集
-
for step, (x_train, y_train) in enumerate(train_db): # batch级别的循环 ,每个step循环一个batch
-
with tf.GradientTape() as tape: # with结构记录梯度信息
-
y = tf.matmul(x_train, w1) b1 # 神经网络乘加运算
-
y = tf.nn.softmax(y) # 使输出y符合概率分布
-
y_ = tf.one_hot(y_train, depth=3) # 将标签值转换为独热码格式,方便计算loss
-
loss = tf.reduce_mean(tf.square(y_ - y)) # 采用均方误差损失函数mse = mean(sum(y-y*)^2)
-
# 计算loss对w, b的梯度
-
grads = tape.gradient(loss, [w1, b1])
-
# 实现梯度更新 w1 = w1 - lr * w1_grad b = b - lr * b_grad
-
w1.assign_sub(a * grads[0]) # 参数w1自更新
-
b1.assign_sub(a * grads[1]) # 参数b自更新
-
# 每1000次迭代,输出一次损失函数
-
if epoch % 10 == 0:
-
print('迭代第%i次,损失函数为:%f' % (epoch, loss))
-
-
-
# 测试部分
-
total_correct, total_number = 0, 0
-
for x_test, y_test in test_db:
-
# 前向传播求概率
-
y = tf.matmul(x_test, w1) b1
-
y = tf.nn.softmax(y)
-
predict = tf.argmax(y, axis=1) # 返回y中最大值的索引,即预测的分类
-
# 将predict转换为y_test的数据类型
-
predict = tf.cast(predict, dtype=y_test.dtype)
-
# 若分类正确,则correct=1,否则为0,将bool型的结果转换为int型
-
correct = tf.cast(tf.equal(predict, y_test), dtype=tf.int32)
-
# 将每个batch的correct数加起来
-
correct = tf.reduce_sum(correct)
-
# 将所有batch中的correct数加起来
-
total_correct = int(correct)
-
# total_number为测试的总样本数,也就是x_test的行数,shape[0]返回变量的行数
-
total_number = x_test.shape[0]
-
# 总的准确率等于total_correct/total_number
-
acc = total_correct / total_number
-
print("测试准确率 = %.2f %%" % (acc * 100.0))
-
data_pre = IsNulldf
-
x_pre = data_pre.iloc[0:, 1:17] # 取16个特征变量
-
x_pre = tf.convert_to_tensor(x_pre)#转换为张量
-
x_pre = tf.cast(x_pre, tf.float32)#转换数据类型
-
y = tf.matmul(x_pre, w1) b1#y值
-
y = tf.nn.softmax(y)
-
category = {0: "性平", 1: "性凉寒", 2: "性温热"}#映射
-
predict = np.array(tf.argmax(y, axis=1)) # 返回y中最大值的索引,即预测的分类[0]
-
for i in range(len(predict)):#未知数据预测
-
print("食物属性为:", category.get(predict[i]))
-
-
#数据标注并写入excel表中
-
_1index=[]
-
_2index=[]
-
_3index = []
-
for i in range(len(predict)):
-
if predict[i]== 1:
-
_1index.append(i)#找到预测为性凉寒
-
elif predict[i]== 2:
-
_2index.append(i)#找到温热
-
else:
-
_3index.append(i)#找到性平
-
-
#在原始数据中标注好分类
-
df3['catef'][kongindex[_1index]] = '性凉寒'
-
df3['catef'][kongindex[_2index]] = '性温热'
-
df3['catef'][kongindex[_3index]] = '性平'
-
print(len(_1index),len(_2index),len(_3index))#看预测各类各有多少个
-
-
#将预测分类写入表格
-
df3_w=pd.concat([df1[df1.columns[0]],df1[df1.columns[2:17]], df3['catef']], axis=1)
-
writer1 = pd.ExcelWriter('df3.xlsx') # 创建excel表格
-
df3_w.to_excel(writer1, 'page_1')
-
writer1.save()#保存
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhgjgkfh
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
怎样阻止微信小程序自动打开
PHP中文网 06-13