当前位置: 首页 > news >正文

【Day36】

DAY 36 复习日

对应5.25作业

仔细回顾一下神经网络到目前的内容,没跟上进度的同学补一下进度。

  • 作业:对之前的信贷项目,利用神经网络训练下,尝试用到目前的知识点让代码更加规范和美观。
  • 探索性作业(随意完成):尝试进入nn.Module中,查看他的方法
    # ------------------- 导入工具库 -------------------
    # pandas: 用于读取和处理表格数据(类似Excel的操作)
    # numpy: 用于高效数值计算(比如矩阵运算)
    # torch: PyTorch深度学习框架(核心库,用于搭建和训练神经网络)
    # sklearn: 机器学习工具库(这里用数据划分、标准化等)
    # time: 用于记录训练时间
    # matplotlib: 可视化图表(绘制损失、准确率曲线)
    # tqdm: 进度条工具(让训练过程更直观)
    # imblearn: 处理数据不平衡(这里暂时未用,但先导入)
    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'python60-days-challenge\1_python-learning-library\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'python60-days-challenge\1_python-learning-library\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.3)  # 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  # 训练轮数(完整遍历训练集的次数)
    losses = []         # 记录每200轮的训练损失
    accuracies = []     # 记录每200轮的测试准确率
    epochs = []         # 记录对应的轮数
    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个类别的分数)loss = criterion(outputs, y_train)  # 计算损失(预测值与真实标签的差异,越小越好)# 反向传播和参数更新optimizer.zero_grad()  # 清空历史梯度(避免梯度累加)loss.backward()        # 反向传播计算梯度(自动求导)optimizer.step()       # 根据梯度更新模型参数(优化器核心操作)# 每200轮记录一次损失和准确率(避免记录太频繁影响速度)if (epoch + 1) % 200 == 0:losses.append(loss.item())  # loss.item():将张量转成Python数值epochs.append(epoch + 1)    # 记录当前轮数# 在测试集上评估模型(不更新参数,只看效果)model.eval()  # 切换到评估模式(关闭Dropout,保证结果稳定)with torch.no_grad():  # 禁用梯度计算(节省内存,加速推理)test_outputs = model(X_test)  # 测试集预测值_, predicted = torch.max(test_outputs, 1)  # 取分数最高的类别作为预测结果correct = (predicted == y_test).sum().item()  # 计算预测正确的样本数accuracy = correct / y_test.size(0)  # 准确率 = 正确数 / 总样本数accuracies.append(accuracy)  # 记录准确率# 更新进度条显示的信息(当前损失和准确率)pbar.set_postfix({'Loss': f'{loss.item():.4f}', 'Accuracy': f'{accuracy * 100:.2f}%'})# 每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')# ------------------- 可视化训练结果 -------------------
    # 创建双y轴图表(损失和准确率在同一张图显示)
    fig, ax1 = plt.subplots(figsize=(10, 6))# 绘制损失曲线(红色)
    color = 'tab:red'
    ax1.set_xlabel('Epoch')  # x轴:训练轮数
    ax1.set_ylabel('Loss', color=color)  # y轴:损失值(红色)
    ax1.plot(epochs, losses, color=color)  # 绘制损失随轮数变化的曲线
    ax1.tick_params(axis='y', labelcolor=color)  # y轴标签颜色与曲线一致# 创建第二个y轴(蓝色),用于绘制准确率
    ax2 = ax1.twinx()
    color = 'tab:blue'
    ax2.set_ylabel('Accuracy', color=color)  # y轴:准确率(蓝色)
    ax2.plot(epochs, accuracies, color=color)  # 绘制准确率随轮数变化的曲线
    ax2.tick_params(axis='y', labelcolor=color)plt.title('Training Loss and Accuracy over Epochs')  # 图表标题
    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}%')  # 打印准确率(百分比形式)
    训练进度: 100%|█████████████████████████████████████████████████████████| 20000/20000 [01:34<00:00, 210.57epoch/s, Loss=0.3135, Accuracy=73.93%]
    Training time: 95.05 seconds
    测试集准确率: 73.93%

    浙大疏锦行

相关文章:

  • openjdk底层(hotspot)汇编指令的内存分布
  • 关于多类型数据划分清洗的整理
  • ISO 20000体系:服务请求管理、问题管理、事件管理区别与联系
  • BAT32G113 发送互补PWM
  • 第十九章:数据治理之数据指标(一):数据指标工具之【指标口径管理系统】与【指标数据查询系统】
  • (九)PMSM驱动控制学习---无感控制之高阶滑膜观测器
  • obsidian 中的查找和替换插件,支持正则
  • STL-从list节点创建和释放展开(内存管理)
  • Linux系统编程-DAY04
  • C语言初阶--操作符
  • 升级Win11后VMware虚拟机屏幕调整问题
  • 领域驱动设计与COLA框架:从理论到实践的落地之路
  • 数字信号处理大实验2.1(基础) 快速傅里叶变换与FFT的时域频域对称性质
  • 微软Build 2025五大AI发布
  • Spring Cloud项目登录认证从JWT切换到Redis + UUID Token方案
  • 前置过滤器和净水机安哪个?
  • git checkout 通配符
  • Kafka Consumer工作流程
  • JVM 的类加载机制
  • 贪心算法应用:贝尔曼-福特松弛问题详解
  • 可以做片头的网站/成都网站建设技术支持
  • grace 7 wordpress/北京seo优化多少钱
  • o2o平台是什么意思/迈步者seo
  • html可以做网站吗/怎么注册个人网站
  • 爱生活和辽宁app下载/单页关键词优化费用
  • 网站建设模板怎么设计/网站页面优化包括