LSTM-糖尿病预测模型优化探索

一、前期准备

python 复制代码
import pandas as pd
import numpy as np
import torch
import torch.nn as nn
from torch.utils.data import TensorDataset, DataLoader
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
from datetime import datetime
import warnings

# 基础设置与随机种子锁定
warnings.filterwarnings('ignore')
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei'] 
plt.rcParams['axes.unicode_minus'] = False 

np.random.seed(42)
torch.manual_seed(42)
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(f"当前设备: {device}")

二、数据预处理

python 复制代码
file_name = 'diabetes.csv'
try:
    df = pd.read_csv(file_name, encoding='gbk')
    print("成功挂载本地医疗数据集")
    
    # 步骤1:剔除无业务意义的列
    if '卡号' in df.columns:
        df.drop(['卡号'], axis=1, inplace=True)
        
    y = df['是否糖尿病'].values
    
    # 步骤2:根据相关性分析,剔除目标列及负相关特征
    cols_to_drop = ['是否糖尿病']
    if '高密度脂蛋白胆固醇' in df.columns:
        cols_to_drop.append('高密度脂蛋白胆固醇')
        print("已按要求剪除负相关特征: '高密度脂蛋白胆固醇'")
        
    X = df.drop(cols_to_drop, axis=1).values

except FileNotFoundError:
    print("未检测到本地数据集,已自动生成R7标准高仿真数据")
    # 模拟截图中800+条数据的规模
    X = np.random.rand(804, 11) * 100 
    y = np.random.randint(0, 2, 804)

#  数据标准化与张量升维
sc_X = StandardScaler()
X_scaled = sc_X.fit_transform(X)

X_tensor = torch.tensor(X_scaled, dtype=torch.float32).to(device)
y_tensor = torch.tensor(y, dtype=torch.int64).to(device)

train_X, test_X, train_y, test_y = train_test_split(X_tensor, y_tensor, test_size=0.2, random_state=42)

# 将二维数据升维,适配LSTM[样本数, 1, 特征数]
train_X = train_X.unsqueeze(1)
test_X = test_X.unsqueeze(1)

train_dl = DataLoader(TensorDataset(train_X, train_y), batch_size=64, shuffle=True)
test_dl = DataLoader(TensorDataset(test_X, test_y), batch_size=64, shuffle=False)

三、构建优化版LSTM网络

python 复制代码
class OptimizedDiabetesLSTM(nn.Module):
    def __init__(self, input_dim):
        super(OptimizedDiabetesLSTM, self).__init__()
        # 使用轻量级LSTM层提取特征
        self.lstm = nn.LSTM(input_size=input_dim, hidden_size=64, num_layers=1, batch_first=True)
        self.dropout = nn.Dropout(0.3)
        self.fc = nn.Linear(64, 2) # 最终分类(是/否糖尿病)

    def forward(self, x):
        out, _ = self.lstm(x)
        out = self.dropout(out[:, -1, :]) 
        out = self.fc(out)
        return out

input_dimension = train_X.shape[2]
model = OptimizedDiabetesLSTM(input_dim=input_dimension).to(device)

criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

四、执行训练循环

python 复制代码
epochs = 50
train_acc_hist, val_acc_hist = [], []
train_loss_hist, val_loss_hist = [], []

for epoch in range(epochs):
    model.train()
    running_loss, correct, total = 0.0, 0, 0
    for batch_X, batch_y in train_dl:
        optimizer.zero_grad()
        outputs = model(batch_X)
        loss = criterion(outputs, batch_y)
        loss.backward()
        optimizer.step()
        
        running_loss += loss.item() * batch_X.size(0)
        _, predicted = torch.max(outputs, 1)
        total += batch_y.size(0)
        correct += (predicted == batch_y).sum().item()
        
    epoch_loss = running_loss / total
    epoch_acc = correct / total
    
    # 验证集评估
    model.eval()
    val_loss, val_correct, val_total = 0.0, 0, 0
    with torch.no_grad():
        for batch_X, batch_y in test_dl:
            outputs = model(batch_X)
            loss = criterion(outputs, batch_y)
            val_loss += loss.item() * batch_X.size(0)
            _, predicted = torch.max(outputs, 1)
            val_total += batch_y.size(0)
            val_correct += (predicted == batch_y).sum().item()
            
    val_epoch_loss = val_loss / val_total
    val_epoch_acc = val_correct / val_total
    
    train_loss_hist.append(epoch_loss)
    train_acc_hist.append(epoch_acc)
    val_loss_hist.append(val_epoch_loss)
    val_acc_hist.append(val_epoch_acc)
    
    if (epoch + 1) % 10 == 0:
        print(f"Epoch [{epoch+1}/{epochs}] | Train Acc: {epoch_acc:.4f} | Val Acc: {val_epoch_acc:.4f}")

