python批量读取心电xml格式数据,提取心电值每个通道按列保存到txt中

该Python代码用于从心电科住院部的心电图机XML数据中,批量提取II、III、V1至V6通道的心电信号,以500Hz采样率和30s时长。数据经过处理后,按列保存到以XML文件名命名的TXT文件中,便于后续分析使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

心电数据来自心电科住院部心电图机,原始数据格式为xml,保存在如下ecgData文件夹下,采样率 500Hz,采集时长均为30s,每份样本具有完整12导联心电信号。
在这里插入图片描述
每个xml格式心电文件内容如下:
在这里插入图片描述
在这里插入图片描述
每个导联包括导联名称和心电数值(digits),心电数值有正负数值,数值之间以空格隔开。
需求:批量提取每个xml格式中的心电数值和通道名称,提取I II V1 V2 V3 V4 V5 V6通道下的数据,批量保存到txt文件内,txt文件名以xml文件命名,每个通道的心电数值在txt中按列保存,不同通道之间以空格分开。
python代码如下:

# -*- coding:utf-8 -*-

import csv
import re
import os
from xml.dom import minidom

def readXML():
    xml_filepath = "ecgData/"  # 存放所有心电xml文件
    txt_filepath = "xml_txt/"  # 截取标注数据保存的csv文件路径
    file_name_list = os.listdir(xml_filepath)
    for xml_name in file_name_list:
        # print("xml_name: ", xml_name)
        txt_name = xml_name.split(".")[0] + ".txt"         # RESTINGBATCHETYYXGNK0895820211019101323816.xml
        print(txt_name)
    # 打开xml文档
    # dom = minidom.parse("ecgData/RESTINGBATCHETYYXGNK0895820211008083641980.xml")  # parse用于打开一个XML文件
        dom = minidom.parse(xml_filepath+xml_name)  # parse用于打开一个XML文件
        # 得到文档元素对象
        # root = dom.documentElement  # documentElement用于得到XML文件的唯一根元素
        # print(root.nodeName)             # nodeName为节点名称
        # digits = root.getElementsByTagName('digits')
        digits = dom.getElementsByTagName('digits')
        MDC_ECG_LEAD_I_value = digits[0].firstChild.data  # firstChild属性返回被选节点的第一个子节点,data表示获取该节点的数据
        # print(MDC_ECG_LEAD_I_value)
        MDC_ECG_LEAD_II_value = digits[1].firstChild.data  # firstChild属性返回被选节点的第一个子节点,data表示获取该节点的数据
        # print(MDC_ECG_LEAD_II_value)
        # MDC_ECG_LEAD_III_value = digits[2].firstChild.data  # firstChild属性返回被选节点的第一个子节点,data表示获取该节点的数据
        # print(MDC_ECG_LEAD_III_value)
        # MDC_ECG_LEAD_aVR_value = digits[3].firstChild.data  # firstChild属性返回被选节点的第一个子节点,data表示获取该节点的数据
        # print(MDC_ECG_LEAD_aVR_value)
        # MDC_ECG_LEAD_aVL_value = digits[4].firstChild.data  # firstChild属性返回被选节点的第一个子节点,data表示获取该节点的数据
        # print(MDC_ECG_LEAD_aVL_value)
        # MDC_ECG_LEAD_aVF_value = digits[5].firstChild.data  # firstChild属性返回被选节点的第一个子节点,data表示获取该节点的数据
        # print(MDC_ECG_LEAD_aVF_value)
        MDC_ECG_LEAD_V1_value = digits[6].firstChild.data  # firstChild属性返回被选节点的第一个子节点,data表示获取该节点的数据
        # print(MDC_ECG_LEAD_V1_value)
        MDC_ECG_LEAD_V2_value = digits[7].firstChild.data  # firstChild属性返回被选节点的第一个子节点,data表示获取该节点的数据
        # print(MDC_ECG_LEAD_V2_value)
        MDC_ECG_LEAD_V3_value = digits[8].firstChild.data  # firstChild属性返回被选节点的第一个子节点,data表示获取该节点的数据
        # print(MDC_ECG_LEAD_V3_value)
        MDC_ECG_LEAD_V4_value = digits[9].firstChild.data  # firstChild属性返回被选节点的第一个子节点,data表示获取该节点的数据
        # print(MDC_ECG_LEAD_V4_value)
        MDC_ECG_LEAD_V5_value = digits[10].firstChild.data  # firstChild属性返回被选节点的第一个子节点,data表示获取该节点的数据
        # print(MDC_ECG_LEAD_V5_value)
        MDC_ECG_LEAD_V6_value = digits[11].firstChild.data  # firstChild属性返回被选节点的第一个子节点,data表示获取该节点的数据
        # print(MDC_ECG_LEAD_V6_value)
        # print(type(MDC_ECG_LEAD_V6_value))          <class 'str'>

        # I通道
        MDC_ECG_LEAD_I_value = re.split('\s+', MDC_ECG_LEAD_I_value)  # 将字符串i以全部空白字符为分割符,将其分割成一个字符列表
        new_MDC_ECG_LEAD_I_value = ','.join(MDC_ECG_LEAD_I_value)  # 将字符列表用','拼接成一个新字符串
        new_MDC_ECG_LEAD_I_value = new_MDC_ECG_LEAD_I_value.strip(',')  # 将新字符串尾部产生的','去掉
        list_new_MDC_ECG_LEAD_I_value = new_MDC_ECG_LEAD_I_value.split(',')  # 按照,分隔成列表
        list_new_MDC_ECG_LEAD_I_value_int = [int(i) for i in list_new_MDC_ECG_LEAD_I_value]
        print(list_new_MDC_ECG_LEAD_I_value_int)

        # II通道
        MDC_ECG_LEAD_II_value = re.split('\s+', MDC_ECG_LEAD_II_value)  # 将字符串i以全部空白字符为分割符,将其分割成一个字符列表
        new_MDC_ECG_LEAD_II_value = ','.join(MDC_ECG_LEAD_II_value)  # 将字符列表用','拼接成一个新字符串
        new_MDC_ECG_LEAD_II_value = new_MDC_ECG_LEAD_II_value.strip(',')  # 将新字符串尾部产生的','去掉
        list_new_MDC_ECG_LEAD_II_value = new_MDC_ECG_LEAD_II_value.split(',')  # 按照,分隔成列表
        list_new_MDC_ECG_LEAD_II_value_int = [int(i) for i in list_new_MDC_ECG_LEAD_II_value]
        print(list_new_MDC_ECG_LEAD_II_value_int)

        # V1通道
        MDC_ECG_LEAD_V1_value = re.split('\s+', MDC_ECG_LEAD_V1_value)  # 将字符串i以全部空白字符为分割符,将其分割成一个字符列表
        new_MDC_ECG_LEAD_V1_value = ','.join(MDC_ECG_LEAD_V1_value)  # 将字符列表用','拼接成一个新字符串
        new_MDC_ECG_LEAD_V1_value = new_MDC_ECG_LEAD_V1_value.strip(',')  # 将新字符串尾部产生的','去掉
        list_new_MDC_ECG_LEAD_V1_value = new_MDC_ECG_LEAD_V1_value.split(',')  # 按照,分隔成列表
        list_new_MDC_ECG_LEAD_V1_value_int = [int(i) for i in list_new_MDC_ECG_LEAD_V1_value]
        print(list_new_MDC_ECG_LEAD_V1_value_int)

        # V2通道
        MDC_ECG_LEAD_V2_value = re.split('\s+', MDC_ECG_LEAD_V2_value)  # 将字符串i以全部空白字符为分割符,将其分割成一个字符列表
        new_MDC_ECG_LEAD_V2_value = ','.join(MDC_ECG_LEAD_V2_value)  # 将字符列表用','拼接成一个新字符串
        new_MDC_ECG_LEAD_V2_value = new_MDC_ECG_LEAD_V2_value.strip(',')  # 将新字符串尾部产生的','去掉
        list_new_MDC_ECG_LEAD_V2_value = new_MDC_ECG_LEAD_V2_value.split(',')  # 按照,分隔成列表
        list_new_MDC_ECG_LEAD_V2_value_int = [int(i) for i in list_new_MDC_ECG_LEAD_V2_value]
        print(list_new_MDC_ECG_LEAD_V2_value_int)

        # V3通道
        MDC_ECG_LEAD_V3_value = re.split('\s+', MDC_ECG_LEAD_V3_value)  # 将字符串i以全部空白字符为分割符,将其分割成一个字符列表
        new_MDC_ECG_LEAD_V3_value = ','.join(MDC_ECG_LEAD_V3_value)  # 将字符列表用','拼接成一个新字符串
        new_MDC_ECG_LEAD_V3_value = new_MDC_ECG_LEAD_V3_value.strip(',')  # 将新字符串尾部产生的','去掉
        list_new_MDC_ECG_LEAD_V3_value = new_MDC_ECG_LEAD_V3_value.split(',')  # 按照,分隔成列表
        list_new_MDC_ECG_LEAD_V3_value_int = [int(i) for i in list_new_MDC_ECG_LEAD_V3_value]
        print(list_new_MDC_ECG_LEAD_V3_value_int)

        # V4通道
        MDC_ECG_LEAD_V4_value = re.split('\s+', MDC_ECG_LEAD_V4_value)  # 将字符串i以全部空白字符为分割符,将其分割成一个字符列表
        new_MDC_ECG_LEAD_V4_value = ','.join(MDC_ECG_LEAD_V4_value)  # 将字符列表用','拼接成一个新字符串
        new_MDC_ECG_LEAD_V4_value = new_MDC_ECG_LEAD_V4_value.strip(',')  # 将新字符串尾部产生的','去掉
        list_new_MDC_ECG_LEAD_V4_value = new_MDC_ECG_LEAD_V4_value.split(',')  # 按照,分隔成列表
        list_new_MDC_ECG_LEAD_V4_value_int = [int(i) for i in list_new_MDC_ECG_LEAD_V4_value]
        print(list_new_MDC_ECG_LEAD_V4_value_int)

        # V5通道
        MDC_ECG_LEAD_V5_value = re.split('\s+', MDC_ECG_LEAD_V5_value)  # 将字符串i以全部空白字符为分割符,将其分割成一个字符列表
        new_MDC_ECG_LEAD_V5_value = ','.join(MDC_ECG_LEAD_V5_value)  # 将字符列表用','拼接成一个新字符串
        new_MDC_ECG_LEAD_V5_value = new_MDC_ECG_LEAD_V5_value.strip(',')  # 将新字符串尾部产生的','去掉
        list_new_MDC_ECG_LEAD_V5_value = new_MDC_ECG_LEAD_V5_value.split(',')  # 按照,分隔成列表
        list_new_MDC_ECG_LEAD_V5_value_int = [int(i) for i in list_new_MDC_ECG_LEAD_V5_value]
        print(list_new_MDC_ECG_LEAD_V5_value_int)

        # V6通道
        MDC_ECG_LEAD_V6_value = re.split('\s+', MDC_ECG_LEAD_V6_value)  # 将字符串i以全部空白字符为分割符,将其分割成一个字符列表
        new_MDC_ECG_LEAD_V6_value = ','.join(MDC_ECG_LEAD_V6_value)  # 将字符列表用','拼接成一个新字符串
        new_MDC_ECG_LEAD_V6_value = new_MDC_ECG_LEAD_V6_value.strip(',')  # 将新字符串尾部产生的','去掉
        list_new_MDC_ECG_LEAD_V6_value = new_MDC_ECG_LEAD_V6_value.split(',')  # 按照,分隔成列表
        list_new_MDC_ECG_LEAD_V6_value_int = [int(i) for i in list_new_MDC_ECG_LEAD_V6_value]
        print(list_new_MDC_ECG_LEAD_V6_value_int)

        fina_list = []
        fina_list.append(list_new_MDC_ECG_LEAD_I_value_int)
        fina_list.append(list_new_MDC_ECG_LEAD_II_value_int)
        fina_list.append(list_new_MDC_ECG_LEAD_V1_value_int)
        fina_list.append(list_new_MDC_ECG_LEAD_V2_value_int)
        fina_list.append(list_new_MDC_ECG_LEAD_V3_value_int)
        fina_list.append(list_new_MDC_ECG_LEAD_V4_value_int)
        fina_list.append(list_new_MDC_ECG_LEAD_V5_value_int)
        fina_list.append(list_new_MDC_ECG_LEAD_V6_value_int)

        with open(txt_filepath + xml_name.split(".")[0] + ".txt", "w", newline="") as cf:
            csvfile = csv.writer(cf, delimiter=' ')
            for column in zip(*[i for i in fina_list]):
                csvfile.writerow(column)
        cf.close()
        print("保存文件成功")

