Advertisement

基于决策树算法的心脏病诊断

阅读量:

基于决策树算法的心脏病诊断研究利用了克利夫兰医学研究中心的心脏病患者数据集,通过数据预处理、模型建立和结果分析,探讨了决策树算法在疾病诊断中的应用。研究首先对数据进行了清洗和特征工程,包括处理因变量的二值化和数据探索。随后,构建了基于信息熵和基尼指数的决策树模型,并通过预剪枝优化模型复杂度。实验结果显示,基于基尼指数的决策树模型在ROC曲线下面积分别为0.69、0.81和0.86,其中剪枝后的基尼指数模型表现最优。最终,剪枝基尼指数决策树模型被选为最佳模型,用于心脏病诊断。研究还指出,尽管机器学习在医疗领域的应用前景广阔,但最终决策仍需结合临床经验,以确保医疗安全。

基于决策树算法的心脏病诊断

目录

采用决策树算法进行心脏疾病诊断分析

  • 前言
    • 采用决策树方法对心脏疾病进行诊断研究

      • 导入相关库
      • 读取数据并概述其基本特征
      • 进行数据探索
      • 构建决策树模型
        • 分离自变量与因变量
    • 分离训练集与测试集

    • 构建决策树模型(基于信息熵)

      • 基于信息熵的决策树模型
      • 模型评估结果
      • 进行决策树可视化
    • 模型建立(基于基尼指数)

      • 基于基尼指数的决策树
      • 模型结果
      • 决策树可视化
    • 模型建立(预剪枝)

      • 基于基尼指数的决策树(预剪枝)
      • 模型结果
      • 决策树可视化
    • 三种结果ROC曲线比较

    • 后记

前言

在机器学习领域,决策树作为一种基础算法,常被广泛提及。这种算法能够有效地处理离散型和连续型数据,且在数据预处理方面具有显著优势,通常情况下,决策树算法对数据的预处理要求较低,具体来说,它通常不需要对数据进行标准化处理,也不需要对缺失值进行复杂的填补操作。与神经网络的不可解释性相比,决策树算法具有更高的透明度,这使得它在决策过程的可视化方面具有显著优势。基于这些优势,决策树算法在医疗数据分析、金融风险评估等多个领域得到了广泛应用。然而,决策树算法也存在一些局限性,例如容易陷入过拟合的陷阱,导致模型的泛化能力较弱。为了解决这一问题,通常可以采用剪枝方法或集成学习策略,其中随机森林算法因其卓越的性能而备受关注。随机森林算法通过集成多个决策树来提升预测能力,已成为机器学习领域中应用最广泛的算法之一。在实际应用中,决策树算法的具体实现方式多种多样,其中基于信息熵的ID3算法、基于信息增益率的C4.5算法以及基于基尼指数的CART算法最为知名。在算法理论方面,本文不做深入探讨,建议对理论感兴趣的研究者参考周志华的《机器学习》或李航的《统计学习方法》等权威教材以获得更深入的理解。本文将重点探讨决策树算法在心脏病诊断领域的实际应用。

基于决策树的心脏病诊断

机器学习在医疗卫生领域有广泛的应用,特别是在临床诊断方面,其预测的准确性有时会超过传统的人工判断。

在这里插入图片描述

(本文数据来源于和鲸社区)

导入相关库

复制代码
    import pandas as pd
    import matplotlib.pyplot as plt
    import seaborn as sns

读取并查看数据基本情况

打印数据特征
首先将数据特征打印出来,方便查看

复制代码
    fea1 = ['ATTR1','ATTR2','ATTR3','ATTR4','ATTR5','ATTR6','ATTR7','ATTR8','ATTR9','ATTR10','ATTR11','ATTR12','ATTR13','ATTR14']
    fea2 = ['年龄','性别','胸痛类型','静息血压','血浆类固醇含量','空腹血糖','静息心电图结果','最高心率','运动型心绞痛','运动引起的ST下降',\
        '最大运动量时心电图ST的斜率','使用荧光染色法测定的主血管数','THAL','患病情况']
复制代码
    fea = zip(fea1,fea2)#打包函数zip()
    for i in fea:
    print (i)

(ATTR1属性,年龄特征)
(ATTR2属性,性别特征)
(ATTR3属性,胸痛类型特征)
(ATTR4属性,静息血压水平)
(ATTR5属性,血浆类固醇水平)
(ATTR6属性,空腹血糖水平)
(ATTR7属性,静息心电图结果)
(ATTR8属性,最高心率数值)
(ATTR9属性,运动型心绞痛类型)
(ATTR10属性,运动诱发ST段下降情况)
(ATTR11属性,运动时ST段下降速率)
(ATTR12属性,主血管数量统计)
(ATTR13属性,thal气道 obstruction状况)
(ATTR14属性,疾病患病程度)

