文章目录

  • 数据集描述
    • 准备工作
    • 实验环境和工具
  • 预测分析
    • 探索性数据分析
      • 数据描述
      • 可视化分析
    • 构建baseline
    • 数据预处理
      • 离群值处理
      • 缺失值处理
      • 特征工程
      • 数据标准化
    • 模型构建与调参优化
    • 完整代码

数据集描述

本数据集内含十个属性列
Pergnancies: 怀孕次数
Glucose:血糖浓度
BloodPressure:舒张压(毫米汞柱)
SkinThickness:肱三头肌皮肤褶皱厚度(毫米)
Insulin:两个小时血清胰岛素(μU/毫升)
BMI:身体质量指数,体重除以身高的平方
Diabets Pedigree Function: 疾病血统指数
是否和遗传相关,Height:身高(厘米)
Age:年龄
Outcome:0表示不患病,1表示患病。

任务:建立机器学习模型以准确预测数据集中的患者是否患有糖尿病

准备工作

查阅资料得知各属性的数据值要求,方面后期对于数据的分析与处理过程。
属性列名称 数据值要求
Pergnancies(怀孕次数) 符合常理即可(可为0)
Glucose(血糖浓度) 正常值为:80~120
BloodPressure(舒张压(毫米汞柱)) 正常值为:60~80
SkinThickness(肱三头肌皮肤褶皱厚度(毫米)) 不为0
Insulin(两个小时血清胰岛素(/毫升)) 正常值为:35~145
BMI(身体质量指数:体重除以身高的平方) 正常值为:18.5~24.9
Diabets Pedigree Function:(疾病血统指数:是否和遗传相关) 无特殊值要求
Height(身高(厘米)) 不为0 符合常理即可
Age(年龄) 符合常理即可
Outcome(0表示不患病,1表示患病) 标签值

实验环境和工具

python3.5.6 + jupyter
数据处理 pandas、numpy
可视化 matplotlib、seaborn
模型构建 sklearn

预测分析

探索性数据分析

数据描述

首先观察基本的数据类型,以及数据是否存在缺失情况,简要统计信息

all_data.shape
all_data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 768 entries, 0 to 767
Data columns (total 10 columns):#   Column                    Non-Null Count  Dtype
---  ------                    --------------  -----  0   Pregnancies               768 non-null    int64  1   Glucose                   768 non-null    int64  2   BloodPressure             768 non-null    int64  3   SkinThickness             768 non-null    int64  4   Insulin                   768 non-null    int64  5   BMI                       768 non-null    float646   DiabetesPedigreeFunction  768 non-null    float647   Age                       768 non-null    int64  8   Height                    766 non-null    object 9   Outcome                   768 non-null    int64
dtypes: float64(2), int64(7), object(1)
memory usage: 60.1+ KB

数据总量时比较少的只有768个例子,可以看到除Height外的属性都为数值型属性。在后续数据预处理过程需要对Height属性进行类型转换操作。目前没有缺失值的出现。

# height 数值类型 为object 需要转化为 数值型
all_data = all_data.astype({'Height':'float64'})
all_data.describe()


发现两个问题:

  1. 缺失值
    从其中的min值可以很直观地观察到,Glucose, BloodPressure, SkinTinckness, Insulin, BMI等特征存在0值的情况(当然Pregnancies根据常识判断是可以为0的)。而根据常规范围明显可以判定这些0值是不合理的,所以也是一种缺失值缺失值,后续数据预处理需要对这些缺失值进行填充处理。
  2. 离群值/异常值
    Glucose,BloodPressure,SkinTinckness,Insulin等特征的max值和75%分位点值或者min值和25%分位点值之间的差距比较大,初步判断可能存在离群值/异常值。尤其是SkinThickness和Insulin特征(具体见图4红色框部分),后续可以通过可视化进一步直观地观察判断。
    为了方便后序对缺失值的统一处理,将异常值统一替换为np.nan。
import numpy as np
#缺失值替换 经分析,除怀孕次数,其他特征的0值表示缺失值 替换为np.nan
replace_list = ['Glucose', 'BloodPressure', 'SkinThickness', 'Insulin', 'BMI', 'Height']
all_data.loc[:,replace_list] = all_data.loc[:,replace_list].replace({0:np.nan})
#各特征缺失数量统计
null_count = all_data.isnull().sum().values
# 缺失值情况
plt.figure()
sns.barplot(x = null_count, y = all_data.columns)
for x, y in enumerate(null_count):plt.text(y, x, "%s" %y, horizontalalignment='center', verticalalignment='center')
plt.show()


