DAY 36 复习日

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

●作业:对之前的信贷项目,利用神经网络训练下,尝试用到目前的知识点让代码更加规范和美观。

●探索性作业(随意完成):尝试进入nn.Module中,查看他的方法

python 复制代码
import torch
import torch.nn as nn
import torch.optim as optim
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
import numpy as np
import pandas as pd
# 导入 Pipeline 和相关预处理工具
from sklearn.pipeline import Pipeline #  用于创建机器学习工作流
from sklearn.compose import ColumnTransformer # 用于将不同的预处理应用于不同的列,之前是对datafame的某一列手动处理,如果在pipeline中直接用standardScaler等函数就会对所有列处理,所以要用到这个工具
from sklearn.preprocessing import OrdinalEncoder, OneHotEncoder, StandardScaler # 用于数据预处理
from sklearn.impute import SimpleImputer # 用于处理缺失值
data = pd.read_csv('data.csv')  # 读取数据
y = data['Credit Default']
X = data.drop(['Credit Default'], axis=1)
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
object_cols = X.select_dtypes(include=['object']).columns.tolist()

# 有序分类特征 (对应你之前的标签编码)
# 注意:OrdinalEncoder默认编码为0, 1, 2... 对应你之前的1, 2, 3...需要在模型解释时注意
# 这里的类别顺序需要和你之前映射的顺序一致
ordinal_features = ['Home Ownership', 'Years in current job', 'Term']
# 定义每个有序特征的类别顺序,这个顺序决定了编码后的数值大小
ordinal_categories = [
    ['Own Home', 'Rent', 'Have Mortgage', 'Home Mortgage'], # Home Ownership 的顺序 (对应1, 2, 3, 4)
    ['< 1 year', '1 year', '2 years', '3 years', '4 years', '5 years', '6 years', '7 years', '8 years', '9 years', '10+ years'], # Years in current job 的顺序 (对应1-11)
    ['Short Term', 'Long Term'] # Term 的顺序 (对应0, 1)
]
# 先用众数填充分类特征的缺失值,然后进行有序编码
ordinal_transformer = Pipeline(steps=[
    ('imputer', SimpleImputer(strategy='most_frequent')), # 用众数填充分类特征的缺失值
    ('encoder', OrdinalEncoder(categories=ordinal_categories, handle_unknown='use_encoded_value', unknown_value=-1))
])


# 分类特征
nominal_features = ['Purpose'] # 使用原始列名
# 先用众数填充分类特征的缺失值,然后进行独热编码
nominal_transformer = Pipeline(steps=[
    ('imputer', SimpleImputer(strategy='most_frequent')), # 用众数填充分类特征的缺失值
    ('onehot', OneHotEncoder(handle_unknown='ignore', sparse_output=False)) # sparse_output=False 使输出为密集数组
])


# 连续特征
# 从X的列中排除掉分类特征,得到连续特征列表
continuous_features = X.columns.difference(object_cols).tolist() # 原始X中非object类型的列

# 先用众数填充缺失值,然后进行标准化
continuous_transformer = Pipeline(steps=[
    ('imputer', SimpleImputer(strategy='most_frequent')), # 用众数填充缺失值 (复现你的原始逻辑)
    ('scaler', StandardScaler()) # 标准化,一个好的实践
])

# --- 构建 ColumnTransformer ---
# 将不同的预处理应用于不同的列子集,构造一个完备的转化器
preprocessor = ColumnTransformer(
    transformers=[
        ('ordinal', ordinal_transformer, ordinal_features),
        ('nominal', nominal_transformer, nominal_features),
        ('continuous', continuous_transformer, continuous_features)
    ],
    remainder='passthrough' # 保留没有在transformers中指定的列(如果存在的话),或者 'drop' 丢弃
)
#对训练集和测试集应用预处理(必须先处理再转换为张量)
X_train_processed = preprocessor.fit_transform(X_train)  # 训练集:拟合+转换
X_test_processed = preprocessor.transform(X_test)        # 测试集:仅转换(复用训练集参数)
# 查看预处理后的特征数(关键:用于模型输入层维度)
print(f"预处理后训练集特征数:{X_train_processed.shape[1]}")  # 假设输出为 M(例如20)
input_feature_num = X_train_processed.shape[1]  # 存储特征数,用于模型定义