print("模型优化训练完毕")

五、结果可视化

python 复制代码
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
epochs_range = range(epochs)

plt.figure(figsize=(14, 5))

# 左图:准确率曲线
plt.subplot(1, 2, 1)
plt.plot(epochs_range, train_acc_hist, label='Training Accuracy', linewidth=2)
plt.plot(epochs_range, val_acc_hist, label='Validation Accuracy', linewidth=2)
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')
plt.xlabel(f"Epochs\nTimestamp: {current_time}") 
plt.grid(True, linestyle='--', alpha=0.6)

# 右图:损失曲线
plt.subplot(1, 2, 2)
plt.plot(epochs_range, train_loss_hist, label='Training Loss', linewidth=2)
plt.plot(epochs_range, val_loss_hist, label='Validation Loss', linewidth=2)
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.xlabel('Epochs')
plt.grid(True, linestyle='--', alpha=0.6)

plt.tight_layout()
plt.show()

六、总结

1. 探索性数据分析(EDA)与相关性矩阵

在构建神经网络前,首先借助 pandas.DataFrame.corr() 方法计算特征间的相关系数,并利用可视化工具绘制热力图。这一步提供了极佳的全局视野,帮助我们直观评估各项生理指标与预测目标(是否患糖尿病)之间的数学关联强度。

2. 果断的特征修剪 (Feature Pruning)

高质量的数据输入是深度学习的绝对基石。本周实战了如何对冗余数据进行果断修剪:

  • 剔除无业务逻辑特征: 使用drop函数移除"卡号"等仅作标识用的字段,防止其成为模型权重更新时的噪音干扰。
  • 剔除负相关特征: 依据相关性分析结果,移除了与目标呈负相关的"高密度脂蛋白胆固醇"字段。此举有效降低了特征维度,大幅减轻了LSTM网络的参数计算负担。

3. 张量维度的严格对齐

针对纯表格型数据,再次巩固了使用PyTorch构建LSTM时的核心前置操作:必须调用 unsqueeze(1) 函数,将原本二维的张量 [Batch_Size, Features] 强制扩展为三维的 [Batch_Size, Time_Steps, Features],以适配时序模型极其苛刻的底层输入形状要求。

相关推荐
派拉软件2 小时前
派拉AIGS应用场景解析:在客户实际环境中,AI Agent如何做到“可控、可管、可审“
大数据·人工智能
创世宇图2 小时前
DeepSeek API涨价的技术归因与开发者成本优化实操
人工智能·deepseek
四六的六2 小时前
端侧模型多端部署实战:从格式转换到灰度发布,Web 和移动端统一部署流水线
前端·人工智能·大模型·ai编程·ai模型·ai产品·端侧ai
深小乐3 小时前
用AI做了6首歌曲MV后,我最大的收获不是会做了,而是干中学
人工智能
郑午时光3 小时前
全球首发!2026年适合IP短剧长视频的AI视频生成工具,即梦seedance2.5轻松做短剧
人工智能·tcp/ip·音视频
智道天成3 小时前
浙江代办食品生产许可证怎么办理,哪些企业可以申请全程代办服务
人工智能
汇策研习社3 小时前
双指标共振交易体系:GMMA趋势骨架 + MACD动能验证实战全解
大数据·人工智能·信息可视化·金融·区块链·fastbull
皮皮虾❀3 小时前
阿里巴巴“千问办公”公测深度解析:企业级Agent如何重塑智能办公
人工智能·阿里云·云计算
G31135422733 小时前
大模型不可用时,业务还能不能继续:企业需要设计降级方案
大数据·服务器·数据库·人工智能·深度学习
TechEdu2026063 小时前
[人工智能]TensorFlow深度学习框架工程实践概览
人工智能·深度学习·ai·tensorflow