可以观察到Glucose,Insulin,SkinThickness,BMI,Height等特征都存在缺失值。并且 Insulin,SkinThickness缺失值比较多,分别占到了48%,30%的比例。所以后期数据预处理也是很关键的。

可视化分析

接下来通过更多针对性的可视化,来进一步探索特征值的分布以及特征和预测变量之间的关系

# 患病和不患病情况下 箱线图查看数据分散情况
for col in all_data.columns:plt.figure(figsize = (10,6))if all_data[col].unique().shape[0] > 2:sns.boxplot(x="Outcome", y=col, data=all_data.dropna())else:sns.countplot(col,hue = 'Outcome',data = all_data.dropna())plt.title(col)plt.show()

部分输出:

观察患病和不患病情况下 各特征值或者人数分布
label接近2:1 存在一定的分布不平衡
像insulin之类的特征离群值是比较多的,由于离群值会对模型评估产生影响,所以后续可能要做处理,剔除偏离较大的离群值
# 患病和不患病情况下 各特征的分布情况
for col in all_data.drop('Outcome',1).columns:plt.figure()sns.displot(data = all_data, x = col,hue = 'Outcome',kind='kde')plt.show()

部分输出:


  1. 从数据样本本身出发研究数据分布特征,可以发现在患病和不患病两种情况下,部分特征的密度分布比较相近,特别是height的分布图,发现两曲线基本相近。感觉和label之间的相关性都不是很强。
  2. 同时,可以发现部分特征存在右偏的现象(skewness (偏度) 描述数据分布形态的统计量,其描述的是某总体取值分布的对称性),考虑到需要数据尽量服从正态分布,所以后续数据预处理需要对存在一定偏度的特征进行相关处理。
# 观察各特征分布和患病的关系
corr = all_data.corr()
plt.figure(figsize = (8,6))
sns.heatmap(corr,annot = True,cmap = 'Blues')
plt.show()


heatmap()函数可以直观地将数据值的大小以定义的颜色深浅表示出来。

  1. 可以发现颜色相对来说都比较浅,也就是说无论是特征和特征之间还是特征和outcome标签之间的相关性都没有很高。
  2. 发现其余各特征变量中与outcome的相关度中最高的是Glucose 属性值为0.49,最低的是Height属性值为0.059。
  3. 同时观察特征与特征之间的关系,发现Insulin与Glucose,BMI和SkinThickness之间的相关度分别为0.58,0.65属于比较高的相关性,由于Insulin是一个确实比较严重的特征,而相关性可以是一种协助填充缺失值的方法。
plt.figure()
sns.scatterplot(x = 'Insulin', y = 'Glucose', data = all_data)
plt.show()
sns.scatterplot(x = 'Insulin', y = 'BMI', data = all_data)
plt.show()
sns.scatterplot(x = 'Insulin', y = 'Age', data = all_data)
plt.show()plt.figure()
sns.scatterplot(x = 'SkinThickness', y = 'BMI', data = all_data)
plt.show()
sns.scatterplot(x = 'SkinThickness', y = 'Glucose', data = all_data)
plt.show()
sns.scatterplot(x = 'SkinThickness', y = 'BloodPressure', data = all_data)
plt.show()

部分输出:

构建baseline

因为决策树几乎不需要数据预处理。其他方法经常需要数据标准化,创建虚拟变量和删除缺失值。

# 读取数据
all_data = pd.read_csv('data.csv')# height 数值类型 为object 需要转化为 数值型
all_data = all_data.astype({'Height':'float64'})
#
all_data.dropna(inplace = True)
# 特征
feature_data = all_data.drop('Outcome',1)
# 标签
label = all_data['Outcome']base_model = DecisionTreeClassifier()
base_scores = cross_validate(base_model, feature_data, label,cv=5,return_train_score=True)
print(base_scores['test_score'].mean())
0.6954248366013072

数据预处理

综合前面分析,先做了以下处理

# 读取数据
all_data = pd.read_csv('data.csv')# height 数值类型 为object 需要转化为 数值型
all_data = all_data.astype({'Height':'float64'})# 理论缺失值0替换为np.nan
replace_list = ['Glucose', 'BloodPressure', 'SkinThickness', 'Insulin', 'BMI', 'Height']
all_data.loc[:,replace_list] = all_data.loc[:,replace_list].replace({0:np.nan})# 删除相关性低的Height
all_data.drop('Height',1,inplace = True)

离群值处理

  1. 经过前面的分析发现数据是存在部分离群值的,虽然实验本身就是关于疾病预测,异常值的存在属于正常现象。但是对于一些可能超出人体接受范围的值,衡量对预测的影响之后,由于数据量比较小,这里选择删除极端异常点。
  2. 极端异常点 :上限的计算公式为Q3+3(Q3-Q1) 下界的计算公式为Q1-3(Q3-Q1))。