# 将数据转换为 PyTorch 张量,因为 PyTorch 使用张量进行训练
# y_train和y_test是整数,所以需要转化为long类型,如果是float32,会输出1.0 0.0
X_train = torch.FloatTensor(X_train_processed)
y_train = torch.LongTensor(y_train.values)
X_test = torch.FloatTensor(X_test_processed)
y_test = torch.LongTensor(y_test.values)

class MLP(nn.Module): # 定义一个多层感知机(MLP)模型,继承父类nn.Module
    def __init__(self): # 初始化函数
        super(MLP, self).__init__() # 调用父类的初始化函数
 # 前三行是八股文,后面的是自定义的
        self.fc1 = nn.Linear(input_feature_num, 20)  # 输入层到隐藏层
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(20, 2)  # 隐藏层到输出层
# 输出层不需要激活函数,因为后面会用到交叉熵函数cross_entropy,交叉熵函数内部有softmax函数,会把输出转化为概率

    def forward(self, x):
        out = self.fc1(x)
        out = self.relu(out)
        out = self.fc2(out)
        return out

# 实例化模型
model = MLP()

# 分类问题使用交叉熵损失函数
criterion = nn.CrossEntropyLoss()

# 使用随机梯度下降优化器
optimizer = optim.SGD(model.parameters(), lr=0.01)

# # 使用自适应学习率的化器
# optimizer = optim.Adam(model.parameters(), lr=0.001)

# 训练模型
num_epochs = 20000 # 训练的轮数

# 用于存储每个 epoch 的损失值
losses = []

import time
start_time = time.time() # 记录开始时间

for epoch in range(num_epochs): # range是从0开始,所以epoch是从0开始
    # 前向传播
    outputs = model.forward(X_train)   # 显式调用forward函数
    # outputs = model(X_train)  # 常见写法隐式调用forward函数,其实是用了model类的__call__方法
    loss = criterion(outputs, y_train) # output是模型预测值,y_train是真实标签

    # 反向传播和优化
    optimizer.zero_grad() #梯度清零,因为PyTorch会累积梯度,所以每次迭代需要清零,梯度累计是那种小的bitchsize模拟大的bitchsize
    loss.backward() # 反向传播计算梯度
    optimizer.step() # 更新参数

    # 记录损失值
    losses.append(loss.item())

    # 打印训练信息
    if (epoch + 1) % 100 == 0: # range是从0开始,所以epoch+1是从当前epoch开始,每100个epoch打印一次
        print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')

time_all = time.time() - start_time # 计算训练时间
print(f'Training time: {time_all:.2f} seconds')
import matplotlib.pyplot as plt
# 可视化损失曲线
plt.plot(range(num_epochs), losses)
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Training Loss over Epochs')
plt.show()
相关推荐
这里有鱼汤13 分钟前
A股预测还能更准?开源大模型Kronos带你跑通预测+回测全流程
后端·python
大模型真好玩31 分钟前
深入浅出LangGraph AI Agent智能体开发教程(二)—LangGraph预构建图API快速创建Agent
人工智能·python·mcp
像风一样自由20201 小时前
Python与Rust语法对比详解:从入门到精通
开发语言·python·rust
Dxy12393102161 小时前
python如何下载svg图片
开发语言·python
hAnGWS2 小时前
Python可视化与交互-matplotlib库
python·交互·matplotlib
limengshi1383922 小时前
人工智能学习:Python相关面试题
jvm·python·学习
威风的虫3 小时前
FastAPI 核心实战:精通路径参数、查询参数与数据交互
python·交互·fastapi
空影星7 小时前
免费在线图片合成视频工具 ,完全免费
python·flask·电脑·智能硬件
向上的车轮9 小时前
Odoo与Django 的区别是什么?
后端·python·django·odoo
Source.Liu11 小时前
【学Python自动化】 2. Windows Python 解释器使用笔记
windows·python·自动化