Advertisement

心脏病预测案例

阅读量:

背景

心脏病是人类健康的头号杀手。全世界1/3的人口死亡是心脏病引起的。而我国,每年有几十万人死于心脏病。如果可以通过提取人体相关的体测指标,通过数据挖掘方式来分析不同特征对于心脏病的影响,将对预防心脏病起到至关重要的作用。本文提供真实的数据,并通过阿里云机器学习平台搭建心脏病预测案例。

数据集介绍

数据源为UCI开源数据集heart_disease。包含了303条美国某区域的心脏病检查患者的体测数据。具体字段如下表。

由于很多人问源数据,我再贴一遍出来:http://archive.ics.uci.edu/ml/machine-learning-databases/00000/

该链接下有个 heart.txt 的文本,数据源全是纯数字,我做过变更才出现下面贴的数据。

age 用年数表示的年龄 sex- 性别枚举(1 = 男性; 0 = 女性)

cp: 胸部疼痛的类型 (值为 ‘1’: 典型的心绞痛 值为 ‘2’: 非典型的心绞痛 值为 ‘3’: 非心绞痛的疼痛)

trestbpss: 静息血压 (准许入院的毫米汞柱(mm Hg))

chol: 以mg/dl为单位的血清类固醇

fbs: (空腹血糖 > 120 mg/dl) (1 = 是; 0 = 否)

restecg: 静息心电图结果 (值为 0: 正常 值为 1: 有ST-T波异常 (T波倒置和/或ST段抬高或压低>0.05 mV) 值为 2: 显示该标准下可能或明确的的左心室肥厚)

thalach : 达到的最大心率

exang : 是否运动诱发的心绞痛 (1 = 是; 0 = 否)

oldpeak : 由与相对休息有明显差异的运动诱导的ST段压低

slope : 运动高峰期的ST段斜率 (值为 1: 上斜 值为 2: 水平)

ca : 被透视荧光检查(flourosopy)标注颜色的大血管的数量 (0-3)

thal : 3 = 正常; 6 = 固有缺陷; 7 = 可修复缺陷

num : 心脏病的诊断 (冠状动脉疾病状态)

status:值为 0: < 50% 直径缩小 (意味着’没有疾病’) 值为 1: > 50% 直径缩小 (意味着’出现了疾病’)

先导入数据:

复制代码
 import pandas as pd

    
 import numpy as np
    
 import matplotlib.pyplot as plt
    
 import warnings
    
 warnings.filterwarnings('ignore')
    
 %matplotlib inline
复制代码
 data = pd.read_table('F:\ data_load\ heat_dieses.txt', sep=' ',names = ['age','sex','cp','trestbps','chol','fbs','restecg','thalach',\

    
                                                                              'exang','oldpeak','slop','ca','thal','status','style'])
    
 data.head()
复制代码
    data['ca'].value_counts()
复制代码
 0.0    175

    
 1.0     65
    
 2.0     38
    
 3.0     20
    
 ?        5
    
 Name: ca, dtype: int64

经过分析发现有字段出现异常值,经过分析将异常值用字段的众数填充:

复制代码
 for j in range(0,data.shape[0]):

    
     if data['ca'][j] == '?':
    
     data['ca'][j] = data['ca'].mode()[0]

由于style只是患病的类型,与预测结果无关,可以去掉

复制代码
    data = data.drop(['style'],axis=1)

上图中很多数据都是文字描述的,在数据预处理的过程中需要根据每个字段的含义将字符转为数值。

二值类的数据:

比如sex字段有female和male两种形式,可以将female表示成0,male表示成1。

多值类的数据:

比如cp字段,表示胸部的疼痛感,可以将疼痛感由轻到重映射成0~3的数值。

