实战 | 糖尿病预测项目详解

糖尿病预测项目

 这次我们要学习的项目是糖尿病的预测,数据保存在diabetes.csv文件中。数据一共有8个特征和1个标签:

Pregnancies:怀孕次数Glucose:葡萄糖测试值BloodPressure:血压SkinThickness:皮肤厚度Insulin:胰岛素BMI:身体质量指数DiabetesPedigreeFunction:糖尿病遗传函数Age:年龄Outcome:糖尿病标签,1表示有糖尿病,0表示没有糖尿病


首先先载入一些常用模块

import numpy as np

import pandas as pd

import matplotlib.pyplot as plt

import seaborn as sns


然后用pandas读入数据

diabetes_data = pd.read_csv('diabetes.csv')

diabetes_data.head()


实战 | 糖尿病预测项目详解_第1张图片


# 查看数据信息

diabetes_data.info(verbose=True)


RangeIndex: 768 entries, 0 to 767

Data columns (total 9 columns):

Pregnancies                 768 non-null int64

Glucose                     768 non-null int64

BloodPressure               768 non-null int64

SkinThickness               768 non-null int64

Insulin                     768 non-null int64

BMI                         768 non-null float64

DiabetesPedigreeFunction    768 non-null float64

Age                         768 non-null int64

Outcome                     768 non-null int64

dtypes: float64(2), int64(7)

memory usage: 54.1 KB

我们从上面可以看到一共有768个数据,并且所有的特征和标签都是768个值,所有没有缺失数据。并且所有数据都是数值类型(int64 or float64)的数据。


# 数据描述

diabetes_data.describe()


实战 | 糖尿病预测项目详解_第2张图片

通过describe我们可以观察到数据的数量,平均值,标准差,最小值,最大值等数据。


# 数据形状

diabetes_data.shape

(768, 9)


# 查看标签分布

print(diabetes_data.Outcome.value_counts())

# 使用柱状图的方式画出标签个数统计

p=diabetes_data.Outcome.value_counts().plot(kind="bar")

0    500

1    268

Name: Outcome, dtype: int64



实战 | 糖尿病预测项目详解_第3张图片

# 可视化数据分布

p=sns.pairplot(diabetes_data, hue = 'Outcome')


实战 | 糖尿病预测项目详解_第4张图片

图片可能需要放大才能看清楚。这里画的图主要是两种类型,直方图和散点图。单一特征对比的时候用的是直方图,不同特征对比的时候用的是散点图,显示两个特征的之间的关系。观察数据分布我们可以发现一些异常值,比如Glucose葡萄糖,BloodPressure血压,SkinThickness皮肤厚度,Insulin胰岛素,BMI身体质量指数这些特征应该是不可能出现0值的。但是数据分布中却有很多0值。


# 把葡萄糖,血压,皮肤厚度,胰岛素,身体质量指数中的0替换为nan

colume = ['Glucose', 'BloodPressure', 'SkinThickness', 'Insulin', 'BMI']

diabetes_data[colume] = diabetes_data[colume].replace(0,np.nan)


# 查看数据空值情况

import missingno as msno

p=msno.bar(diabetes_data)


实战 | 糖尿病预测项目详解_第5张图片

图中可以看到葡萄糖,血压,皮肤厚度,胰岛素,身体质量指数都是存在空值的,并且皮肤厚度和胰岛素中的空值特别多。


# 设定阀值

thresh_count = diabetes_data.shape[0]*0.8

# 若某一列数据缺失的数量超过20%就会被删除

diabetes_data = diabetes_data.dropna(thresh=thresh_count, axis=1)

p=msno.bar(diabetes_data)


实战 | 糖尿病预测项目详解_第6张图片

把空值超过20%的特征都去除掉之后,只剩下6个特征。


# 导入插补库

from sklearn.preprocessing import Imputer

# 对数值型变量的缺失值,我们采用均值插补的方法来填充缺失值

imr = Imputer(missing_values='NaN', strategy='mean', axis=0)

colume =  ['Glucose', 'BloodPressure', 'BMI']

# 进行插补