if __name__ == '__main__':
    readXML()

批量提取后的txt文件保存到如下xml_txt文件夹内,txt文件名以xml文件命名。
在这里插入图片描述
保存到txt中内容如下:
在这里插入图片描述

### 使用卷积神经网络处理心电图XML文件 #### 解析XML文件并提取有用的心电图数据 为了使用卷积神经网络(CNN)来处理心电图(ECG) XML文件中的数据,首先需要解析这些XML文件以获取其中的时间序信号和其他元数据Python库`xml.etree.ElementTree`可以帮助完成这一任务。 ```python import xml.etree.ElementTree as ET def parse_ecg_xml(file_path): tree = ET.parse(file_path) root = tree.getroot() ecg_data = [] for child in root.findall('.//Waveform/LeadData'): lead_value = [float(x.text) for x in child.find('AnalogData').findall('SampleValue')] ecg_data.append(lead_value) return ecg_data ``` 上述代码片段展示了如何读取特定路径下的XML文档,并从中抽取各个导联对应的采样表[^1]。 #### 准备输入张量供CNN训练 一旦获得了原始时间序形式的ECG记录,则需将其转换成适合于馈入到CNN架构的形式——通常是二维数组或图像表示法。一种常见的做法是将每条通道数据重塑为固定长度的一维向量;如果多条通道存在的话,则可以堆叠在一起形成三维矩阵作为单一样本实例的一部分。 ```python import numpy as np def prepare_input_tensor(ecg_records, target_length=5000): padded_records = [] for record in ecg_records: # 对较短的记录填充零至目标长度 if len(record) < target_length: padding_size = target_length - len(record) padded_record = np.pad(record, (0, padding_size), mode='constant') else: # 裁剪过长的记录使其匹配目标长度 padded_record = record[:target_length] padded_records.append(padded_record) input_tensor = np.array(padded_records).reshape(-1, 1, target_length) return input_tensor ``` 这里定义了一个辅助函数用于调整所有样本尺寸一致以便后续操作。 #### 构建适用于一维信号的CNN模型结构 考虑到ECG属于典型的一维连续波形而非传统意义上的图片资料,在设计网络层时应特别注意选用能够有效捕捉局部特征模式的一维卷积核。下面给出了一种简单的基于Keras框架搭建此类专用型CNN的例子: ```python from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Conv1D, MaxPooling1D, Flatten, Dense, Dropout model = Sequential([ Conv1D(filters=64, kernel_size=7, activation='relu', input_shape=(None, 5000)), MaxPooling1D(pool_size=2), Conv1D(filters=64, kernel_size=5, activation='relu'), MaxPooling1D(pool_size=2), Flatten(), Dense(units=128, activation='relu'), Dropout(rate=0.5), Dense(units=num_classes, activation='softmax') # num_classes取决于具体应用场景所需的类别数 ]) model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) ``` 这段脚本创建了一个具有两层卷积运算加上全连接分类器的标准拓扑配置,同时设置了Adam优化算法与交叉熵损失度量标准。 #### 训练过程及评估指标设定 最后一步就是利用准备好的训练集对所建立起来的模型实施迭代更新直至收敛稳定为止。期间还需定期保存最佳权重参数副本以防后期回滚调优之需。此外,建议引入验证子集用来监控泛化性能表现以免发生过度拟合现象。 ```python history = model.fit(X_train, y_train, epochs=epochs, batch_size=batch_size, validation_split=validation_ratio, callbacks=[checkpoint_callback]) ``` 以上即为整个流程概述,涵盖了从初步导入直至最终部署上线所需经历的主要环节。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值