读取数据

复制代码
    data = pd.read_csv('data.csv',names = fea1)
    data.head()

输出:

在这里插入图片描述

响应变量ATTR14被赋值为1(无疾病)和2(有疾病)。在后续阶段需要将该变量转换为0、1或1、-1的形式进行编码处理。如果不进行处理,这将导致模型评估阶段出现错误,函数无法区分正反例。

复制代码
    data.shape

输出:
(270, 14)
数据包括14个特征、270条记录。

复制代码
    data.info()

输出:
<class ‘pandas.core.frame.DataFrame’>
RangeIndex: 270 entries, 0 to 269
Data columns (total 14 columns):
ATTR1 270 non-null int64
ATTR2 270 non-null int64
ATTR3 270 non-null int64
ATTR4 270 non-null int64
ATTR5 270 non-null int64
ATTR6 270 non-null int64
ATTR7 270 non-null int64
ATTR8 270 non-null int64
ATTR9 270 non-null int64
ATTR10 270 non-null float64
ATTR11 270 non-null int64
ATTR12 270 non-null int64
ATTR13 270 non-null int64
ATTR14 270 non-null int64
dtypes: float64(1), int64(13)
memory usage: 29.6 KB

数据无缺失值。

数据转换
将因变量转换为0-1变量

复制代码
    data['ATTR14'] = data['ATTR14'].replace(1,0) #1替换为0
    data['ATTR14'] = data['ATTR14'].replace(2,1) #2替换为1
    data.head()

输出:

在这里插入图片描述

“ATTR14”列已经转换为0-1变量。

数据探索

复制代码
    plt.rcParams["font.sans-serif"]=["SimHei"] #支持中文显示
    plt.rcParams["axes.unicode_minus"]=False #支持负号显示
    data.hist('ATTR1') #在x轴上绘制定量数据的分布特征(用于连续数据,而柱状图用于离散数据)
    plt.title('年龄分布')

输出:

在这里插入图片描述

年龄基本服从正态分布。

复制代码
    sns.countplot(x = 'ATTR2',hue = 'ATTR14',data = data)
    plt.legend(labels = ['未患病','患病'])
    plt.title('性别患病情况')
    #   0为女性,1为男性
在这里插入图片描述

从图上可以看出,数据中男性记录较多,且患病比例也较高。

复制代码
    sns.countplot(y = 'ATTR14',data = data)

输出:

在这里插入图片描述

因变量中的数据样本比例差异较小,因此无需考虑数据比例失衡问题。

决策树模型建立

划分自变量和因变量
复制代码
    x = data.iloc[:,:13]
    y = data.iloc[:,13]
划分训练集和测试集
复制代码
    from sklearn.model_selection import train_test_split
    x_train,x_test,y_train,y_test = train_test_split(x,y,test_size = 0.3 , random_state = 0)
模型建立(基于信息熵)
基于信息熵的决策树
复制代码
    from sklearn.tree import DecisionTreeClassifier
    dt1 = DecisionTreeClassifier(criterion = 'entropy',random_state = 0) #基于信息熵的决策树(一般数据维度较高或者噪音较多使用基尼指数‘gini’)
    dt1.fit(x_train , y_train)

DecisionTreeClassifier(
regularization parameter for pruning=0.0,
weight assigned to classes=None,
criterion for measuring node quality=entropy,
maximum depth of the tree=None,
maximum number of features considered for splitting=None,
maximum number of leaf nodes=None,
minimum decrease in impurity required to split a node=0.0,
minimum impurity threshold for splitting=None,
minimum number of samples required to be at a leaf node=1,
minimum number of samples required to split an internal node=2,
minimum weight fraction of samples required to be at a leaf node=0.0,
deprecated parameter for sorting strategy=deprecated,
random number seed=0,
splitting criterion=best
)

模型结果

测试结果

复制代码
    y_pred = dt1.predict(x_test)
    score = dt1.score(x_test , y_test)
    print(score)

输出:0.6790123456790124
模型在测试集上的预测结果只有0.679,表现一般,不算优秀。

分类报告

复制代码
    from sklearn.metrics import classification_report
    print(classification_report(y_test, y_pred))

输出:

在这里插入图片描述

ROC曲线