diabetes_data[colume] = imr.fit_transform(diabetes_data[colume])

p=msno.bar(diabetes_data)


实战 | 糖尿病预测项目详解_第7张图片

使用特征的平均值给特征中的缺失值进行填充,填充后所有的数据就没有空值了。


plt.figure(figsize=(12,10))  

# 画热力图,数值为两个变量之间的相关系数

p=sns.heatmap(diabetes_data.corr(), annot=True)


实战 | 糖尿病预测项目详解_第8张图片

热力图可能也需要放大来看,它是表示两个数据之间的相关性,数值范围是-1到1之间,大于0表示两个数据是正相关的,小于0表示两个数据是负相关的,等于0就是不相关。我们可以看到有一条对角线上的数值都是1,两个数据如果是相同的两个数据,那么他们的相关系数就是1。并且这个相关系数矩阵是对称的。


我们可以观察到一些比较明显的特征,比如Age年龄跟Pregnancies怀孕次数有比较强的相关性,也就是说年龄越大怀孕次数就越多,或者怀孕次数越多年龄就越大,这应该是比较合理的一个情况。


糖尿病的标签Outcome和Glucose葡萄糖测试值正相关系数比较大,也就是说葡萄糖测试值比较高的话,那么就很可能患有糖尿病。


# 把数据切分为特征x和标签y

x = diabetes_data.drop("Outcome",axis = 1)

y = diabetes_data.Outcome from sklearn.model_selection import train_test_split

# 切分数据集,test_size=0.3表示30%为测试集。stratify=y表示切分后训练集和测试集中的数据类型的比例跟切分前y中的比例一致

# 比如切分前y中0和1的比例为1:2,切分后y_train和y_test中0和1的比例也都是1:2

x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.3, stratify=y)


# 导入KNN算法

from sklearn.neighbors import KNeighborsClassifier

# 保存不同k值测试集准确率

test_scores = []

# 保存不同k值训练集准确率

train_scores = []

x_train_values = x_train.values

y_train_values = y_train.values

# 设置30个k值

k = 30

for i in range(1,k):

    knn = KNeighborsClassifier(i)

    knn.fit(x_train,y_train)

    # 保存测试集准确率

    test_scores.append(knn.score(x_test,y_test))

    # 保存训练集准确率

    train_scores.append(knn.score(x_train,y_train))


plt.title('k-NN Varying number of neighbors')

plt.plot(range(1,k),test_scores,label="Test")

plt.plot(range(1,k),train_scores,label="Train")

plt.legend()

plt.xticks(range(1,k))

plt.xlabel('k')

plt.ylabel('accuracy')

plt.show()


实战 | 糖尿病预测项目详解_第9张图片

不同k值得到不同的准确率结果。


# 选择一个最好的k值作为模型参数

k = np.argmax(test_scores)+1

knn = KNeighborsClassifier(k)

knn.fit(x_train,y_train)

knn.score(x_test,y_test)

0.8138528138528138


from sklearn.metrics import confusion_matrix

from sklearn.metrics import classification_report

y_pred = knn.predict(x_test)

print(classification_report(y_pred, y_test))

              precision    recall  f1-score   support


           0       0.88      0.84      0.86       157

           1       0.69      0.76      0.72        74


   micro avg       0.81      0.81      0.81       231

   macro avg       0.79      0.80      0.79       231

weighted avg       0.82      0.81      0.82       231

macro avg:宏平均,所有类的算数平均数micro avg:分母就是输入分类器的预测样本个数,分子就是预测正确的样本个数weighted avg:加权平均,每个类别的权值为:类别suppot/总suppot


confusion = confusion_matrix(y_pred, y_test)

df_cm = pd.DataFrame(confusion)

sns.heatmap(df_cm, annot=True)


实战 | 糖尿病预测项目详解_第10张图片

混淆矩阵,测试集中非糖尿病被预测为非糖尿病有130例,糖尿病被预测为糖尿病有56例,非糖尿病被预测为糖尿病有25例,糖尿病被预测为非糖尿病有18例子。

你可能感兴趣的:(实战 | 糖尿病预测项目详解)