复制代码
 cp_mapping = {'angina':0,'abnang':2,'notang':1,'asympt':3}

    
 data['cp'] = data['cp'].map(cp_mapping)
    
  
    
 sex_mapping = {'fem':0,'male':1}
    
 data['sex'] = data['sex'].map(sex_mapping)
    
  
    
 fbs_mapping = {'true':0,'fal':1}
    
 data['fbs'] = data['fbs'].map(fbs_mapping)
    
  
    
 restecg_mapping = {'hyp':2,'norm':0,'abn':'1'}
    
 data['restecg'] = data['restecg'].map(restecg_mapping)
    
  
    
 exang_mapping = {'true':0,'fal':1}
    
 data['exang'] = data['exang'].map(exang_mapping)
    
  
    
 slop_mapping = {'down':2,'flat':1,'up':0}
    
 data['slop'] = data['slop'].map(slop_mapping)
    
  
    
 thal_mapping = {'rev':2,'fix':1,'norm':0,'?':0}
    
 data['thal'] = data['thal'].map(thal_mapping)
    
  
    
 status_mapping = {'sick':1,'buff':0}
    
 data['status'] = data['status'].map(status_mapping)
复制代码
    data.head()

接下来看一下每个特征的相关系数:

复制代码
 corr = data.corr()

    
 import seaborn as sns
    
 fig, ax = plt.subplots(figsize=(9,9))
    
 ax.set_title(u'相关系数')
    
 sns.heatmap(corr,annot=True,vmax=1,vmin=0,xticklabels=True,yticklabels=True,cmap=plt.cm.Blues);

归一化
将每个特征的数值范围变为0到1之间,可以去除量纲对结果的影响,公式为result=(val-min)/(max-min)。本次实验通过逻辑回归二分类来进行模型训练,需要每个特征去除量纲的影响。归一化结果如下图所示。

复制代码
 from sklearn.preprocessing import StandardScaler

    
 Scaler = StandardScaler()
    
 for column in data.columns:
    
     if column != 'status':
    
     data[column] = Scaler.fit_transform(data[column].values.reshape(-1,1))

监督学习就是已知结果来训练模型。因为已经知道每个样本是否患有心脏病,因此本次实验是监督学习。解决的问题是预测一组用户是否患有心脏病。

拆分
通过拆分组件将数据分为两部分,本次实验按照训练集和预测集7:3的比例拆分。训练集数据流入逻辑回归二分类组件用来训练模型,预测集数据进入预测组件。

逻辑回归二分类
逻辑回归是一个线性模型,通过计算结果的阈值实现分类(具体的算法详情请自行查阅资料)。逻辑回归训练好的模型可以在模型页签中查看。

接下来对模型进行交叉验证,选出合适的超参数:

复制代码
 def print_KFold_scores(x_train_data, y_train_data):

    
     fold = KFold(5,shuffle=False)
    
     
    
     c_param_range = [0.01,0.1,1,10,100]
    
     
    
     result_table = pd.DataFrame(index = range(len(c_param_range),2), columns = ['C_parameter','Mean recall score'])
    
     result_table['C_parameter'] = c_param_range
    
     
    
     j = 0
    
     recall_accs = []
    
     for c_param in c_param_range:
    
     print('----------------------------')
    
     print('c_param',c_param)
    
     print('----------------------------')
    
     
    
     for train_index, test_index in fold.split(x_train_data):
    
         lr = LogisticRegression(C = c_param, penalty = 'l2')
    
         lr.fit(x_train_data.iloc[train_index,:],y_train_data.iloc[train_index,:].values.ravel())
    
         y_pred = lr.predict(x_train_data.iloc[test_index,:])
    
         
    
         recall_acc = recall_score(y_train_data.iloc[test_index,:].values.ravel(),y_pred,average="micro")
    
         recall_accs.append(recall_acc)
    
         
    
         print('recall_score',recall_acc)
    
     
    
     result_table.loc[j,1:2] = np.mean(recall_accs)
    
     j+=1
    
     print('Mean recall score:',np.mean(recall_accs))
    
     best_c = result_table.loc[result_table['Mean recall score'].astype('float').idxmax()]['C_parameter']
    
     print('*****************************************************************************')
    
     print('Best model to choose from cross validation is with C parameter = ', best_c)
    
     print('*****************************************************************************')
    
     return best_c    
    
  
    
 best_c = print_KFold_scores(X_train,y_train)