复制代码
    #绘制AUC曲线
    from sklearn import metrics
    y_score = dt1.predict_proba(x_test)[:,1]
    fpr,tpr,threshold = metrics.roc_curve(y_test,y_score)
    roc_auc = metrics.auc(fpr,tpr)
    plt.stackplot(fpr,tpr,color = 'steelblue',alpha = 0.5,edgecolor = 'black')#alpha调节颜色深浅
    plt.plot(fpr,tpr,color='black',lw = 1) #lw:调节线条粗细
    plt.plot([0,1],[0,1],color = 'red',linestyle = '--')
    plt.text(0.5,0.3,'ROC curve (area = %0.2f)'%roc_auc)
    
    plt.xlabel('1-specificity')
    plt.ylabel('sensitivity')
    plt.show()

输出:

在这里插入图片描述

ROC曲线下面积只有0.69。

决策树可视化

在进行决策树可视化时,建议提前安装graphviz软件,具体下载地址可参考官网:http://www.graphviz.org/。安装步骤建议参考网上教程,这里就不具体展开了。

复制代码
    import pydotplus
    from sklearn import tree
    dot_data = tree.export_graphviz(dt1 , out_file = None)
    graph = pydotplus.graph_from_dot_data(dot_data)
    graph.write_png('heart_disease1.png') #输出PNG格式
    #graph.write_pdf('heart_disease.pdf') #输出PDF格式

保存的决策树可视化结果为:

在这里插入图片描述

可以看出,生成了层数为8层的决策树。

综合以上分析,基于信息熵的决策树模型在心脏疾病诊断预测任务中的表现尚可。考虑到数据特征共有13个维度,维度数量较多,建议采用基尼指数作为决策树模型的评估标准。

模型建立(基于基尼指数)
基于基尼指数的决策树
复制代码
    dt2 = DecisionTreeClassifier(criterion = 'gini',random_state = 0) #基于基尼指数的决策树
    dt2.fit(x_train , y_train)

DecisionTreeClassifier参数设置如下:ccp_alpha参数设置为0.0,class_weight属性未做特殊设置,criterion属性设置为gini方法,max_depth参数未做限制,max_features参数未做限制,max_leaf_nodes参数未做限制,min_impurity_decrease参数设置为0.0,min_impurity_split参数未做设置,min_samples_leaf参数设置为1,min_samples_split参数设置为2,min_weight_fraction_leaf参数设置为0.0,presort参数设置为deprecated,random_state参数设置为0,splitter参数设置为best。

模型结果

测试结果

复制代码
    y_pred = dt2.predict(x_test)
    score = dt2.score(x_test , y_test)
    print(score)

输出:0.8024691358024691

通过计算得出,以基尼指数为评估标准的决策树预测结果为0.8025,高于采用信息熵评估的决策树预测结果0.679,其在预测效果方面优于后者。

分类报告

复制代码
    from sklearn.metrics import classification_report
    print(classification_report(y_test, y_pred))

输出:

在这里插入图片描述

精确率和召回率等,基于基尼指数的决策树都优于基于信息熵的决策树。

ROC曲线

复制代码
    #绘制AUC曲线
    y_score = dt2.predict_proba(x_test)[:,1]
    fpr,tpr,threshold = metrics.roc_curve(y_test,y_score)
    roc_auc = metrics.auc(fpr,tpr)
    plt.stackplot(fpr,tpr,color = 'steelblue',alpha = 0.5,edgecolor = 'black')#alpha调节颜色深浅
    plt.plot(fpr,tpr,color='black',lw = 1)
    plt.plot([0,1],[0,1],color = 'red',linestyle = '--')
    plt.text(0.5,0.3,'ROC curve (area = %0.2f)'%roc_auc)
    plt.xlabel('1-specificity')
    plt.ylabel('sensitivity')
    
    plt.show()

输出:

在这里插入图片描述

ROC曲线下面积为0.81,优于基于信息熵的决策树的ROC曲线下面积0.69。

决策树可视化
复制代码
    import pydotplus
    from sklearn import tree
    dot_data = tree.export_graphviz(dt2 , out_file = None)
    graph = pydotplus.graph_from_dot_data(dot_data)
    graph.write_png('heart_disease2.png') 
    # graph.write_pdf('heart_disease2.pdf')

保存的决策树可视化结果为:

在这里插入图片描述

结果可以看出最终生成了11层的决策树。

模型建立(预剪枝)
基于基尼指数的决策树(预剪枝)

决策树的深度并非越大越好。模型可能过度吸收数据中的微小细节,尽管在训练集中预测效果显著,但在测试集上的表现却不尽如人意,即导致模型过拟合。常用剪枝策略来优化决策树算法,通常包括预剪枝和后剪枝两种方法。本文以预剪枝策略为例,通过设定生成树的最大深度来控制其生长。

