You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在PyTorch中将OhioT1DM数据集的XML文件转为张量?

实现步骤:从OhioT1DM XML数据到模型输入张量

下面是从数据集读取、解析到张量转换的完整流程,适配你的需求:

1. 导入依赖库

先把需要的工具库导入:

import os
import xml.etree.ElementTree as ET
import pandas as pd
import torch
from sklearn.preprocessing import LabelEncoder, StandardScaler
from torch.nn.utils.rnn import pad_sequence

2. 批量收集XML文件路径

写个工具函数,一次性收集2018和2020年指定split(train/test)下的所有XML文件:

DATA_ROOT = "dataset"

def collect_xml_files(target_years, split_type):
    xml_paths = []
    for year in target_years:
        split_dir = os.path.join(DATA_ROOT, str(year), split_type)
        for filename in os.listdir(split_dir):
            if filename.endswith(".xml"):
                xml_paths.append(os.path.join(split_dir, filename))
    return xml_paths

# 收集训练集和测试集文件
train_xmls = collect_xml_files([2018, 2020], "train")
test_xmls = collect_xml_files([2018, 2020], "test")

3. 解析XML文件为结构化数据

遍历所有XML文件,提取患者基本信息和各类事件数据,整理成统一格式:

def parse_single_xml(xml_path):
    tree = ET.parse(xml_path)
    root = tree.getroot()
    patient_base = root.attrib  # 提取患者id、weight、insulin_type等属性
    patient_id = patient_base["id"]
    all_events = []

    # 处理临时基础胰岛素事件(temp_basal)
    temp_basal_node = root.find("temp_basal")
    if temp_basal_node:
        for event in temp_basal_node.findall("event"):
            all_events.append({
                "patient_id": patient_id,
                "event_type": "temp_basal",
                "ts": event.attrib["ts_begin"],
                "ts_end": event.attrib["ts_end"],
                "value": float(event.attrib["value"]),
                **patient_base
            })
    
    # 处理餐食事件(meal)
    meal_node = root.find("meal")
    if meal_node:
        for event in meal_node.findall("event"):
            all_events.append({
                "patient_id": patient_id,
                "event_type": "meal",
                "ts": event.attrib["ts"],
                "meal_type": event.attrib["type"],
                "carbs": float(event.attrib["carbs"]),
                **patient_base
            })
    
    # 可以继续添加其他事件类型的解析(比如血糖、大剂量胰岛素等)
    return all_events

# 解析所有训练数据
train_raw_data = []
for path in train_xmls:
    train_raw_data.extend(parse_single_xml(path))

# 转成DataFrame,方便后续预处理
train_df = pd.DataFrame(train_raw_data)

4. 数据预处理

把原始数据转换成模型能接受的格式:

# 1. 处理时间特征:把字符串转成datetime格式,方便排序/提取时序特征
def parse_time_str(time_str):
    return pd.to_datetime(time_str, format="%d-%m-%Y %H:%M:%S")

train_df["ts"] = train_df["ts"].apply(parse_time_str)
train_df["ts_end"] = train_df["ts_end"].fillna(pd.NaT).apply(lambda x: parse_time_str(x) if pd.notna(x) else x)

# 2. 编码类别特征(比如胰岛素类型、餐食类型)
le_insulin = LabelEncoder()
train_df["insulin_type_encoded"] = le_insulin.fit_transform(train_df["insulin_type"])

le_meal = LabelEncoder()
# 仅对餐食事件编码,非餐食事件填充默认值
train_df["meal_type_encoded"] = train_df["meal_type"].apply(
    lambda x: le_meal.fit_transform([x])[0] if pd.notna(x) else 0
)

# 3. 归一化数值特征(weight、value、carbs)
scaler = StandardScaler()
numeric_cols = ["weight", "value", "carbs"]
train_df[numeric_cols] = scaler.fit_transform(train_df[numeric_cols].fillna(0))

5. 转换为张量

根据你的模型类型(时序模型/普通MLP),选择不同的转换方式:

方式1:时序模型(如LSTM)输入

按患者分组,构建时序序列并做padding:

# 按患者分组,每个组内按时间排序
patient_groups = train_df.groupby("patient_id")
sequences = []
feature_cols = ["insulin_type_encoded", "meal_type_encoded", "weight", "value", "carbs"]

for _, group in patient_groups:
    sorted_group = group.sort_values("ts")
    seq_tensor = torch.tensor(sorted_group[feature_cols].values, dtype=torch.float32)
    sequences.append(seq_tensor)

# 对序列做padding,统一长度
padded_sequences = pad_sequence(sequences, batch_first=True)
# padded_sequences形状:[患者数量, 最长序列长度, 特征数量]

方式2:普通MLP输入

把每个事件作为独立样本,直接转换:

train_features = train_df[feature_cols].values
train_tensor = torch.tensor(train_features, dtype=torch.float32)
# train_tensor形状:[事件总数, 特征数量]

6. 输入模型示例

以LSTM为例,简单搭建模型并输入数据:

class T1DMLSTM(nn.Module):
    def __init__(self, input_size, hidden_size, num_layers, output_size):
        super().__init__()
        self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True)
        self.fc = nn.Linear(hidden_size, output_size)
    
    def forward(self, x):
        out, _ = self.lstm(x)
        # 取每个序列最后一个时间步的输出做预测
        return self.fc(out[:, -1, :])

# 初始化模型
model = T1DMLSTM(input_size=padded_sequences.shape[2], hidden_size=64, num_layers=2, output_size=1)
# 前向传播
output = model(padded_sequences)

内容的提问来源于stack exchange,提问作者Pegtomous

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 13:47:48