# remove the outliers
# 异常点 上须的计算公式为Q3+1.5(Q3-Q1);下须的计算公式为Q1-1.5(Q3-Q1)
# 极端异常点 :上限的计算公式为Q3+3(Q3-Q1) 下界的计算公式为Q1-3(Q3-Q1)
# 由于数据量比较少 所以选择删除极端异常值
def remove_outliers(feature,all_data):first_quartile = all_data[feature].describe()['25%']third_quartile = all_data[feature].describe()['75%']iqr = third_quartile - first_quartile# 异常值下标index = all_data[(all_data[feature] < (first_quartile - 3*iqr)) | (all_data[feature] > (first_quartile + 3*iqr))].indexall_data = all_data.drop(index)return all_data
outlier_features = ['Insulin', 'Glucose', 'BloodPressure', 'SkinThickness', 'BMI', 'DiabetesPedigreeFunction']
for feat in outlier_features:all_data = remove_outliers(feat,all_data)

处理之后的数据基本的统计信息

缺失值处理

为了防止数据泄露,尽量在划分训练集测试集之后,即不要在整体数据上做preprocessing 所以缺失数值填充最好分开进行处理

缺失值处理这里考虑

  1. 直接删除处理
def drop_method(all_data):median_fill = ['Glucose', 'BloodPressure','SkinThickness', 'BMI','Height']for column in median_fill:median_val = all_data[column].median()all_data[column].fillna(median_val, inplace=True)all_data.dropna(inplace = True)return all_data
  1. 中值填充
def median_method():for column in list(all_data.columns[all_data.isnull().sum() > 0]):median = all_data[column].median()all_data[column].fillna(median, inplace=True)
  1. KNNImputer填充
def knn_method():# 先将缺失值比较少的特征用中值填充values = {'Glucose': all_data['Glucose'].median(),'BloodPressure':all_data['BloodPressure'].median(),'BMI':all_data['BMI'].median()}all_data.fillna(value=values,inplace=True)# 用KNNImputer 填充 Insulin SkinThicknesscorr_SkinThickness = ['BMI', 'Glucose','BloodPressure', 'SkinThickness']# 权重按距离的倒数表示。在这种情况下,查询点的近邻比远处的近邻具有更大的影响力SkinThickness_imputer = KNNImputer(weights = 'distance')all_data[corr_SkinThickness] = SkinThickness_imputer.fit_transform(all_data[corr_SkinThickness])corr_Insulin = ['Glucose', 'BMI','BloodPressure', 'Insulin']Insulin_imputer = KNNImputer(weights = 'distance')all_data[corr_Insulin] = Insulin_imputer.fit_transform(all_data[corr_Insulin])
  1. 随机森林填充
from sklearn.ensemble import RandomForestRegressor
from sklearn.impute import SimpleImputer  # 用来填补缺失值
def predict_method(feature):# 复制一份数据 避免对原数据做出不必要的修改copy_data = all_data.copy()# 缺失了的下标predict_index = copy_data[copy_data[feature].isnull()].index# 没缺失的下标train_index = copy_data[feature].dropna().index# 用作预测 的训练集标签train_label = copy_data.loc[train_index,feature]copy_data = copy_data.drop(feature,axis=1)# 对特征先用中值填充imp_median = SimpleImputer(strategy='median')# 用作预测的训练集特征train_feature = copy_data.loc[train_index]train_feature = imp_median.fit_transform(train_feature)# 需要进行预测填充处理的缺失值pre_feature = copy_data.loc[predict_index]pre_feature = imp_median.fit_transform(pre_feature)# 选取随机森林模型fill_model = RandomForestRegressor()fill_model = fill_model.fit(train_feature,train_label)# 预测 填充pre_value = fill_model.predict(pre_feature)all_data.loc[predict_index,feature] = pre_value#用随机森林的方法填充缺失值较多的 SkinThickness 和 Insulin 缺失值
predict_method("Insulin")
predict_method("SkinThickness")
# 其余值中值填充
for column in list(all_data.columns[all_data.isnull().sum() > 0]):median = all_data[column].median()all_data[column].fillna(median, inplace=True)

特征工程

# 特征
feture_data = all_data.drop('Outcome',1)
# 标签
label = all_data['Outcome']
# 利用BMI和身高构造weight特征
# BMI = weight(kg) / height(m)**2
feture_data['weight'] = (0.01*feture_data['Height'])**2 * feture_data['BMI']

数据标准化

# 标准化
Std = StandardScaler()
feture_data = Std.fit_transform(feture_data)

