第三十七天打卡

知识点回顾:

  1. 过拟合的判断:测试集和训练集同步打印指标
  2. 模型的保存和加载
    1. 仅保存权重
    2. 保存权重和模型
    3. 保存全部信息checkpoint,还包含训练状态
  3. 早停策略

作业:对信贷数据集训练后保存权重,加载权重后继续训练50轮,并采取早停策略

import pandas as pd
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler, StandardScaler, OneHotEncoder, LabelEncoder
import time
import matplotlib.pyplot as plt
from tqdm import tqdm
from imblearn.over_sampling import SMOTE# ------------------- 设备配置(GPU/CPU) -------------------
# 检查是否有可用的GPU:如果有则用GPU加速训练(速度更快),否则用CPU
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(f"使用设备: {device}")  # 打印当前使用的设备(确认是否启用GPU)# ------------------- 加载并清洗数据 -------------------
# 加载信贷预测数据集(假设data.csv在当前目录下)
# 数据包含用户信息(如收入、工作年限)和标签(是否违约:Credit Default)
data = pd.read_csv(r'data.csv')# 丢弃无用的Id列(Id是用户唯一标识,与信贷违约无关)
data = data.drop(['Id'], axis=1)  # axis=1表示按列删除# 区分连续特征(数值型)和离散特征(文本型/类别型)
# 连续特征:比如年龄、收入(可以取任意数值)
# 离散特征:比如职业、教育程度(只能取有限的类别)
continuous_features = data.select_dtypes(include=['float64', 'int64']).columns.tolist()  # 数值列
discrete_features = data.select_dtypes(exclude=['float64', 'int64']).columns.tolist()  # 非数值列# 离散特征用众数(出现次数最多的值)填充缺失值
# 例:如果"职业"列有缺失,用出现最多的职业填充
for feature in discrete_features:if data[feature].isnull().sum() > 0:  # 检查是否有缺失值mode_value = data[feature].mode()[0]  # 计算众数data[feature].fillna(mode_value, inplace=True)  # 填充缺失值# 连续特征用中位数(中间位置的数)填充缺失值
# 例:如果"收入"列有缺失,用所有收入的中间值填充(比平均数更抗异常值)
for feature in continuous_features:if data[feature].isnull().sum() > 0:median_value = data[feature].median()  # 计算中位数data[feature].fillna(median_value, inplace=True)# ------------------- 离散特征编码(转成数值) -------------------
# 有顺序的离散特征(比如"工作年限"有"1年"<"2年"<"10+年")用标签编码(转成数字)
mappings = {"Years in current job": {"10+ years": 10,  # "10+年"对应数字10(最大)"2 years": 2,     # "2年"对应数字2"3 years": 3,"< 1 year": 0,    # "<1年"对应数字0(最小)"5 years": 5,"1 year": 1,"4 years": 4,"6 years": 6,"7 years": 7,"8 years": 8,"9 years": 9},"Home Ownership": {  # 房屋所有权(有顺序:租房 < 房贷 < 有房贷 < 自有房?)"Home Mortgage": 0,  # 房贷"Rent": 1,           # 租房"Own Home": 2,       # 自有房"Have Mortgage": 3   # 有房贷(可能顺序需要根据业务调整)},"Term": {  # 贷款期限(短期 < 长期)"Short Term": 0,  # 短期"Long Term": 1    # 长期}
}# 使用映射字典将文本转成数字(标签编码)
data["Years in current job"] = data["Years in current job"].map(mappings["Years in current job"])
data["Home Ownership"] = data["Home Ownership"].map(mappings["Home Ownership"])
data["Term"] = data["Term"].map(mappings["Term"])# 无顺序的离散特征(比如"贷款用途":购车/教育/装修,彼此无大小关系)用独热编码
# 独热编码:将1列转成N列(N是类别数),每列用0/1表示是否属于该类别
data = pd.get_dummies(data, columns=['Purpose'])  # 对"Purpose"列做独热编码# 独热编码后会生成新列(比如Purpose_购车、Purpose_教育),需要将这些列的类型从bool转成int(0/1)
list_final = []  # 存储新生成的列名
data2 = pd.read_csv(r'data.csv')  # 重新读取原始数据(对比列名)
for i in data.columns:if i not in data2.columns:  # 原始数据没有的列,就是新生成的独热列list_final.append(i)
for i in list_final:data[i] = data[i].astype(int)  # 将bool型(True/False)转成int(1/0)# ------------------- 分离特征和标签 -------------------
X = data.drop(['Credit Default'], axis=1)  # 特征数据(所有列,除了标签列)
y = data['Credit Default']  # 标签数据(0=未违约,1=违约)# 划分训练集(80%)和测试集(20%):训练集用来学习规律,测试集验证模型效果
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)  # random_state固定随机种子,保证结果可复现# 特征标准化(将特征缩放到0-1区间,避免大数值特征"欺负"小数值特征)
scaler = MinMaxScaler()  # 创建MinMaxScaler(最小-最大标准化)
X_train = scaler.fit_transform(X_train)  # 用训练集拟合标准化参数并转换
X_test = scaler.transform(X_test)  # 用训练集的参数转换测试集(保证数据分布一致)# 将数据转成PyTorch张量(神经网络只能处理张量数据),并移动到GPU(如果有)
# FloatTensor:32位浮点数(特征数据)
# LongTensor:64位整数(标签数据,分类任务需要)
X_train = torch.FloatTensor(X_train).to(device)
y_train = torch.LongTensor(y_train.values).to(device)
X_test = torch.FloatTensor(X_test).to(device)
y_test = torch.LongTensor(y_test.values).to(device)# ------------------- 定义神经网络模型 -------------------
class MLP(nn.Module):def __init__(self):super(MLP, self).__init__()  # 调用父类构造函数(必须)# 全连接层1:输入30个特征(根据数据预处理后的列数确定),输出64个神经元self.fc1 = nn.Linear(30, 64)self.relu = nn.ReLU()  # 激活函数(引入非线性,让模型能学习复杂规律)self.dropout = nn.Dropout(0.2)  # Dropout层(随机丢弃30%的神经元,防止过拟合)# 全连接层2:输入64个神经元,输出32个神经元self.fc2 = nn.Linear(64, 32)# 全连接层3:输入32个神经元,输出2个类别(0=未违约,1=违约)self.fc3 = nn.Linear(32, 2)def forward(self, x):# 前向传播:数据从输入层→隐藏层→输出层的计算流程x = self.fc1(x)    # 输入层→隐藏层1:30→64x = self.relu(x)   # 激活函数(过滤负数值)x = self.dropout(x)  # 应用Dropout(防止过拟合)x = self.fc2(x)    # 隐藏层1→隐藏层2:64→32x = self.relu(x)   # 激活函数x = self.fc3(x)    # 隐藏层2→输出层:32→2(输出未归一化的分数)return x# ------------------- 初始化模型、损失函数、优化器 -------------------
model = MLP().to(device)  # 实例化模型并移动到GPU
criterion = nn.CrossEntropyLoss()  # 交叉熵损失函数(适合分类任务)
optimizer = optim.Adam(model.parameters(), lr=0.001)  # Adam优化器(比SGD更智能,自动调整学习率)# ------------------- 模型训练 -------------------
num_epochs = 20000  # 训练轮数(完整遍历训练集的次数)
train_losses = []         # 记录每200轮的训练损失
test_losses = []          # 记录每200轮的测试损失
accuracies = []     # 记录每200轮的测试准确率
epochs = []         # 记录对应的轮数
# ==========新增早停相关参数==========
best_test_loss = float('inf')  # 记录最佳测试集损失
best_epoch = 0                 # 记录最佳epoch
patience =  50              # 早停耐心值(连续多少轮测试集损失未改善时停止训练)
counter = 0                    # 早停计数器
early_stopped = False          # 是否早停标志
# =====================================
start_time = time.time()  # 记录训练开始时间# 创建tqdm进度条(可视化训练进度)
with tqdm(total=num_epochs, desc="训练进度", unit="epoch") as pbar:for epoch in range(num_epochs):# 前向传播:模型根据输入数据计算预测值outputs = model(X_train)  # 模型输出(形状:[训练样本数, 2],表示每个样本属于2个类别的分数)train_loss = criterion(outputs, y_train)  # 计算损失(预测值与真实标签的差异,越小越好)# 反向传播和参数更新optimizer.zero_grad()  # 清空历史梯度(避免梯度累加)train_loss.backward()        # 反向传播计算梯度(自动求导)optimizer.step()       # 根据梯度更新模型参数(优化器核心操作)# 每200轮记录一次损失和准确率(避免记录太频繁影响速度)if (epoch + 1) % 200 == 0:# 在测试集上评估模型(不更新参数,只看效果)model.eval()  # 切换到评估模式(关闭Dropout,保证结果稳定)with torch.no_grad():  # 禁用梯度计算(节省内存,加速推理)test_outputs = model(X_test)  # 测试集预测值test_loss = criterion(test_outputs, y_test)  # 计算测试集损失model.train()  # 切换回训练模式# 记录损失值和准确率train_losses.append(train_loss.item())  # 训练集损失test_losses.append(test_loss.item())  # 测试集损失epochs.append(epoch + 1)  # 记录轮数# 更新进度条显示的信息(当前损失和准确率)pbar.set_postfix({'Train Loss': f'{train_loss.item():.4f}', 'Test Loss': f'{test_loss.item():.4f}'})# ===== 新增早停逻辑 =====if test_loss.item() < best_test_loss: # 如果当前测试集损失小于最佳损失best_test_loss = test_loss.item() # 更新最佳损失best_epoch = epoch + 1 # 更新最佳epochcounter = 0 # 重置计数器# 保存最佳模型torch.save(model.state_dict(), 'best_model.pth')else:counter += 1if counter >= patience:print(f"早停触发!在第{epoch+1}轮,测试集损失已有{patience}轮未改善。")print(f"最佳测试集损失出现在第{best_epoch}轮,损失值为{best_test_loss:.4f}")early_stopped = Truebreak  # 终止训练循环# ======================# 每1000轮更新一次进度条(避免进度条刷新太频繁)if (epoch + 1) % 1000 == 0:pbar.update(1000)  # 进度条前进1000步# 确保进度条最终显示100%(防止最后一轮未更新)if pbar.n < num_epochs:pbar.update(num_epochs - pbar.n)# 计算总训练时间并打印
time_all = time.time() - start_time
print(f'Training time: {time_all:.2f} seconds')# ===== 新增:加载最佳模型用于最终评估 =====
if early_stopped:print(f"加载第{best_epoch}轮的最佳模型进行最终评估...")model.load_state_dict(torch.load('best_model.pth'))
# ================================# ------------------- 可视化训练结果 -------------------
# 创建双y轴图表(损失和准确率在同一张图显示)
# 可视化损失曲线
plt.figure(figsize=(10, 6))
plt.plot(epochs, train_losses, label='Train Loss')
plt.plot(epochs, test_losses, label='Test Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Training and Test Loss over Epochs')
plt.legend()
plt.grid(True)
plt.show()# ------------------- 最终测试集评估 -------------------
model.eval()  # 切换到评估模式
with torch.no_grad():  # 禁用梯度计算outputs = model(X_test)  # 测试集预测值_, predicted = torch.max(outputs, 1)  # 取预测类别(0或1)correct = (predicted == y_test).sum().item()  # 正确预测的样本数accuracy = correct / y_test.size(0)  # 计算准确率print(f'测试集准确率: {accuracy * 100:.2f}%')  # 打印准确率(百分比形式)
#测试集准确率: 77.20%

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/news/906996.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java高频面试之并发编程-21