复制代码
    dt3 = DecisionTreeClassifier(criterion = 'gini',max_depth = 6,random_state = 0) #基于基尼指数的决策树,设置最大层数为6(测试为最佳层数)
    dt3.fit(x_train , y_train)
    y_pred = dt3.predict(x_test)
    score = dt3.score(x_test , y_test)
    print(score)

输出:0.8271604938271605
结果优于无剪枝操作的结果0.8025。

模型结果

查看分类报告

复制代码
    from sklearn.metrics import classification_report
    print(classification_report(y_test, y_pred))

输出:

在这里插入图片描述

ROC曲线

复制代码
    #绘制AUC曲线
    y_score = dt3.predict_proba(x_test)[:,1]
    fpr,tpr,threshold = metrics.roc_curve(y_test,y_score)
    roc_auc = metrics.auc(fpr,tpr)
    plt.stackplot(fpr,tpr,color = 'steelblue',alpha = 0.5,edgecolor = 'black')#alpha调节颜色深浅
    plt.plot(fpr,tpr,color='black',lw = 1)
    plt.plot([0,1],[0,1],color = 'red',linestyle = '--')
    plt.text(0.5,0.3,'ROC curve (area = %0.2f)'%roc_auc)
    plt.xlabel('1-specificity')
    plt.ylabel('sensitivity')
    
    plt.show()

输出:

在这里插入图片描述

ROC曲线下面积为0.86,优于上面两个模型的结果。

决策树可视化
复制代码
    import pydotplus
    from sklearn import tree
    dot_data = tree.export_graphviz(dt2 , out_file = None)
    graph = pydotplus.graph_from_dot_data(dot_data)
    graph.write_png('heart_disease3.png') 
    # graph.write_pdf('heart_disease3.pdf')

保存的决策树可视化结果为:

在这里插入图片描述
三种结果ROC曲线比较
复制代码
    y_score1 = dt1.predict_proba(x_test)[:,1]
    y_score2 = dt2.predict_proba(x_test)[:,1]
    y_score3 = dt3.predict_proba(x_test)[:,1]
    fpr1,tpr1,threshold = metrics.roc_curve(y_test,y_score1)
    fpr2,tpr2,threshold = metrics.roc_curve(y_test,y_score2)
    fpr3,tpr3,threshold = metrics.roc_curve(y_test,y_score3)
    roc_auc1 = metrics.auc(fpr1,tpr1)
    roc_auc2 = metrics.auc(fpr2,tpr2)
    roc_auc3 = metrics.auc(fpr3,tpr3)
    plt.plot(fpr1,tpr1,color='black',lw = 1)
    plt.plot(fpr2,tpr2,color='blue',lw = 1)
    plt.plot(fpr3,tpr3,color='green',lw = 1)
    plt.plot([0,1],[0,1],color = 'red',linestyle = '--')
    # plt.text(0.5,0.3,'ROC curve (area = %0.2f)'%roc_auc)
    plt.legend(labels = ['信息熵','基尼指数','剪枝基尼指数'])
    plt.xlabel('1-specificity')
    plt.ylabel('sensitivity')
    
    plt.show()

输出:

在这里插入图片描述

通过分析结果可以看出,其ROC曲线涵盖了基尼指数和信息熵两种决策树的曲线。因此,建议选择基于剪枝基尼指数的决策树模型来进行心脏病诊断。

后记

决策树算法也存在一些局限性,除了剪枝处理以外,其改进思路是采用集成学习方法,将多棵决策树集成形成随机森林结构,这种改进通常能带来更好的性能表现。如有机会,会持续补充随机森林的相关案例,介绍该算法的实际应用。此外,个人意见是,对于医疗卫生领域的算法应用,由于涉及生命安全,如疾病诊断,模型算法仅能作为辅助工具使用,最终仍需依靠医生的经验和判断来决定用药方案,完全依赖算法可能会有风险。不容置疑的是,当今科学技术发展极为迅速,许多机器算法在疾病诊断上的准确率往往高于人类,然而,机器算法只是通过数据学习进行判断,一些无法被数据捕捉到的特征可能未被模型捕捉到,此时,经验丰富的医生的判断会更加科学。相信在科学技术的持续推动下,医疗卫生领域的研究和发展将更加高效、可靠。

(本文数据来源于和鲸社区/克利夫兰医学研究中心)

全部评论 (0)

还没有任何评论哟~