模型构建与调参优化

用到的模型

from sklearn.svm import SVC,SVR
from sklearn.tree import DecisionTreeClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier,StackingClassifier

调参方法

from sklearn.model_selection import GridSearchCV

评估指标 Accuracy roc_auc

from sklearn.metrics import make_scorer from sklearn.metrics import
accuracy_score from sklearn.metrics import roc_auc_score

def train(model, params):grid_search = GridSearchCV(estimator = model, param_grid = params,scoring=scores,refit='Accuracy')grid_search.fit(feture_data,label)print(grid_search.best_estimator_)return grid_searchdef paint(x,y):plt.figure()sns.lineplot(x=x,y=y)plt.show()

SVC

#调参时先尝试一个大范围,确定比较小的范围,然后在小范围里搜索
model = SVC()
params  =  {'C':np.linspace(0.1, 2, 100)}
SVC_grid_search = train(model,params)paint([x for x in range(100)],SVC_grid_search.cv_results_['mean_test_Accuracy'])
paint([x for x in range(100)],SVC_grid_search.cv_results_['mean_test_AUC'])
print("test_Accuracy : {}\ntest_AUC : {}".format(SVC_grid_search.cv_results_['mean_test_Accuracy'].mean(),SVC_grid_search.cv_results_['mean_test_AUC'].mean()))

LogisticRegression

model = LogisticRegression()
params = {"C":np.linspace(0.1,2,100)}
LR_grid_search = train(model,params)paint([x for x in range(100)],LR_grid_search.cv_results_['mean_test_Accuracy'])
paint([x for x in range(100)],LR_grid_search.cv_results_['mean_test_AUC'])
print("test_Accuracy : {}\ntest_AUC : {}".format(LR_grid_search.cv_results_['mean_test_Accuracy'].mean(),LR_grid_search.cv_results_['mean_test_AUC'].mean()))

RandomForestClassifier

model = RandomForestClassifier()
params = {"n_estimators":[x for x in range(30,50,2)],'min_samples_split':[x for x in range(4,10)]}
RFC_grid_search = train(model,params)
print("test_Accuracy : {}\ntest_AUC : {}".format(RFC_grid_search.cv_results_['mean_test_Accuracy'].mean(),RFC_grid_search.cv_results_['mean_test_AUC'].mean()))

StackingClassifier

estimators = [('SVC',SVC_grid_search.best_estimator_),('NB', LR_grid_search.best_estimator_),('RFC', RFC_grid_search.best_estimator_)
]
model = StackingClassifier(estimators=estimators, final_estimator=SVC())
model_score = cross_validate(model,feture_data, label,scoring=scores)
print("test_Accuracy : {}\ntest_AUC : {}".format(model_score['test_Accuracy'].mean(),model_score['test_AUC'].mean()))

SVC预测结果:

  1. 直接删除缺失值以及异常值删除公式上限Q3+1.5(Q3-Q1);下限计算公式为Q1-1.5(Q3-Q1)
    SVC(C=1.097979797979798)
    test_Accuracy : 0.8549075391180654
    test_AUC : 0.511601411290322

  2. 直接删除缺失值以及异常值删除公式上限Q3+3(Q3-Q1);下限计算公式为Q1-3(Q3-Q1)
    SVC(C=1.405050505050505)
    test_Accuracy : 0.7953321596244133
    test_AUC : 0.7133755225726653

  3. 中值填充以及异常值删除公式上限Q3+3(Q3-Q1);下限计算公式为Q1-3(Q3-Q1)
    SVC(C=1.7888888888888888)
    test_Accuracy : 0.7814101086443079
    test_AUC : 0.7248522348166069

其余略

总结:

  1. 一些删除数据值的处理方法导致样本标签的不均衡会导致对比例大的样本造成过拟合,也就是说预测偏向样本数较多的分类。这样就会大大降低模型的泛化能力。表现在准确率很高,但roc_auc_score很低。上面SVC的预测结果就很好的说明了。
  2. 可以看出由于缺失值比较多,所以反而各种填充方法的效果比直接删除的效果是要更差的(也有可能我没找到合适的填充方法)
  3. 关于离群值的处理,主要方法有直接删除法,替换为缺失值处理,以及中值填充法等。由于缺失值处理那里的效果不是很理想,所以就选择了直接删除,并且在平衡了roc_auc_score和accuracy两个指标后,选择只删除极端异常点。
  4. 关于样本0/1比例的问题,可以考虑上采样或者下采样的方法平衡样本。本文不涉及。

完整代码

https://github.com/wang-hui-shan/Pima_Diabetes_Predict