hello啊&#xff0c;各位观众姥爷们&#xff01;&#xff01;&#xff01;本baby今天又来报道了&#xff01;哈哈哈哈哈嗝&#x1f436; 面试官&#xff1a;详细说说AQS AQS&#xff08;AbstractQueuedSynchronizer&#xff09;是 Java 并发包&#xff08;java.util.concurre…

按键状态机

原工程地址&#xff1a;https://github.com/candylife9/state_machine_example 视频&#xff1a;C语言之状态机编程_02_状态机使用案例分析_哔哩哔哩_bilibili 我觉得讲的挺好的。 来自豆包封装的通用接口 头文件 /*** file key_state_machine.h* brief 通用按键状态机接口…

华为OD机试真题——新学校选址(2025A卷:100分)Java/python/JavaScript/C/C++/GO最佳实现

2025 A卷 100分 题型 本专栏内全部题目均提供Java、python、JavaScript、C、C++、GO六种语言的最佳实现方式; 并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析; 本文收录于专栏:《2025华为OD真题目录+全流程解析+备考攻略+经验分…

欧拉操作系统下安装hadoop集群

背景&#xff1a;欧拉操作系统下安装CDH集群的时候&#xff0c;需要安装python2.7.5&#xff0c;但是本身欧拉系统对python2的支持可能没有那么好&#xff0c;所以考虑搭建原生的hadoop集群。 基础环境如下 组件名称组件版本欧拉VERSION“22.03 (LTS-SP4)”jdkopenjdk versio…

