精华内容
下载资源
问答
  • 心跳信号分类预测
    2021-11-24 14:59:37

    导入相关库:(加了一个测试时间的)

    读写入数据:

    训练训练集和测试集:

    设计模型和输出验证集:

    def abs_sum(y_pre, y_tru):
        loss = sum(sum(abs(y_pre - y_tru)))
        return loss
    
    
    clf = LGBMClassifier(
        learning_rate=0.1,  # 0.05
        n_estimators=10230,
        num_leaves=31,
        max_depth=7,
        subsample=0.8,
        colsample_bytree=0.8,
        metric=None,
        objective='multiclass'
    )
    answers = []
    mean_score = 0
    onehot_encoder = OneHotEncoder(sparse=False)
    sk = StratifiedKFold(n_splits=10, shuffle=True, random_state=2019)
    for train, testA in sk.split(train_x, target):
        x_train = train_x.iloc[train]
        y_train = target.iloc[train]
        x_test = train_x.iloc[testA]
        y_test = target.iloc[testA]
    
        clf.fit(x_train, y_train, eval_set=[(x_test, y_test)], verbose=100,
                early_stopping_rounds=100)
        y_pre = clf.predict(x_test)
        y_test = np.array(y_test).reshape(-1, 1)
        y_test = onehot_encoder.fit_transform(y_test)
    
        y_pre = np.array(y_pre).reshape(-1, 1)
        y_pre = onehot_encoder.fit_transform(y_pre)
    
        print('lgb验证的auc:{}'.format(abs_sum(y_test, y_pre)))
        mean_score += abs_sum(y_test, y_pre) / 10
        y_pred_valid = clf.predict_proba(test1)
        answers.append(y_pred_valid)
    print('mean valAuc:{}'.format(mean_score))
    lgb_pre = sum(answers) / 10
    re = pd.DataFrame(lgb_pre)
    result = pd.read_csv('E:/yangben1/sample_submit.csv')
    result['label_0'] = re[0]
    result['label_1'] = re[1]
    result['label_2'] = re[2]
    result['label_3'] = re[3]
    result.to_csv('E:/yangben31/submit.csv', index=False)
    end = time.time()
    print (end-start)

    总结:

    此算法在心跳信号分类预测-baseline中正确率、训练时间、绝对值误差都是比较好的,在后期的优化上可以更好。(新人入坑)

     

     

     

     

    更多相关内容
  • 天池-零基础入门数据挖掘-心跳信号分类预测-EDA分析全过程-代码
  • 零基础入门数据挖掘-心跳信号分类预测-386分-33名 代码.rar
  • 天池入门赛-心跳信号分类预测-PyTorch CNN模型 B榜16
  • 心跳信号分类预测处理分享

            前些时间,做了个阿里天池的练习赛,心跳预测。说是练习赛,实际也没赛,因为最后的结果也没拿去提交、上传之类的,最后做了个小展示,权当做练手,在这里和大家分享一下整体的思路,希望可以给后来者一些启发。期待可以和大家一起沟通交流,指出不足之处,相互学习,共同进步。

            先回顾一下先前的题目:

            数据集见下面链接,也不用大家花C币了,直接在下面链接就能下载。

            零基础入门数据挖掘-心跳信号分类预测赛题与数据-天池大赛-阿里云天池

    一、赛题数据

    赛题以预测心电图心跳信号类别为任务,数据集报名后可见并可下载,该数据来自某平台心电图数据记录,总数据量超过20万,主要为1列心跳信号序列数据,其中每个样本的信号序列采样频次一致,长度相等。为了保证比赛的公平性,将会从中抽取10万条作为训练集,2万条作为测试集A,2万条作为测试集B,同时会对心跳信号类别(label)信息进行脱敏。

    字段表

    FieldDescription
    id为心跳信号分配的唯一标识
    heartbeat_signals心跳信号序列
    label心跳信号类别(0、1、2、3)

    二、评测标准

    选手需提交4种不同心跳信号预测的概率,选手提交结果与实际心跳类型结果进行对比,求预测的概率与真实值差值的绝对值(越小越好)。

    具体计算公式如下:

    针对某一个信号,若真实值为[y_1,y_2,y_3,y_4][y1​,y2​,y3​,y4​],模型预测概率值为[a_1,a_2,a_3,a_4][a1​,a2​,a3​,a4​],那么该模型的平均指标abs-sumabs−sum为
    {abs-sum={\mathop{ \sum }\limits_{{j=1}}^{{n}}{{\mathop{ \sum }\limits_{{i=1}}^{{4}}{{ \left| {y\mathop{{}}\nolimits_{{i}}-a\mathop{{}}\nolimits_{{i}}} \right| }}}}}}abs−sum=j=1∑n​i=1∑4​∣yi​−ai​∣
    例如,心跳信号为1,会通过编码转成[0,1,0,0][0,1,0,0],预测不同心跳信号概率为[0.1,0.7,0.1,0.1][0.1,0.7,0.1,0.1],那么这个预测结果的abs-sumabs−sum为
    {abs-sum={ \left| {0.1-0} \right| }+{ \left| {0.7-1} \right| }+{ \left| {0.1-0} \right| }+{ \left| {0.1-0} \right| }=0.6}abs−sum=∣0.1−0∣+∣0.7−1∣+∣0.1−0∣+∣0.1−0∣=0.6     

      

    三、结果提交

    提交前请确保预测结果的格式与sample_submit.csv中的格式一致,以及提交文件后缀名为csv。

    形式如下:

    id,label_0,label_1,label_2,label_3
    100000,0,0,0,0
    100001,0,0,0,0
    100002,0,0,0,0
    100003,0,0,0,0

            原本题目中还有提交结果,我在这里只做了前两部分。

            接下来具体将从处理分析数据、构建模型、结果分析以及对模型的改进与优化四个方面阐述。


      一、数据处理    

            首先,拿到原始数的后,先查看了数据的大致情况,查看数据的形式、数量,以便确定后续的处理方法。

            100000条数据,每条数据内是由","划分的205个数据,要想对其进行处理,首先要对数据进行分列重组,以便进行后续处理。(个人习惯将标签放到前面)

    data=pd.read_csv('C:\\Users\\LFY\\Desktop\\\\train0.csv')
    
    data.head()
    
    data1 = data['heartbeat_signals'].str.split(',', expand=True)   # 将数据按‘,’拆分
    new_names = ['signals_' + str(x + 1) for x in range(205)]   # 为新生成的列取名
    data1.columns = new_names  # 重命名新生成的列名
    data1["label"] = data["label"]  #加入标签列
    data1 = pd.DataFrame(data1,dtype=np.float64)    # 转化为数组形式
    
    #把label移到最前面
    
    col=list(data1)
    col.index('label')
    col.insert(0,col.pop(col.index('label')))
    data2=data1.loc[:,col]
    

            将数据拆分后,更容易观察数据的特征。用data.head()查看数据,进而对数据进行探索性分析(对数据不明所以,所以先做个图看看)

            观察数据可知,这个波形类似于心电图,结合题目背景,猜想每条数据可能都是取自某导联的一段心电图。无独有偶,心电监测的采样频率正是12000Hz,折合到每秒采样200次,与每条数据的205个值非常接近。由此,我们有理由猜测,该数据主要是一个心电检测12000Hz,每秒200个采样点,数据规模为100000条*205个维度的心跳数据。该数据集很可能是一个十万段长度为一秒左右的心跳数据。

            对数据集中的训练集进行简单的处理后发现不存在缺失值与异常值,对各个类别样本进行统计。发现样本存在两个较为明显的问题。

    1.样本不平衡

            对于分类模型而言,样本不均衡的问题很重要。标签为0类、1类、2类、3类的样本分别有64327、3562、14199、17912条。第0类的占比64.327%,但第1类的仅占总样本数的3.562%,样本数最多的第0类是样本数最少的第1类的将近20倍,这就导致了模型会学习到训练集中这种不均衡样本比例的先验信息,以至于在实际预测时就会对多数类别有侧重。故需要对样本不平衡问题先进行处理。

            在数据处理时需要对训练集进行数据增强和扩增,将样本数量较少的那些类中加工出更多数据的表示,提高原数据集的数量及质量,从而提高模型的学习效果。因此需要将第1类、第2类、第3类的样本进行扩增,使各类样本数达到均衡。

            由于原始数据是心电数据,因此采用Scale(缩放)处理的方法。该方法的本质是根据某一类随时间变化的心跳的波形,对其进行一个缩放作用,从而生成一个新的数据但不改变其波峰波谷的这些特征本质。最终进行样本扩增后,四个类别的样本数基本一致。

    scale的实现也很简单,代码如下:

    def DA_Scaling(X, sigma=0.1):
        scalingFactor = np.random.normal(loc=1.0, scale=sigma, size=(1,X.shape[1])) 
        myNoise = np.matmul(np.ones((X.shape[0],1)), scalingFactor)
        return X*myNoise

    具体过程如下,以一类样本扩充为例:一类样本做数据增强后,样本量扩增了16倍,数量基本与0类样本大致接近

    ​
    #对标签为1的样本进行数据增强
    idxs = data3.query('label==1').index
    datmp = data3.iloc[idxs,:].reset_index(drop=True)
    datmp['label'] = 1
    data11=DA_Scaling(datmp, sigma=0.1)
    for ii in np.arange(16):
        data11 = pd.concat((data11, datmp), axis=0).reset_index(drop=True)
    data11['label']=1
    
    ​#打乱数据,使得不同标签样本均匀混合
    data_train = data_train.sample(frac=1, random_state=2022).reset_index(drop=True)

    二、三类样本扩充同理,扩增至与0类样本数量相近

    扩增之后的各类样本数量如下:

    数据增强后的均衡数据集

    类别

    样本数

    0类

    22404

    1类

    22164

    2类

    24584

    3类

    30850

    2.数据末尾持续0

            部分数据中的末尾部分持续为0,对此异常情况推测是进行心跳采样时还没有到1秒钟的情况下,就摘下电极片,摘下后数据都为0,而这部分持续为0的维度本不是心跳的特征,因此在数据处理时将其剔除。具体处理方式为:先将末尾的0转化为NaN,再将原本行数据转化为列,每个时间

    
    #数据处理:删去样本末尾的0,转为NaN
    def assign_nan(data):
        nptmp = data.to_numpy()
        #    print(nptmp.shape)
    
        left_idxs = np.arange(nptmp.shape[0])
        for ii in np.arange(nptmp.shape[1])[::-1]:
            idxs = np.where(nptmp[left_idxs, ii] <= 1.e-5)[0]
            if idxs.size > 0:
                nptmp[left_idxs[idxs], ii] = np.nan
                left_idxs = left_idxs[idxs]
            #            print(f'{ii}: {left_idxs.size}, |, {left_idxs}')
            else:
                #            print(f'Finished at {ii}')
                break
    
        # nptmp[:, :2] = np.nan
        return pd.DataFrame(nptmp[:,:], index=data.index, columns=data.columns[:])
    
    data3=assign_nan(data2)
    
    # 对心电特征进行行转列处理,同时为每个心电信号加入时间步特征time
    train_heartbeat_df = data_train.iloc[:,1:].stack()
    train_heartbeat_df = train_heartbeat_df.reset_index()
    train_heartbeat_df.rename(columns={"level_0":"id","level_1":"time", 0:"heartbeat_signals"}, inplace=True)
    
    train_heartbeat_df["heartbeat_signals"] = train_heartbeat_df["heartbeat_signals"].astype(float)
    

            得到的数据如下图所示,第一列为代表样本编号的id,第二列为对应的时间 ,从signals_1到signals_205分别对应205个时间节点。heartbeat_signals为对应时间的心电信号

    而此时的心电信号为0的行已在之前就被转化为NaN,在转化为列数据的时候,被删除掉了,如下图所示,id为12029的心电信号在135之后的信号值都为0,故被剪去。

     处理完数据的不平衡问题和末尾为0的问题后,数据的基本预处理已经完成,进入到下一部分——特征提取

    3.特征提取 

            因为数据本身的特点——时间序列数据,故考虑使用时间序列特征提取包:tsfresh进行特征提取

            在tsfresh中,内置了三种特征提取方案,我们可以根据实际情况,去选择不同的特征组合进行提取。除了已经预设的特征组合外,还可以自定义特征组合方式,提取指定的特征。

    在这里我使用的是 ComprehensiveFCParameters这一组合,具体其他组合也在这里提供给大家,任选其一即可,我在这里都放出来,以供大家选取使用。

            tips:建议大家在提取特征后,直接就把提取到的特征存下来,因为提取的过程真的蛮久,提取之后,可以直接用存下来的特征去进行之后的步骤,而不用每次都重复这个提取过程

    
    #不同特征提取组合
    settings = ComprehensiveFCParameters()
    
    settings  =  MinimalFCParameters ()
    
    settings  =  EfficientFCParameters()
    
    
    #设置所提取的特征
    fc_parameters={
        "length":None,
        "large_standard_deviation":[{"r": 0.05}, {"r": 0.1}],
        "abs_energy":None,
        "absolute_sum_of_changes":None,
        "agg_linear_trend":[{"f_agg":'mean','attr': 'pvalue', 'chunk_len': 2}]
    }
    
    #对应的label
    data_label=data_train1.iloc[:,0]
    #提取默认特征
    train_features=extract_relevant_features ( train_heartbeat_df ,data_label,column_id='id', column_sort='time',  default_fc_parameters = settings )
    #提取指定特征
    # train_features=extract_features ( train_heartbeat_df ,column_id='id', column_sort='time',  default_fc_parameters=fc_parameters )
    #所提取出的特征
    train_features
    #保存特征
    train_features.to_csv("100000_statistics_feature.csv")

    提取保存完特征之后,就可以用所提取的特征进行建模了

    二、模型构建

            具体模型选择随机森林。期中最大的决策树个数为500棵,损失函数选择信息增益,最大特征数为划分时最多考虑n个特征,决策树的最大深度为20,最小叶子节点为1。其他参数均设置为默认数值。

             由于提取到的特征维度较高,直接输入模型会导致模型运行时间过长。故先对提取得到的特征维度进行降维,再输入模型中。具体使用PCA来进行降维

    features=pd.read_excel(r'C:\Users\LFY\Desktop\fea.xlsx')
    pca=PCA(n_components=39) # 取前39个主成分
    features=features.iloc[:,-39:]
    min_max_normalizer=preprocessing.MinMaxScaler(feature_range=(0,1))
    features=min_max_normalizer.fit_transform(features)
    a=pca.fit(features)
    results=pca.transform(features)
    print(pca.explained_variance_ratio_) # 方差贡献率
    #print(results) # 降维后的数据
    data=pd.DataFrame(results)

    将降维后的数据输入到随机森林模型中,进行分类

    利用准确率、召回率、精确度、F1分数、混淆矩阵、ROC曲线来评价该预测模型的性能。最终结果为:准确率为0.956、召回率为0.955、精确度为0.955、F1分数为0.932。(重复运行5次的平均值)。混淆矩阵如下图所示。不调参时由于没有设置随机森林的深度,导致模型过拟合,在经过调整参数后选择模型的深度为20取得不错的效果。通过结果可以看出模型总的准确率为0.956

     三、结果分析

            模型最后的分类准确率为95.6%(重复运行5次的平均值),平均运行时间时长为561秒。对于疾病类判别的问题,相较于分类正确的样本,我们往往更关注于被错判的样本。

            分析错误的样本能帮住我们找到先前工作中被忽略的部分。分析每一类的特点,首先了解心电图的组成部分,它包括有P波、QRS波、T波、PR段、ST段等。P波是每一组中的第一波,它是由心房除极所产生。QRS波代表两心室除极和最早期复位过程的电位和时间变化。在标准情况下,ST段水平线是以PR段为基线的延长线。正常人的ST段应在等电位线上,有时存在一些轻微的偏移。一次正常的心跳是从P波开始,之后是QRS波,最后是T波。

     第1类心跳信号示例图

            观察第1类如图6所示,该图在TP段间有异常抖动现象,甚至看不清P波的基线,这种情况可能为心房纤颤。

     第2类心跳信号示例图

           观察第2类,如上图所示,QRS波振幅较小而频率高,波形较为抖动,可能为室性心动过速。

    第3类心跳信号示例图

            第3类如上图所示,P波段在图8中几乎观察不到,缺少P波,可能为房室结性早搏。

            下面对错判成的三个类别分别进行分析。首先是被错判为第1类的样本均值,如下图所示。

     错判为1类的样本分布图

            上图是当真实标签并不是1类时被模型错判为1类的心电图每个维度的平均值的图。观察正常第1类可以发现基本上看不到P波的基线,一直处于一个向上波动的姿态,且在第76到第126维度上即对应的TP段出现了异常抖动的现象。这些都是典型的第1类即心房纤颤的特征。第0类被错判为第1类的心电图中可以明显看到同样是在第76到126维心跳出现剧烈的波动,且P波同样不明显,因此可以推测模型学到的第1类的特征主要就是在第1维到第50维的P波不明显以及第76到126维上的剧烈波动。观察第2类和第3类被错判为第1类的图可以获得在对这些样本分类时,模型主要是因为P波找不到基线而将其错判为1类。总结可获得模型对第1类所学到的特征着重关注于P波的基线是否可观察。

            其次是被错判为第2类的样本均值,如下图所示。

     错判为2类的样本分布图

            被错判为第2类的样本的心电图每个维度的平均值如上图所示,正常情况下第2类所表现出的特征可以看出是从第3到第101维心电数据的QRS波较为抖动,且在这一秒的波形中基本都有抖动情况,被诊断为室性心动过速。观察原始第0类、原始第1类、原始第2类都可以看出他们被错判的主要原因也是由于出现了这一特征,它们的波形都存在着QRS波较小但频率较高的情况,可以推测模型对于第2类心电图所学到的特征主要就是在中间部分QRS波的抖动。

            最后是被错判为第3类的样本均值,如下图所示。

    错判为3类的样本分布图

            被错判为第3类的样本的心电图每个维度的平均值如图11所示,正常情况下第3类表现出来的特征为缺少P波即在51维前看不到一个较缓的波谷,观察被错判的另外几个类别都出现了这种情况,即模型对第三类所学习到的特征推测是前51维没有明显的P波存在。

            综上,对于被错判的样本我们可以做出推测是因为它们表现出了其他类型所具有的特征,而这个特征又恰巧是模型较为关注的特征,因此出现样本病例被错判的情况。

    四、改进与优化

    角度1. 本模型基础上进行优化,增加医学方面的先验知识

            由于模型会出现过分的关注数据中的某些重点特征或由于数据处理不是很充分也可能会学习到一些不好的特征,从而导致将类别错判,为解决这个问题,可以在建立模型时给模型添加一个先验知识,让模型学习到一些关键的特征,例如在本文中可以加入一些心电数据更加关注的特征。另外还可以在构建模型是运用多模态的方法,即可以再加入一个视觉模态之类的,通过多方面的信息来判断病人到底是什么病症,这也是提高模型预测准确度的一个方法。

    角度2. 尝试使用更多的模型

            目前,只使用了PCA进行降维,还可以考虑其他一些实用的降维方法,譬如GA遗传算法等方法;建模方面除了随机森林外,还有很多经典的分类模型也可以使用。

    角度3. 在可视化方面,增加热力图等图形

    五、总结与致谢

    在此感谢我的导师和我的舍友们,没有你们的帮助,这个作品绝不会是现在的样子(虽然现在也很稚拙)但我们一起努力的时候,真的很快乐呀,跟着大佬们每天都学到非常多,幸甚至哉!

    展开全文
  • 【天池】零基础入门数据挖掘-心跳信号分类预测(GPU版本) 本文献给Python初学者,里面的编程方式还比较稚嫩,欢迎提出宝贵意见。如果在GPU运行过程中遇到问题,欢迎留言交流。文中的程序部分借鉴了天池中两位大神的...

    【天池】零基础入门数据挖掘-心跳信号分类预测(GPU版本)

    为什么要写这篇文章?

    本文献给Python初学者,里面的编程方式还比较稚嫩,欢迎提出宝贵意见。如果在GPU运行过程中遇到问题,欢迎留言交流。文中的程序部分借鉴了天池中两位大神的代码,向两位致敬。欢迎链接过去Star他们。
    【心跳信号分类预测】冠军攻略–小小靓仔
    零基础入门数据挖掘-心跳信号分类预测_top5思路–余睿
    这是一个天池长期赛,目前这个代码最好成绩是217名,还未上榜。会在这和大家持续更新排名进展。个人主要是无线通信+AI方向,后面多分享这个方向的。

    赛题背景

    赛题以心电图心跳信号数据为背景,要求选手根据心电图感应数据预测心跳信号所属类别,其中心跳信号对应正常病例以及受不同心律不齐和心肌梗塞影响的病例,这是一个多分类的问题。通过这道赛题来引导大家了解医疗大数据的应用,帮助竞赛新人进行自我练习、自我提高。
    赛题链接
    Alt

    赛题分析

    这是机器学习中的监督学习问题,所有标签已经打好,信号已经标准化在0-1之间,是一个典型的多分类问题(四分类)。人体信号中比较麻烦的是信号预处理和标准化等,这个属于入门赛,已经先帮助选手消化好了。但实际做项目可就没有这么幸运了,可能这就是入门赛和实际工作中项目之间的差异之一吧。
    医疗数据中还有一个特点是正常样本多,病患样本少。这个问题在本赛题中也体现出来了。正常样本(分类1)超过了10000例,而某种心脏疾病的病例数才几百例。这也是分类问题中经常遇到的,最好对小样本进行数据增强,稍后验证有效的方法出来后再补充。
    Alt

    赛题环境

    pytorch 1.8.1
    python 3.8
    cuda 11.2
    cudnn 8.1.0
    硬件 RTX 3060
    神州战神Z8游戏本

    代码剖析

    虽然目前该代码仅排名217/3749,这个代码主要是为初学者展示代码结构,降低入门门槛。因为是长期赛,排名会和大家实时更新。

    导入资源包,初始化参数

    import numpy as np
    import torch
    import csv
    ...
    
    batch_size = 256
    train_split = 0.9
    valid_split = 0.1
    patient = 20
    epo = 130

    训练集验证集划分常规操作(这部分代码要感谢余睿)

    # 定义数据适配器,用于加载数据至pytorch框架
    class DataAdapter(Data.Dataset):
    
        def __init__(self,X,Y):
            super(DataAdapter,self).__init__()
            self.X = torch.FloatTensor(X)
            self.Y = torch.LongTensor(Y)
    
        def __getitem__(self,index):
            return self.X[index,:],self.Y[index]
    
        def __len__(self):
            return len(self.X)
    
    
    def read_data(batch_size,train_split,valid_split):
    
        signal = []
        label = []
    
        train_data = r'./train.csv' # 训练文件路径
    
        weight = [0,0,0,0]
    
        with open(train_data,'r') as f:
            reader = csv.DictReader(f)
            for line in reader:
                signal.append([float(num) for num in line['heartbeat_signals'].split(',')])  # 滤波后的数据
                label.append(int(float(line['label'])))  # 标签
                weight[int(float(line['label']))] += 1  # 各标签的权重
    
        dataset = DataAdapter(signal,label) # 构造数据集
        train_size = int(len(signal) * train_split)
        valid_size = len(signal) - train_size
        train_dataset,valid_dataset = Data.random_split(dataset,[train_size,valid_size])  # 随机划分训练集和验证集
    
        train_loader = Data.DataLoader(train_dataset,batch_size = batch_size,shuffle = True,num_workers = 0) # 加载DataLoader
        valid_loader = Data.DataLoader(valid_dataset,batch_size = batch_size,shuffle = True,num_workers = 0)
    
        return train_loader,valid_loader,[len(label)/ii for ii in weight]
    
    # 定义该函数用于重新打乱训练集和验证集
    def shuffle_data(train_loader,valid_loader,valid_split,batch_size):
        train_dataset = train_loader.dataset.dataset # 获取训练集的数据集
        valid_dataset = valid_loader.dataset.dataset
        X = torch.cat((train_dataset.X,valid_dataset.X),0) # 拼接数据集
        Y = torch.cat((train_dataset.Y,valid_dataset.Y),0)
        dataset = DataAdapter(X,Y) # 重新生成数据集
        train_dataset,valid_dataset = Data.random_split(dataset,[len(dataset) - int(len(dataset)*valid_split),int(len(dataset)*valid_split)]) # 重新划分训练集和验证集
        train_loader = Data.DataLoader(train_dataset,batch_size = batch_size,shuffle = True,num_workers = 0)
        valid_loader = Data.DataLoader(valid_dataset,batch_size = batch_size,shuffle = True,num_workers = 0)
        return train_loader,valid_loader
    
    # 定义训练函数
    def train_model(train_loader, model, criterion, optimizer, device):
        model.train()
        train_loss = []
        train_acc = []
    
        for i, data in enumerate(train_loader, 0):
            # inputs,labels = data[0].cuda(),data[1].cuda()
            inputs, labels = data[0].cuda(), data[1].cuda()  # 获取数据
    
            outputs = model(inputs)  # 预测结果
    
            _, pred = outputs.max(1)  # 求概率最大值对应的标签
    
            num_correct = (pred == labels).sum().item()
            acc = num_correct / len(labels)  # 计算准确率
    
            loss = criterion(outputs, labels)  # 计算loss
            optimizer.zero_grad()  # 梯度清0
            loss.backward()  # 反向传播
            optimizer.step()  # 更新系数
    
            train_loss.append(loss.item())
            train_acc.append(acc)
    
        return np.mean(train_loss), np.mean(train_acc)
    
    # 定义测试函数,具体结构与训练函数相似
    def test_model(test_loader, criterion, model, device):
        model.eval()
        test_loss = []
        test_acc = []
    
        for i, data in enumerate(test_loader, 0):
            # inputs,labels = data[0].cuda(),data[1].cuda()
            inputs, labels = data[0].cuda(), data[1].cuda()
    
            outputs = model(inputs)
            loss = criterion(outputs, labels)
    
            _, pred = outputs.max(1)
    
            num_correct = (pred == labels).sum().item()
            acc = num_correct / len(labels)
    
            test_loss.append(loss.item())
            test_acc.append(acc)
    
        return np.mean(test_loss), np.mean(test_acc)

    这里CNN模型框架要感谢状元小小靓仔,个人修改了一下,结果变得像幼儿园小朋友写的了。希望大佬也可以多多指点,不吝赐教。对和我一样的初学者有一个好处就是比较易懂。

    # 定义模型结构
    class CNN(nn.Module):
    
        def __init__(self):
            super(CNN,self).__init__()
            self.conv1 = nn.Conv1d(in_channels = 1,out_channels = 16,kernel_size = 3,stride = 1,padding = 1)
            self.conv2 = nn.Conv1d(16,32,3,1,1)
            self.conv3 = nn.Conv1d(32,64,3,1,1)
            self.conv4 = nn.Conv1d(64,64,5,1,2)
            self.conv5 = nn.Conv1d(64,128,5,1,2)
            self.conv6 = nn.Conv1d(128,128,5,1,2)
            self.maxpool = nn.MaxPool1d(3,stride=2)
            self.relu = nn.ReLU()
            self.sigmoid = nn.Sigmoid()
            self.softmax = nn.Softmax(dim=1)
            self.dropout = nn.Dropout(0.5)
            self.flatten = nn.Flatten()
            self.fc1 = nn.Linear(6400,256)
            self.fc21 = nn.Linear(6400,16)
            self.fc22 = nn.Linear(16,256)
            self.fc3 = nn.Linear(256,4)
    
        def forward(self,x):
            x = x.view(x.size(0),1,x.size(1))
            x = self.conv1(x)   #nn.Conv1d(in_channels = 1,out_channels = 32,kernel_size = 11,stride = 1,padding = 5)
            x = self.relu(x)
            x = self.conv2(x)
            x = self.relu(x)
            x = self.conv3(x)
            x = self.relu(x)
            x = self.conv4(x)
            x = self.relu(x)
            x = self.maxpool(x)
            x = self.conv5(x)
            x = self.relu(x)
            x = self.conv6(x)
            x = self.relu(x)
            x = self.maxpool(x)
            x = self.dropout(x)
            x = self.flatten(x)
            x1 = self.fc1(x)
            x1 = self.relu(x1)
            x21 = self.fc21(x)
            x22 = self.relu(x21)
            x22 = self.fc22(x22)
            x2 = self.sigmoid(x22)
            x = self.fc3(x1+x2)
            return x

    后面就是预测结果的代码。

    def predict_ali_testset(batch_size, model, device):
        '''
        该函数用于生成预测文件
        '''
        ipath = r'./'  # 输入数据文件路径
        opath = r'./'  # 输出提交文件路径
        signal = []
        ...

    以及主体代码__main__,这个框架可以用pycharm模板生成的。一般把def函数全都写到main前面去。GPU需要注意的就是把模型和数据都.cuda()。然后最终要从GPU取回到CPU。这块我也在借鉴代码阶段,不知道是否发挥了GPU3060全部潜能,还请多指教。

    if __name__ == '__main__':
    
        device = torch.device("cuda:1" if torch.cuda.is_available() else "cpu")
        print(device)
        model = CNN().cuda()  # 初始化模型,
        criterion = nn.CrossEntropyLoss()
        print('******start loading data******')
        start = time.time()
        train_loader, valid_loader, weight = read_data(batch_size, train_split, valid_split)
        early_stopping = EarlyStopping(patient, verbose=False)
        end = time.time()
        run = end - start
        print('[1]load: %.5f sec' % run)
        print('******start shuffling data******')
        train_loader, valid_loader = shuffle_data(train_loader,
                                                  valid_loader, valid_split, batch_size)  # 打乱训练集及验证集
    
        optimizer = optim.Adam(model.parameters(), lr=0.0001)  # 使用Adam优化算法
        clr = CosineAnnealingLR(optimizer, T_max=150)  # 使用余弦退火算法改变学习率
        best_loss = 10
        print('******start training model******')
        start = time.time()
        for epoch in range(epo):
            time_all = 0
            start_time = time.time()
            train_loss, train_acc = train_model(train_loader, model, criterion, optimizer, device)  # 训练模型
            clr.step()  # 学习率迭代
            time_all = time.time() - start_time
            valid_loss, valid_acc = test_model(valid_loader, criterion, model, device)  # 测试模型
            print('- Epoch: %d - Train_loss: %.5f - Train_acc: %.5f - Val_loss: %.5f - Val_acc: %5f - T_Time: %.3f 当前学习率:%f'
                  % (epoch, train_loss, train_acc, valid_loss, valid_acc, time_all, optimizer.state_dict()['param_groups'][0]['lr']))
    
            if valid_loss < best_loss:
                best_loss = valid_loss
                #print('Find better model in Epoch {0}, saving model.'.format(epoch))
                torch.save(model.state_dict(),'./best_model.pt')  # 保存最优模型
    
        torch.cuda.empty_cache()
        end = time.time()
        run = end - start
        print('[2]train: %.5f sec' % run)
    
        print('******start predicting data******')
    
        model = CNN()
        model.load_state_dict(torch.load('./best_model.pt'))  # 加载模型参数
        model.eval()
        model.cuda()
        predict_ali_testset(batch_size, model, device)  # 生成预测文件
        print('[3] prediction done')
        print('the end')

    Alt

    比赛成绩

    长期赛目前成绩217/3749,后面改进的方向将会是对CNN模型的修改,如何使CNN模型更加能够掌握心电信号特征。如何将信号物理模型融入AI模型,physics-based DNN是很有意思的学问,也是体现专业领域人士不被AI所替代裁员展现出来的最后的倔强。
    会实时和大家汇报比赛排名和更新算法,欢迎指点。
    Alt

    结束语

    您的支持将支付我GPU运行的电费账单,可以一直将喜欢的AI比赛进行下去。

    排名更新至194/3753
    排名更新至140/3755
    排名更新至97/3767
    排名更新至91/3804

    [1]https://doi.org/10.3390/diagnostics12030654
    [2]https://doi.org/10.1038/s41598-020-77599-6
    [3]ARRHYTHMIA CLASSIFICATION WITH HEARTBEAT-AWARE TRANSFORMER lepu医疗
    [4]http://dx.doi.org/10.1109/TBME.2015.2468589

    展开全文
  • 该数据包是从某平台下过来进行综合在一起的数据包,可用于机器学习预测和分析,通过不同算法来实现python代码既可,但该数据包类无python代码。有需要的可以联系小编。
  • 赛题以医疗数据挖掘为背景,要求选手使用提供的心跳信号传感器数据训练模型并完成不同心跳信号分类的任务。为了更好的引导大家入门,还特别为本赛题定制了学习方案,其中包括数据科学库、通用流程和baseline方案...

    1、赛题背景

    赛题以医疗数据挖掘为背景,要求选手使用提供的心跳信号传感器数据训练模型并完成不同心跳信号的分类的任务。为了更好的引导大家入门,还特别为本赛题定制了学习方案,其中包括数据科学库、通用流程和baseline方案学习三部分。

    通过对本方案的完整学习,可以帮助掌握数据竞赛基本技能。同时我们也将提供专属的视频直播学习通道。

    2、赛题数据

    赛题以预测心电图心跳信号类别为任务,数据集报名后可见并可下载,该数据来自某平台心电图数据记录,总数据量超过20万,主要为1列心跳信号序列数据,其中每个样本的信号序列采样频次一致,长度相等。为了保证比赛的公平性,将会从中抽取10万条作为训练集,2万条作为测试集A,2万条作为测试集B,同时会对心跳信号类别(label)信息进行脱敏。

    字段表

    Field: Description
    id : 为心跳信号分配的唯一标识
    heartbeat_signals: 心跳信号序列
    label: 心跳信号类别(0、1、2、3)

    在这里插入图片描述

    3、具体流程

    3.1 在天池官网下载数据

    在这里插入图片描述
    下载好的数据后有三个字段 id ,heartbeat_signalslabel

    3.2 绘制前10个id的图像

    由于心跳信号序列是一大串的数字,我们本身看不出什么信息。首先第一个想法就是把图像绘制出来。
    第一张图
    在这里插入图片描述
    第二张图
    在这里插入图片描述
    第三张图
    在这里插入图片描述
    前10张图
    在这里插入图片描述
    绘图代码如下:

    import pandas as pd
    import matplotlib.pyplot as plt
    
    
    def draw(data_train):
        for index in range(10): # 绘制前10 条数据
        	# a = data_train['heartbeat_signals'] # 获取heartbeat_signals列数据
            a = data_train['heartbeat_signals'].get(index)  # 读取某个下标元素 (行)
            b = a.split(",") # 分隔 0.9999,0.12323,0.678394 数据
            
            square = [] # 列坐标
            for i in b:
                square.append(float(i))
    
            x = [] # 行坐标
            for i in range(len(b)):
                x.append(i / 10.0)  # 行坐标除以10 
    
            plt.plot(x, square)
            # plt.savefig("C:/Users/admin/Desktop/filename.png") 绘制图像集合,并删除plt.close()
            plt.savefig("C:/Users/admin/Desktop/filename" + str(index) + ".png")# 绘制分图像
            plt.close()
            # plt.show()
    
    
    def main():
        data_train = pd.read_csv("C:/Users/admin/Desktop/train1.csv") #这里数据取了前10行
        
        # df = pd.read_csv("C:/Users/admin/Desktop/train1.csv", usecols=[2]) 读取指定列
        # x = data_train[['heartbeat_signals']]
        # y=data_train['heartbeat_signals'].index
        # x = data_train['heartbeat_signals']
        draw(data_train)
    
    
    if __name__ == '__main__':
        main()
    

    取前10行的数据的代码如下:

    import pandas as pd
    import numpy as np
    
    data_train = pd.read_csv("C:/Users/admin/Desktop/train.csv") # 读取训练集
    data_test_A = pd.read_csv("C:/Users/admin/Desktop/testA.csv") # 读取测试集
    
    train=data_train.head(10) 
    train.to_csv('C:/Users/admin/Desktop/train1.csv')
    

    3.3 绘制每个标签的前10个图像

    知道了大致的图像,还是不能查找出什么关系,我们尝试能不能看看每个label的图像有没有什么不同。
    lable=0
    在这里插入图片描述
    lable=1
    在这里插入图片描述
    lable=2
    在这里插入图片描述
    lable=3
    在这里插入图片描述

    import pandas as pd
    import matplotlib.pyplot as plt
    
    
    def draw(data_train):
        count = 0
        for index in range(200):
            if count == 10:
                break
    
            if data_train['label'].get(index) == 3.0:
                a = data_train['heartbeat_signals'].get(index)  # 读取某个下标元素
                b = a.split(",")
                count = count+1
                square = []
                for i in b:
                    square.append(float(i))
    
                x = []
                for i in range(len(b)):
                    x.append(i / 10.0)
    
                plt.plot(x, square)
                plt.savefig("C:/Users/admin/Desktop/filename.png")
                #plt.savefig("C:/Users/admin/Desktop/filename" + str(index) + ".png")
                #plt.close()
                # plt.show()
    
    
    def main():
        # data_train = pd.read_csv("C:/Users/admin/Desktop/train2.csv")
        data_train = pd.read_csv("C:/Users/admin/Desktop/train2.csv", usecols=[2, 3])
        # df = pd.read_csv("C:/Users/admin/Desktop/train1.csv", usecols=[2]) 读取指定列
    
        # x = data_train[['heartbeat_signals']]
        # y=data_train['heartbeat_signals'].index
        # x = data_train['heartbeat_signals']
        draw(data_train)
    
    
    if __name__ == '__main__':
        main()
    
    展开全文
  • 数据挖掘比赛数据集
  • 心跳信号分类预测(任务一)

    千次阅读 2021-03-15 21:56:14
    文章目录赛题理解导入第三方包lightgbm xgboost catboost理解读取数据数据预处理df.memory_usage()reduce...赛题以心电图数据为背景,要求选手根据心电图感应数据预测心跳信号,其中心跳信号对应正常病例以及受不同心律
  • 天池-零基础入门数据挖掘-心跳信号分类预测-baseline说明-代码-跑出来的结果-555分 https://tianchi.aliyun.com/competition/entrance/531883/introduction
  • 阿里天池心跳信号分类预测baseline

    千次阅读 热门讨论 2021-04-02 00:55:53
    阿里天池又来了一个数据挖掘新人赛,是关于心跳信号分类预测问题,主要针对初学者学习数据挖掘知识 比赛地址链接 这次数据比较有意思,和最常见的多属性结构化数据不同,本次数据是心电图数据记录,所以用一下传统...
  • 赛题以预测心电图心跳信号类别为任务,数据集报名后可见并可下载,该数据来自某平台心电图数据记录,总数据量超过20万,主要为1列心跳信号序列数据,其中每个样本的信号序列采样频次一致,长度相等。为了保证比赛的...
  • 天池比赛:零基础入门数据挖掘-心跳信号分类预测 主要介绍建模的步骤和思路(借鉴了B榜第一、第七以及各位大佬的部分内容,关于模型融合的部分将在之后的博客继续推出),采用CNN卷积神经网络对提供的一维数据进行...
  • 2 心跳检测,归属到传统机器学习的分类问题。采用的是lightgbm。这个是个结构化赛事比较管用的一个分类器。 3 有一些比较重要的基础内容,需要补充学习一下: 推荐: 机器学习原理与实践 pandas数据处理 Matplotlib...
  • 心跳信号分类预测

    2021-03-16 15:19:43
    赛题以心电图心跳信号数据为背景,要求选手根据心电图感应数据预测心跳信号所属类别,其中心跳信号对应正常病例以及受不同心律不齐和心肌梗塞影响的病例,这是一个多分类的问题。 学习目标:理解比赛数据和评分体系...
  • 数据挖掘--心跳信号分类预测

    千次阅读 2021-03-14 22:43:40
    赛题以心电图数据为背景,要求选手根据心电图感应数据预测心跳信号,其中心跳信号对应正常病例以及受不同心律不齐和心肌梗塞影响的病例,这是一个多分类问题。 数据下载地址,比赛要求参赛选手根据给定的数据集,...
  • 一、赛题 赛题以心电图数据为背景,要求选手根据心电图感应数据预测心跳信号,其中心跳信号对应正常病例以及受不同心律不齐和心肌梗塞影响的病例,这是一个多分类的问题。通过这道赛题来引导大家了解医疗大数据的...
  • 比赛地址:零基础入门数据挖掘-心跳信号分类预测 参考资料:由DataWhale开源的学习资料 赛题简介 本次新人赛是Datawhale与天池联合发起的0基础入门系列赛事 —— 心跳信号分类预测。 赛题以心电图心跳信号数据为...
  • 这三天的任务是做数据分析,主要是利用python的pandas以及可视化工具matplotlib、seabon,查看数据分布情况。 pandas中有一些非常好用的函数,可以快速得到数据的统计信息。比如,describe()来各列数据的相关统计量...
  • 心跳信号分类预测(tsfresh特征工程)

    千次阅读 2021-03-16 21:49:17
    文章目录1、问题建模赛题理解赛题数据评价指标混淆矩阵线下验证...准确率通常无法成为分类器的首要性能指标,特别是当你处理有偏数据集时(即某些类比其他类更为频繁)。 可以使用confusion_matrix()函数来获取混淆矩阵
  • 有监督学习:有特征,给定因变量,缩小预测值与因变量差 有监督学习,分为回归和分类 分类:因变量离散 回归:因变量连续 常用学习库:scikit-learn,常用包: import numpy as np import pandas as pd import ...
  • plt.title('Log Normal') sns.distplot(y, kde=False, fit=st.lognorm) ## 3) 查看预测值的具体频数 plt.hist(Train_data['label'], orientation = 'vertical',histtype = 'bar', color ='red') plt.show() 同时...
  • 标题零基础入门数据挖掘-心跳信号分类预测 Task1 赛题理解与baseline实现 赛题背景:以医疗数据挖掘为背景,要求使用提供的心跳信号传感器数据训练模型并完成不同心跳信号的分类的任务。 数据集格式:分为三列:ID号...
  • 心跳信号分类预测(一)

    千次阅读 2021-03-16 09:20:51
    赛题以预测心电图心跳信号类别为任务,该数据来自某平台心电图数据记录,总数据量超过20万,主要为1列心跳信号序列数据,其中每个样本的信号序列采样频次一致,长度相等。为了保证比赛的公平性,将会从中抽取10万条...
  • 此部分为零基础入门数据挖掘-心跳信号分类预测的 Task3 特征工程部分,带你来了解时间序列特征工程以及分析方法,欢迎大家后续多多交流。 赛题:零基础入门数据挖掘-心跳信号分类预测 项目地址: 比赛地址: 3.1 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,999
精华内容 799
关键字:

心跳信号分类预测