基于机器学习的皮马印第安人糖尿病预测
本文是针对Kaggle上面一份皮马印第安人糖尿病的数据的建模,属于机器学习中的二分类问题。原数据地址:
https://www.kaggle.com/code/vincentlugat/pima-indians-diabetes-eda-prediction-0-906/data
目录
本文的整体目录:
导入库
1 | import pandas as pd |
数据概况
数据基本信息
In [3]:
1 | df = pd.read_csv("diabetes.csv") |
Out[3]:
整体的数据量信息:
In [3]:
1 | df.shape |
Out[3]:
1 | (768, 9) |
数据缺失值情况:
In [4]:
1 | df.isnull().sum() |
Out[4]:
1 | Pregnancies 0 |
In [5]:
1 |
|
Out[5]:
1 | Pregnancies int64 |
In [6]:
1 | df.info() |
查看数据的描述统计信息,针对数值型的字段。本案例全部是数值型字段:
In [7]:
1 | df.describe() |
Out[7]:
字段解释
In [8]:
1 | columns = df.columns |
Out[8]:
1 | Index(['Pregnancies', 'Glucose', 'BloodPressure', 'SkinThickness', 'Insulin', |
- Pregnancies:妊娠期周数
- Glucose:葡萄糖含量
- BloodPressure:血压
- SkinThickness:皮肤厚度
- Insulin:胰岛素含量
- BMI:身体的BMI指标
- DiabetesPedigreeFunction:糖尿病系谱函数值
- Age:年龄
- Outcome:最终的分类标签;0-健康,1-糖尿病患者
不同Outcome下的人群对比
查看不同最终的分类标签数据分布情况:
In [9]:
1 | D = df[df["Outcome"] != 0] |
In [10]:
1 | df1 = df["Outcome"].value_counts().reset_index() |
Out[10]:
Outcome | Count | |
---|---|---|
0 | 0 | 500 |
1 | 1 | 268 |
In [11]:
1 | fig = px.bar(df1, |
In [12]:
1 | def target_percent(): |
缺失值处理
数据中部分字段的取值为0,在这里我们认为:0是缺失值
In [13]:
1 | df[['Glucose','BloodPressure','SkinThickness','Insulin','BMI']] = df[['Glucose','BloodPressure','SkinThickness','Insulin','BMI']].replace(0,np.NaN) # 0用空值代替 |
缺失值比例可视化:
In [14]:
1 | def missing_plot(df, key): |
字段分布
不同字段下的数据分布情况:
In [15]:
1 | plt.style.use('ggplot') # 指定风格 |
相关系数热力图
查看不同字段间的相关性强弱:
In [16]:
1 | corr = df.corr() |
Out[16]:
1 | array([[ 1. , 0.12813455, 0.21417848, 0.10023907, 0.08217103, |
In [17]:
1 | corr.head() |
Out[17]:
针对原始数据的相关系数热力图:
1 | trace = go.Heatmap(x=matrix_cols, |
使用seaborn快速实现:
In [20]:
1 | sns.heatmap(corr) |
缺失值均值填充
In [21]:
1 | df.isnull().sum() |
Out[21]:
1 | Pregnancies 0 |
根据Outcome进行分组统计,使用均值填充该字段的缺失值:
In [22]:
1 | def fill_median(col): |
字段Insulin
In [23]:
1 |
In [24]:
1 | def plot_distribution(col, bin_size): |
查看不同Outcome下的均值并填充:
In [25]:
1 | fill_median("Insulin") |
Out[25]:
Outcome | Insulin | |
---|---|---|
0 | 0 | 102.5 |
1 | 1 | 169.5 |
In [26]:
1 | df.loc[(df['Outcome'] == 0 ) & (df['Insulin'].isnull()), 'Insulin'] = 102.5 |
字段Glucose
In [27]:
1 | plot_distribution("Glucose",0) |
1 | df.loc[(df['Outcome'] == 0 ) & (df['Glucose'].isnull()), 'Glucose'] = 107 |
字段SkinThickness
In [30]:
1 | plot_distribution("SkinThickness",0) |
1 | fill_median("SkinThickness") |
字段BMI
In [33]:
1 | plot_distribution("BMI",0) |
字段BloodPressure
In [36]:
1 | plot_distribution("BloodPressure", 0) |
其他不存在缺失值的字段的分布情况:
In [39]:
1 | plot_distribution("Age",0) |
填充之后再次查看数据的缺失值情况:已经不存在缺失值
In [42]:
1 | missing_plot(df,"Outcome") |
特征构建及EDA
创建3个绘图函数:
两两特征关系
In [43]:
1 | def plot_feat1_feat2(feat1, feat2) : |
指定特征绘图
In [44]:
1 | def barplot(var_select, sub) : |
指定特征下不同Outcome人群占比
In [45]:
1 | def plot_pie(var_select, sub) : |
Glucose和Age关系
In [46]:
1 | plot_feat1_feat2('Glucose','Age') |
绘制二者关系的散点图,并标记密集区域:
In [47]:
1 | palette ={0 : 'lightblue', 1 : 'gold'} |
创建后一个新特征:N1
In [48]:
1 | df.loc[:,'N1']=0 |
In [49]:
1 | barplot('N1', ':Glucose <= 120 and Age <= 30') |
基于BMI新特征-N2
In [51]:
1 | df.loc[:,'N2']=0 |
In [52]:
1 | barplot('N2', ': BMI <= 30') |
不同Outcome下的占比:
In [53]:
1 | plot_pie('N2', 'BMI <= 30') |
Pregnancies 和 Age关系
In [54]:
1 | plot_feat1_feat2('Pregnancies','Age') |
1 | palette ={0 : 'lightblue', 1 : 'gold'} |
构造特征N3:
Glucose和BloodPressure关系
In [59]:
1 | px.scatter(df, |
1 | palette ={0 : 'lightblue', 1 : 'gold'} |
构建新特征N4:
In [62]:
1 | # 新特征 |
基于SkinThickness构建特征
In [63]:
1 | df.loc[:,'N5']=0 |
In [64]:
1 | barplot('N5', ':SkinThickness <= 20') |
SkinThickness 和 BMI的关系
In [65]:
1 | plot_feat1_feat2('SkinThickness','BMI') |
1 | df.loc[:,'N6']=0 |
1 | barplot('N6', ': BMI < 30 and SkinThickness <= 20') |
Glucose和BMI的关系
In [69]:
1 | plot_feat1_feat2('Glucose','BMI') |
1 | palette ={0 : 'lightblue', 1 : 'gold'} |
1 | df.loc[:,'N7']=0 |
基于Insulin构建特征
In [72]:
1 |
|
1 | df.loc[:,'N9']=0 |
基于BloodPressure构建特征
In [74]:
1 | df.loc[:,'N10']=0 |
In [75]:
1 | barplot('N10', ': BloodPressure < 80') |
基于Pregnancies构建特征
In [76]:
1 | plot_distribution('Pregnancies', 0) |
1 | df.loc[:,'N11']=0 |
其他特征衍生
In [78]:
1 | df['N0'] = df['BMI'] * df['SkinThickness'] |
In [79]:
1 | D = df[(df['Outcome'] != 0)] |
In [80]:
1 | plot_distribution('N0', 0) |
1 | df.loc[:,'N15']=0 |
构造了多个新特征后的数据:
建模
In [83]:
1 | df.nunique() |
Out[83]:
1 | Pregnancies 17 |
In [84]:
1 | df.nunique()[df.nunique() < 12] # 字段的唯一值小于12种 |
Out[84]:
1 | Outcome 2 |
In [85]:
1 | df.nunique()[df.nunique() < 12].keys().tolist() |
Out[85]:
1 | ['Outcome', |
特征分类
根据每个特征的唯一值不同,将特征分为数值型特征和分类型特征
In [86]:
1 | target_col = ["Outcome"] |
编码
In [87]:
1 | le = LabelEncoder() |
In [88]:
1 | df = pd.get_dummies(data=df,columns=multi_cols) |
数据标准化
In [89]:
1 | std = StandardScaler() |
In [90]:
1 | df_copy = df.copy() |
Out[90]:
新数据的相关系数矩阵
In [91]:
1 | corr = df.corr() |
切分特征和标签
In [92]:
1 | X = df.drop('Outcome', 1) |
模型评估
定义一个函数model_performance来评估不同分类模型的性能:
In [93]:
1 | def model_performance(model, subtitle) : |
不同模型不同指标的得分显示:
In [94]:
1 | def scores_table(model, subtitle): |
构建LGBM模型
In [95]:
1 | random_state=42 |
In [96]:
1 | model_performance(lgbm_clf, 'LightGBM') |
构建KNN分类模型
1 | knn_clf = KNeighborsClassifier() |
1 | visualizer = DiscriminationThreshold(voting_clf) |
数据获取
关于本文的数据集获取方式,关注【尤而小屋】,回复糖尿病即可领取