SQL语句的执行流程

文章目录 一、执行流程二、建立连接三、预处理器四、解析器4.1 词法分析4.2 语法分析4.3 语义分析 五、优化器六、执行器七、返回结果 一、执行流程 阶段主要功能关键组件1. 建立连接身份验证、权限检查连接器2. 预处理器缓存检查、SQL预处理查询缓存3. 解析器词法分析、语法分…

TiDB:从快速上手到核心原理与最佳实践

文章目录 引言第一部分&#xff1a;TiDB快速体验与实践指南1. TiDB概述2. TiDB部署方式2.1 本地测试环境部署2.2 生产环境部署2.3 Kubernetes部署2.4 云服务 3. TiDB基本操作3.1 连接TiDB3.2 数据库和表操作3.3 分区表3.4 事务操作 4. 数据迁移到TiDB4.1 从MySQL迁移4.2 使用Ti…

总结:进程和线程的联系和区别

前言:通过学习javaEE初阶中的多线程章节后加上我自己的理解,想来总结一下线程和进程的联系和区别. 一来是能更好地复习知识,二来是为了记录我的学习路程,相信未来的我回首不会忘记这段难忘的经历. 1.进程 先来谈谈进程:进程是操作系统中资源分配的基本单位. 1)进程的执行方…

边缘云的定义、实现与典型应用场景!与传统云计算的区别!

