一、实验目的
Python聚类决策树训练与预测:
1、掌握决策树的基本原理并理解监督学习的基本思想。
2、掌握Python实现决策树的方法。
基于神经网络的MNIST手写体识别:
1、学习导入和使用Tensorflow。
2、理解学习神经网络的基本原理。
3、学习使用Python实现MNIST手写体识别。
二、实验原理
运用Jupyter notebook平台编写实例Python决策树构建、训练、可视化及预测程序。运用Jupyter notebook平台编写实例Python神经网络程序。
三、使用软件平台
1、Windows 11电脑一台。
2、Anaconda、Python、Spyder平台Jupyter notebook平台。
四、实验内容
实例一:
实例1:基于ONE-HOT编码的银行贷款决策树
基于sklearn库和ONE-HOT编码的决策树,并实现可视化。
要求:
(1)使用pandas读取银行贷款信息数据集。
(2)使用DictVectorizer做数据处理,实现输入特征向量化。
(3)利用sklearn库构建决策树并开展训练。
(4)利用pydotplus库完成决策树可视化。
结果:
代码:
# 导入必要库
import pandas as pd
from sklearn.tree import DecisionTreeClassifier, plot_tree
from sklearn.feature_extraction import DictVectorizer
import matplotlib.pyplot as plt
import matplotlib as mpl
# 自动检测文件编码
import chardet
# 检测文件编码
file_path = 'loan_YN.csv'
with open(file_path, 'rb') as f:
raw_data = f.read()
detected_encoding = chardet.detect(raw_data)['encoding']
# 解决中文显示问题
mpl.rcParams['font.sans-serif'] = ['SimHei'] # 使用中文字体(如 SimHei)
mpl.rcParams['axes.unicode_minus'] = False # 正常显示负号
# 加载数据
data = pd.read_csv('loan_YN.csv', encoding=detected_encoding) # 自动检测到的编码
# 查看数据前几行
print(data.head())
# 特征和目标变量
X = data[['age', 'income', 'guding', 'VIP']]
y = data['loan']
# 特征向量化(使用 DictVectorizer 进行 ONE-HOT 编码)
vec = DictVectorizer(sparse=False)
X_encoded = vec.fit_transform(X.to_dict(orient='records'))
# 训练决策树
clf = DecisionTreeClassifier(criterion='entropy', max_depth=4, random_state=42)
clf.fit(X_encoded, y)
# 可视化决策树
plt.figure(figsize=(20, 10))
plot_tree(clf,
feature_names=vec.get_feature_names_out(),
class_names=clf.classes_,
filled=True,
rounded=True)
plt.title("基于CSV数据的决策树")
plt.show()
思考题:
思考1:基于特征数字化的银行贷款决策树
要求:
(1)利用pandas导入特征数字化的银行贷款数据集,查看并分析数据内容。
(2)参照实例1完成决策树的构建和训练。
(3)利用pydotplus库完成决策树可视化。
(4)观察特征数字化和特征向量化对决策树的影响。
结果:
代码:
# 导入必要库
import pandas as pd
from sklearn.tree import DecisionTreeClassifier, export_graphviz
import pydotplus
# 加载数据
file_path = 'loan_YN_01.csv' # 确保路径正确,例如 'C:/path_to_file/loan_YN_01.csv'
data = pd.read_csv(file_path)
# 特征和目标变量分离
X = data[['age', 'income', 'guding', 'VIP']] # 特征
y = data['loan'] # 目标
# 构建并训练决策树
clf = DecisionTreeClassifier(criterion='entropy', max_depth=5, random_state=42)
clf.fit(X, y)
# 导出决策树为 DOT 格式
dot_data = export_graphviz(
clf,
out_file=None,
feature_names=['age', 'income', 'guding', 'VIP'], # 特征名
class_names=['N', 'Y'], # 类别名
filled=True,
rounded=True,
special_characters=True
)
# 使用 pydotplus 生成图片
graph = pydotplus.graph_from_dot_data(dot_data)
# 保存图片
graph.write_png("decision_tree.png")
print("决策树图片已保存为 decision_tree.png")
实例2:构建、训练、保存神经网络模型,并输出训练及测试准确率。
用Python编程实现,导入TensorFlow包,定义神经网络模型,读取并且输入MNIST数据集的训练图片和标签数据,启动网络训练,输出得到网络不同批次训练的损失值和准确率。
要求:
(1)初始化参数矩阵,定义一个init_weights(shape)函数,使得该函数可以返回一个与输入形状相同的tensor,标准差为0.01,并且利用该函数生成shape=[784, 16]的全连接层1、shape=[16, 16]的全连接层2和shape=[16, 10]的输出层。
(2)初始化网络模型,定义一个按顺序与以上两个全连接层和输出层相乘的神经网络model(x,h1,h2,out),x代表输入训练数据,h1,h2,out分别代表(1)中定义的两个全连接层和输出层,并且返回最终的输出结果。
(3)定义好损失函数、优化器后,设置模型训练的训练次数和每批次送入模型的图片数量,开始模型训练,要求训练次数在代码开始运行后可以从键盘输入。
(4)每隔1000个训练批次输出一次平均损失值和训练准确率,损失值保留6位小数,准确率保留3位小数,最后输出一个平均测试准确率,保留三位小数。
结果:
代码:
import tensorflow as tf
import numpy as np
from tensorflow.keras.datasets import mnist
from tensorflow.keras.utils import to_categorical
from tqdm import tqdm # 导入 tqdm 用于进度条
# 导入数据集
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.reshape(-1, 784).astype('float32') / 255.0
x_test = x_test.reshape(-1, 784).astype('float32') / 255.0
y_train = to_categorical(y_train, 10)
y_test = to_categorical(y_test, 10)
# 注册自定义类为可序列化对象
@tf.keras.utils.register_keras_serializable()
# 定义模型
class NeuralNetwork(tf.keras.Model):
def __init__(self):
super(NeuralNetwork, self).__init__()
self.dense1 = tf.keras.layers.Dense(16, activation='relu') # 第一隐藏层
self.dense2 = tf.keras.layers.Dense(16, activation='relu') # 第二隐藏层
self.output_layer = tf.keras.layers.Dense(10) # 输出层
def call(self, x):
x = self.dense1(x)
x = self.dense2(x)
return self.output_layer(x)
def get_config(self):
"""返回模型配置字典"""
config = super(NeuralNetwork, self).get_config()
return config
@classmethod
def from_config(cls, config):
"""从配置字典恢复模型实例"""
return cls()
# 自定义回调函数用于输出格式调整和进度条
class ProgressBarCallback(tf.keras.callbacks.Callback):
def __init__(self, epochs):
self.epochs = epochs
self.progress_bar = tqdm(total=epochs, desc="训练进度", unit="epoch")
def on_epoch_end(self, epoch, logs=None):
# 更新进度条
self.progress_bar.update(1)
# 每 1000 次或最后一次打印日志
if (epoch + 1) % 1000 == 0 or epoch + 1 == self.epochs:
print(f"\n第 {epoch + 1} 次训练\t损失值: {logs['loss']:.6f}\t训练准确率: {logs['accuracy']:.3%}")
def on_train_end(self, logs=None):
# 关闭进度条
self.progress_bar.close()
def calculate_average_accuracy(model, x, y, batch_size=128):
num_batches = len(x) // batch_size
accuracies = []
for i in range(num_batches):
batch_x = x[i * batch_size:(i + 1) * batch_size]
batch_y = y[i * batch_size:(i + 1) * batch_size]
_, acc = model.evaluate(batch_x, batch_y, verbose=0)
accuracies.append(acc)
return np.mean(accuracies)
# 初始化模型
model = NeuralNetwork()
# 编译模型
model.compile(
optimizer=tf.keras.optimizers.Adam(learning_rate=0.001),
loss=tf.keras.losses.CategoricalCrossentropy(from_logits=True),
metrics=['accuracy']
)
# 输入训练次数
epochs = int(input("请输入训练次数: "))
# 训练模型,添加自定义回调和进度条
model.fit(
x_train, y_train,
batch_size=128,
epochs=epochs,
validation_data=(x_test, y_test),
callbacks=[ProgressBarCallback(epochs)],
verbose=0 # 禁用默认输出
)
# 测试集评估
test_loss, test_acc = model.evaluate(x_test, y_test, verbose=0)
# 计算测试集的平均准确率
average_test_acc = calculate_average_accuracy(model, x_test, y_test)
# 打印结果
print(f"测试集整体准确率: {test_acc:.3%}")
print(f"测试集平均准确率: {average_test_acc:.3%}")
# 使用 .keras 扩展名保存为 Keras 推荐的保存格式
model.save("neural_network_plus_model.keras")
print("模型已保存为 neural_network_model.keras")
实例3:可视化模型输出结果和标签。
导入matplotlib.pyplot和numpy,利用实验1中训练好的模型来预测MNIST测试集的图片,并且在得到结果的同时与数据集中的标签进行对比,判断预测是否正确。
要求:
(1)定义图片展示函数display_compare(num),可以通过键盘选择需要预测的图片,num为需要进行预测和判断的图片序号(范围为0-10000)。
(2)将输入图片重构为网络需要的维度([1,784])送入模型进行预测并且保留下来,通过argmax激活函数获得模型的输出数字和实际标签进行比较,判断预测是否正确。
(3)利用matplotlib.pyplot包,展示所预测原始图片(需要将输入重构为28*28大小才能恢复成原始图片样式),并且在图片title处输出预测值和标签和预测是否正确。
结果:
代码:
import tensorflow as tf
import matplotlib.pyplot as plt
import matplotlib
import numpy as np
from tensorflow.keras.models import load_model # 用于加载模型
# 设置中文字体
matplotlib.rcParams['font.sans-serif'] = ['SimHei'] # 设置字体为黑体
matplotlib.rcParams['axes.unicode_minus'] = False # 解决负号显示问题
# 加载 .keras 格式
model = load_model("neural_network_model.keras")
print("模型已加载: neural_network_model.keras")
# 加载测试数据
(_, _), (x_test, y_test) = tf.keras.datasets.mnist.load_data() # 仅加载测试集
x_test = x_test.reshape(-1, 784).astype('float32') / 255.0 # 数据归一化
y_test = tf.keras.utils.to_categorical(y_test, 10) # One-hot 编码
def display_compare(num):
"""
可视化预测和标签
:param num: 测试集中的图片序号
"""
# 提取图片和标签
img = x_test[num].reshape(1, 784)
label = y_test[num]
# 模型预测
logits = model(img)
pred = tf.argmax(logits, axis=1).numpy()[0]
true_label = tf.argmax(label).numpy()
# 判断预测是否正确
is_correct = (pred == true_label)
# 绘制图片
plt.imshow(img.reshape(28, 28), cmap='gray')
plt.title(f"预测值: {pred}, 实际值: {true_label}, 预测{'正确' if is_correct else '错误'}")
plt.axis('off')
plt.show()
# 输入图片编号
num = int(input("请输入想要查看的图片编号(0-9999范围): "))
display_compare(num)
注意:必须现有训练模型,才能进行图片判断。