特别鸣谢:评论区提建议的小伙伴>-<

sklearn预测pima糖尿病相关推荐

  1. python k-近邻算法 案例实战 预测Pima 印度安人的糖尿病

    前言 一.目的和要求 理解k-近邻算法的原理,掌握k-近邻算法的应用开发. 二.主要内容 实例:糖尿病预测 任务:预测Pima 印度安人的糖尿病 数据来源: https://www.kaggle.co ...

  2. 使用sklearn预测走势_Prophet: 时间序列预测库

    prophet是facebook开源的python预测库,该库的api设计与sklearn很像,也是分为fit方法和predict方法. prophet库可以帮助我们进行 Saturating For ...

  3. 使用Python、Pandas、Sklearn预测NBA比赛结果

    Abstract: 作为课程作业,下面的内容是利用每场胜负数据.球员的生物数据等进行的NBA比赛预测.内容包括:1. 获得数据 2. 构造特征 3. 学习验证.最后能够提升16%的准确率. 获取数据集 ...

  4. 机器学习实战3.4决策树项目案例03:使用Sklearn预测隐形眼镜类型

    搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多人工智能.机器学习干货 csdn:https://blog.csdn.net/baidu_31657889/ github ...

  5. 使用sklearn预测共享单车出行情况

    近期文章 导入数据 import pandas as pd df = pd.read_csv('data/train.csv') df.head() 我们看一下季节和假期对出行对影响,用到seabor ...

  6. sklearn预测评估指标:混淆矩阵计算详解-附Python计算代码

    目录 前言 混淆矩阵 python代码 前言 很多时候需要对自己模型进行性能评估,对于一些理论上面的知识我想基本不用说明太多,关于校验模型准确度的指标主要有混淆矩阵.准确率.精确率.召回率.F1 sc ...

  7. sklearn预测评估指标计算详解:准确率(Accuracy)、精确率(Precision)、召回率(Recall)、F1score

    目录 前言 一.准确率 二.精确率 三.召回率 四.F1-score

  8. 学习笔记——仅仅为了留下Pima印第安人糖尿病发病数据集的网址

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/qq_42370150/article/ ...

  9. python预测糖尿病_实战 | 糖尿病预测项目

    项目介绍 这次我们要学习的项目是糖尿病的预测,数据保存在diabetes.csv文件中.数据一共有8个特征和1个标签: Pregnancies:怀孕次数Glucose:葡萄糖测试值BloodPress ...

最新文章

  1. 3D游戏编程入门(十五)索引缓存
  2. linux 查询内存和核心数,Linux下查看操作系统信息、内存情况及cpu信息:cpu个数、核心数、线程数...
  3. css布局模型详细介绍
  4. linux ftp匿名只能下载,04. 创建匿名用户能够上传下载,或只能下载的目录
  5. html动画加载效果,CSS3 实现 Loading(加载)动画效果
  6. 线段树(Segment Tree)
  7. 鸟哥私房菜整理(二)
  8. java页面注册_java编写注册页面
  9. DeepFool笔记:对原理的理解和公式推导(多分类)
  10. Ubuntu 18.04配置ORB-SLAM2+ROS实时运行ORB-SLAM2+SLAM相关库的安装 相关问题汇总(USB_CAM , ROS 编译问题)
  11. STM32CubeMX的使用教程
  12. java word 颜色设置_如何在Java中为word文档(.doc或.docx)设置背景颜色(页面颜色)?...
  13. 论文阅读笔记:《Neural3D: Light-weight Neural Portrait Scanning via Context-aware Correspondence Learning》
  14. Java GUI气泡诗词02
  15. Infortrend主要产品线全部支持25 GbE主机通道
  16. 【Java常用类】String和StringBuffer类(下)
  17. Http 403错误重现实验及解决方法
  18. SAP中通过成本核算表计算间接费用实例
  19. 认证密钥协商(Authentication key agreement)的安全目标
  20. PYTHON 100days学习笔记007-1:python数据类型补充(1)

热门文章

  1. 复旦大学2018--2019学年第一学期(18级)高等代数I期末考试第七大题解答
  2. python监控当前联网状态详情
  3. Ubuntu Linux 软件寻找/安装/卸载 图文详解教程
  4. MATLAB基于BP神经网络的手势识别
  5. 技术牛逼,就可以成为专家吗?
  6. CHM电子书加密器(最新版V2009.9)
  7. 【转】隐马尔科夫模型(HMM)及其Python实现
  8. 内部排序算法总结(use python)
  9. React Conf 2018 专题 —— React Today and Tomorrow Part I 视频中英双语字幕
  10. C/C++ 语言中表达式的求值