一、什么是边缘云&#xff1f;‌ 边缘云是一种‌分布式云计算架构‌&#xff0c;将计算、存储和网络资源部署在‌靠近数据源或终端用户的网络边缘侧‌&#xff08;如基站、本地数据中心或终端设备附近&#xff09;&#xff0c;而非传统的集中式云端数据中心。 ‌核心特征‌&…

海康威视摄像头C#开发指南:从SDK对接到安全增强与高并发优化

一、海康威视SDK核心对接流程​​ 1. ​​开发环境准备​​ ​​官方SDK获取​​&#xff1a;从海康开放平台下载最新版SDK&#xff08;如HCNetSDK.dll、PlayCtrl.dll&#xff09;。​​依赖项安装​​&#xff1a;确保C运行库&#xff08;如vcredist_x86.exe&#xff09;与S…

《软件工程》第 9 章 - 软件详细设计

目录 9.1 详细设计的任务与过程模型 9.2 用例设计 9.2.1 设计用例实现方案 9.2.2 构造设计类图 9.2.3 整合并优化用例实现方案 9.3 子系统设计 9.3.1 确立内部设计元素 9.3.2 导出设计类图 9.4 构件设计 9.5 类设计 9.5.1 精化类间关系 9.5.2 精化属性和操作 9.5.…

spring+tomcat 用户每次发请求,tomcat 站在线程的角度是如何处理用户请求的,spinrg的bean 是共享的吗