复制代码
 ----------------------------

    
 c_param 0.01
    
 ----------------------------
    
 recall_score 0.7551020408163265
    
 recall_score 0.8979591836734694
    
 recall_score 0.7916666666666666
    
 recall_score 0.875
    
 recall_score 0.8541666666666666
    
 Mean recall score: 0.8347789115646258
    
 ----------------------------
    
 c_param 0.1
    
 ----------------------------
    
 recall_score 0.7142857142857143
    
 recall_score 0.8775510204081632
    
 recall_score 0.8125
    
 recall_score 0.8541666666666666
    
 recall_score 0.8541666666666666
    
 Mean recall score: 0.8286564625850341
    
 ----------------------------
    
 c_param 1
    
 ----------------------------
    
 recall_score 0.7142857142857143
    
 recall_score 0.8775510204081632
    
 recall_score 0.8333333333333334
    
 recall_score 0.8333333333333334
    
 recall_score 0.8333333333333334
    
 Mean recall score: 0.8252267573696146
    
 ----------------------------
    
 c_param 10
    
 ----------------------------
    
 recall_score 0.7142857142857143
    
 recall_score 0.8775510204081632
    
 recall_score 0.8333333333333334
    
 recall_score 0.8541666666666666
    
 recall_score 0.8333333333333334
    
 Mean recall score: 0.8245535714285713
    
 ----------------------------
    
 c_param 100
    
 ----------------------------
    
 recall_score 0.7142857142857143
    
 recall_score 0.8775510204081632
    
 recall_score 0.8333333333333334
    
 recall_score 0.8541666666666666
    
 recall_score 0.8333333333333334
    
 Mean recall score: 0.8241496598639455
    
 *****************************************************************************
    
 Best model to choose from cross validation is with C parameter =  0.01
    
 *****************************************************************************

画出混淆矩阵图:

复制代码
 def plot_confusion_matrix(cm, classes,

    
                       title='Confusion matrix',
    
                       cmap=plt.cm.Blues):
    
     """
    
     This function prints and plots the confusion matrix.
    
     """
    
     plt.imshow(cm, interpolation='nearest', cmap=cmap)
    
     plt.title(title)
    
     plt.colorbar()
    
     tick_marks = np.arange(len(classes))
    
     plt.xticks(tick_marks, classes, rotation=0)
    
     plt.yticks(tick_marks, classes)
    
  
    
     thresh = cm.max() / 2.
    
     for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
    
     plt.text(j, i, cm[i, j],
    
              horizontalalignment="center",
    
              color="white" if cm[i, j] > thresh else "black")
    
  
    
     plt.tight_layout()
    
     plt.ylabel('True label')
    
     plt.xlabel('Predicted label')
复制代码
 import itertools

    
 lr = LogisticRegression(C=0.01,penalty = 'l2')
    
 lr.fit(X_train,y_train)
    
 y_pred = lr.predict(X_test.values)
    
  
    
 # Compute confusion matrix
    
 cnf_matrix = confusion_matrix(y_test,y_pred)
    
 np.set_printoptions(precision=2)
    
  
    
 print("Recall metric in the testing dataset: ", cnf_matrix[1,1]/(cnf_matrix[1,0]+cnf_matrix[1,1]))
    
  
    
 # Plot non-normalized confusion matrix
    
 class_names = [0,1]
    
 plt.figure()
    
 plot_confusion_matrix(cnf_matrix
    
                   , classes=class_names
    
                   , title='Confusion matrix')
    
 plt.show()
复制代码
    lr.score(X_test,y_test)
复制代码
9016393442622951

由上可知:模型的数据的分类准确率为:0.9016393442622951,召回率为:0.8518518518519

由混淆矩阵图可知仅仅将两个正常人误判为患病者,效果符合实际要求。

全部评论 (0)

还没有任何评论哟~