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()
相关推荐
q5673152338 分钟前
Rust爬虫与代理池技术解析
开发语言·爬虫·python·rust
Dxy123931021642 分钟前
Python如何合并两个Excel文件
爬虫·python·excel
fsnine2 小时前
数字图像处理基础——opencv库(Python)
人工智能·python·opencv
Yc98012 小时前
解决:开启魔法后vscode pip命令不能安装中科大python镜像问题
vscode·python·pip
xunie3 小时前
2025-08-09通过授权码的方式给exe程序充值
python
GoodTime4 小时前
Datawhale AI夏令营 -「多模态RAG图文问答挑战赛」
人工智能·python·算法
Aousdu5 小时前
算法_python_学习记录_01
python·学习·算法
张子夜 iiii12 小时前
(0️⃣基础)程序控制语句(初学者)(第3天)
人工智能·python
码农派大星。15 小时前
Selenium在Pyhton应用
python·selenium·测试工具