对于 springtomcat 用户每次发请求&#xff0c;tomcat 站在线程的角度是如何处理的 比如 bio nio apr 等情况 tomcat 配置文件中 maxThreads 的数量是相对于谁来说的&#xff1f; 以及 spring Controller 中的全局变量:各种bean 对于线程来说是共享的吗&#xff1f; 一、Tomca…

存储引擎系列--LSM不同Compaction策略性能分析对比

本文介绍一下参考论文里的Compaction性能分析部分,作者在RocksDB的基础上做了多种策略的改造,然后提出了benchmarking方法论,关注compaction性能的哪些维度,并对结果进行分析。 一、Standardization of Compaction Strategies 1.1 实验平台的选择 作者选择了RocksDB作为…

leetcode 3559. Number of Ways to Assign Edge Weights II

leetcode 3559. Number of Ways to Assign Edge Weights II 1. 解题思路2. 代码实现 题目链接&#xff1a;3559. Number of Ways to Assign Edge Weights II 1. 解题思路 这一题是题目3558. Number of Ways to Assign Edge Weights I的进阶版本。 对于题目3558来说&#xf…

推理模型 vs 非推理模型:核心区别及优劣势解析

推理能力上的差异 推理模型在推理能力方面表现突出,它们擅长通过生成中间步骤和“思维链”逐步解决复杂问题。这意味着面对数学计算、逻辑推理、多跳推断等任务时,推理模型能够将问题分解为若干子步骤,每一步给出推理结果,最终汇总得到答案。这种逐步推导的方式使得推理模…

OPENEULER搭建私有云存储服务器

一、关闭防火墙和selinux 二、下载相关软件 下载nginx&#xff0c;mariadb、php、nextcloud 下载nextcloud&#xff1a; sudo wget https://download.nextcloud.com/server/releases/nextcloud-30.0.1.zip sudo unzip nextcloud-30.0.1.zip -d /var/www/html/ sudo chown -R…

Docker 与微服务架构:从单体应用到容器化微服务的迁移实践

随着软件系统规模和复杂性的日益增长,传统的单体应用(Monolithic Application)在开发效率、部署灵活性和可伸缩性方面逐渐暴露出局限性。微服务架构(Microservice Architecture)作为一种将大型应用拆分为一系列小型、独立、松耦合服务的模式,正成为现代企业构建弹性、敏捷…

【C#】Invalidate()的使用

Invalidate()的使用 Invalidate() 是 C# 中用于通知控件需要重新绘制的方法。它通常用于 Windows Forms 应用程序中&#xff0c;当想要更新控件的显示内容时使用。调用 Invalidate() 方法后&#xff0c;系统会安排对该控件进行重绘&#xff0c;这将导致后续调用 OnPaint 方法&…

我店模式系统开发打造本地生活生态商圈

在当今快节奏的商业环境中&#xff0c;商家们面临着越来越多的挑战&#xff0c;包括市场竞争加剧、消费者需求多样化以及运营效率的提高等。为了应对这些挑战&#xff0c;越来越多的商家开始寻求信息化解决方案&#xff0c;以提升运营效率和客户体验。我的店模式系统平台应运而…

Linux(Ubuntu)新建文件权限继承问题

当你在一个工作目权限为777的文件下&#xff0c;新建一个文件的时候&#xff0c;就有可能发生&#xff0c;新建的这个文件&#xff0c;权限和其他文件&#xff0c;或者工作目录不一致的问题&#xff0c;我们不可能每次新建一个文件&#xff0c;就要 sudo chmod -R 777 /PATH 所…

Vue3和React中插件化设计思想

Vue 3 和 React 都广泛支持插件化设计思想&#xff0c;但因为它们的架构和理念不同&#xff0c;插件化的实现方式也不尽相同。以下分别详细讲解这两者中如何实现插件化&#xff1a; &#x1f7e9; 一、Vue 3 中的插件化实现 Vue 3 继承了 Vue 2 的插件机制&#xff0c;同时增强…