糖尿病数据分析:血压与年龄关系可视化

一、查看数据信息

python 复制代码
import matplotlib.pyplot as plt				
import pandas as pd
import matplotlib.font_manager as fm
from sklearn.feature_selection import SelectKBest,chi2
plt.rcParams['font.sans-serif']=['SimHei']
#数据探索
data = pd.read_excel(r"D:\Python\健康医学数据分析\第9章 医学实践综合案例源代码\案例4:糖尿病致病因素数据分析与可视化\diabetes.xlsx")		# 读取文件
data.info()									# 查看数据信息
data.describe()

代码解析:

  1. 导入库

    • matplotlib.pyplot:用于数据可视化
    • pandas:用于数据处理和分析
    • matplotlib.font_manager:用于管理字体
    • sklearn.feature_selection:用于特征选择(虽然导入但未使用)
  2. 字体设置

    • plt.rcParams['font.sans-serif']=['SimHei']:设置matplotlib使用黑体(SimHei)显示中文,避免中文乱码
  3. 数据加载

    • 使用pd.read_excel()从指定路径读取Excel文件
    • 文件路径指向一个糖尿病数据集(diabetes.xlsx)
  4. 数据探索

    • data.info():显示数据的基本信息,包括:
      • 列名和数据类型
      • 非空值数量
      • 内存使用情况
    • data.describe():显示数据的统计摘要,包括:
      • 计数(count)
      • 均值(mean)
      • 标准差(std)
      • 最小值(min)
      • 四分位数(25%, 50%, 75%)
      • 最大值(max)

运行结果:

二、 绘制箱线图查看异常值

python 复制代码
# 绘制箱线图查看异常值
fig = plt.figure(figsize=(20, 15))
plt.subplot(421)
plt.boxplot(data['Pregnancies'],showmeans=True,patch_artist='bule')
plt.title('怀孕次数',fontsize='x-large')
plt.ylabel('人数')

plt.subplot(422)
plt.boxplot(data['Glucose'],showmeans=True,patch_artist='bule')
plt.title('口服葡萄糖耐量试验中血浆葡萄糖浓度',fontsize='x-large')
plt.ylabel('人数')

plt.subplot(423)
plt.boxplot(data['BloodPressure'],showmeans=True,patch_artist='bule')
plt.title('舒张压',fontsize='x-large')
plt.ylabel('人数')

plt.subplot(424)
plt.boxplot(data['SkinThickness'],showmeans=True,patch_artist='bule')
plt.title('三头肌组织褶厚度',fontsize='x-large')
plt.ylabel('人数')

plt.subplot(425)
plt.boxplot(data['Insulin'],showmeans=True,patch_artist='bule')
plt.title('2小时血清胰岛素',fontsize='x-large')
plt.ylabel('人数')

plt.subplot(426)
plt.boxplot(data['BMI'],showmeans=True,patch_artist='bule')
plt.title('身体质量指数(BMI)',fontsize='x-large')
plt.ylabel('人数')

plt.subplot(427)
plt.boxplot(data['DiabetesPedigreeFunction'],showmeans=True,patch_artist='bule')
plt.title('糖尿病系统功能',fontsize='x-large')
plt.ylabel('人数')

plt.subplot(428)
plt.boxplot(data['Age'],showmeans=True,patch_artist='bule')
plt.title('年龄',fontsize='x-large')
plt.ylabel('人数')
plt.show()

创建画布

python 复制代码
fig = plt.figure(figsize=(20, 15))  # 设置画布大小(宽20英寸,高15英寸)
  • 通过 figsize 调整整体图形大小,适合同时展示多个子图。

绘制子图

  • 使用 plt.subplot(421)plt.subplot(428) 将画布分为 4行2列共8个子图 ,每个子图对应一个特征:
    • Pregnancies(怀孕次数)
    • Glucose(葡萄糖浓度)
    • BloodPressure(舒张压)
    • SkinThickness(皮肤厚度)
    • Insulin(胰岛素)
    • BMI(身体质量指数)
    • DiabetesPedigreeFunction(糖尿病遗传函数)
    • Age(年龄)

箱线图参数

python 复制代码
plt.boxplot(data['列名'], showmeans=True, patch_artist='bule')
  • showmeans=True:显示均值(绿色三角标记)。
  • patch_artist='bule':试图设置箱体颜色为蓝色,但参数有误(正确应 为 patch_artist=True, boxprops={'facecolor':'blue'})。

标题和标签

每个子图添加中文标题(如 '怀孕次数')和纵轴标签('人数'),字体大小设为 x-large

显示图形

python 复制代码
plt.show()

运行结果:

三、将0值用平均值替换

python 复制代码
#将0值用平均值替换
for i in range(6):
    value = int(data.iloc[:,i].mean())
    data.iloc[:,i].replace(0,value=value,inplace=True)
data.head()

遍历前 6 列数据

python 复制代码
for i in range(6):  # 处理前6列(0到5列)
  • 假设数据集的前 6 列是数值型特征(如 Pregnancies, Glucose 等)。

计算列的平均值

python 复制代码
value = int(data.iloc[:, i].mean())  # 取整后的列均值
  • data.iloc[:, i] 选择第 i 列的所有行。
  • .mean() 计算该列的平均值,并用 int() 取整。

替换 0 值为均值

python 复制代码
data.iloc[:, i].replace(0, value=value, inplace=True)
  • 将当前列中所有 0 值替换为 value(均值)。
  • inplace=True 直接修改原数据,无需重新赋值。

查看处理后的数据

python 复制代码
data.head()  # 显示前5行,验证替换结果

运行结果:

四、查看不同年龄段血压情况,多重柱状图---血压

python 复制代码
#查看不同年龄段血压情况,多重柱状图---血压
row=0;num1=0;num2=0;num3=0;num20=0;num30=0;num40=0;num50=0;num60=0;num21=0;num31=0;num41=0;num51=0;num61=0;num22=0;num32=0;num42=0;num52=0;num62=0
for i in data.loc[:,"Outcome"]:
    if i==0:
        continue
        row+=1
    else:
        if data.loc[row,"BloodPressure"]<=60:
            num1+=1
            if 20<data.loc[row,"Age"]<=30:
                num20+=1
            elif 30<data.loc[row,"Age"]<=40:
                num30+=1
            elif 40<data.loc[row,"Age"]<=50:
                num40+=1
            elif 50<data.loc[row,"Age"]<=60:
                num50+=1
            else:
                num60+=1
        elif 60<data.loc[row,"BloodPressure"]<=90:
            num2+=1
            if 20<data.loc[row,"Age"]<=30:
                num21+=1
            elif 30<data.loc[row,"Age"]<=40:
                num31+=1
            elif 40<data.loc[row,"Age"]<=50:
                num41+=1
            elif 50<data.loc[row,"Age"]<=60:
                num51+=1
            else:
                num61+=1
        else:
            num3+=1
            if 20<data.loc[row,"Age"]<=30:
                num22+=1
            elif 30<data.loc[row,"Age"]<=40:
                num32+=1
            elif 40<data.loc[row,"Age"]<=50:
                num42+=1
            elif 50<data.loc[row,"Age"]<=60:
                num52+=1
            else:
                num62+=1
        row+=1
dataplot = pd.DataFrame({'分类': ['低血压','血压正常','高血压'],
                     '21岁-30岁':[num20,num21,num22],
                    '31岁-40岁':[num30,num31,num32],
                    '41岁-50岁':[num40,num41,num42],
                    '51岁-60岁':[num50,num51,num52],
                    '61岁-70岁':[num60,num61,num62]})
print(dataplot)
dataplot.plot(x='分类', kind='bar')
plt.xticks(rotation=360)
plt.ylabel('人数(人)', fontproperties='simhei')
plt.title("不同血压情况下的年龄分布")
plt.legend()
plt.show()
  1. 目标:统计糖尿病患者中,不同血压范围(低血压、正常血压、高血压)在各年龄段的人数。
  2. 血压分组
    • 低血压(≤60 mmHg)
    • 血压正常(60-90 mmHg)
    • 高血压(>90 mmHg)
  3. 年龄分组
    • 21-30岁
    • 31-40岁
    • 41-50岁
    • 51-60岁
    • 61-70岁
  4. 实现方式
    • 通过循环遍历每一行数据,手动统计每个血压和年龄组合的人数。
    • 使用多个变量(如 num20, num21 等)记录计数结果。
    • 最后将结果整理成表格并绘制柱状图。

优化代码:

python 复制代码
# 筛选糖尿病患者
diabetic_data = data[data['Outcome'] == 1].copy()

# 创建血压分组
bp_bins = [0, 60, 90, float('inf')]
bp_labels = ['低血压', '血压正常', '高血压']
diabetic_data['血压分组'] = pd.cut(diabetic_data['BloodPressure'], 
                                 bins=bp_bins, 
                                 labels=bp_labels)

# 创建年龄分组
age_bins = [20, 30, 40, 50, 60, 70]
age_labels = ['21-30岁', '31-40岁', '41-50岁', '51-60岁', '61-70岁']
diabetic_data['年龄分组'] = pd.cut(diabetic_data['Age'], 
                                 bins=age_bins, 
                                 labels=age_labels)

# 创建交叉表
cross_tab = pd.crosstab(diabetic_data['血压分组'], diabetic_data['年龄分组'])
print(cross_tab)

# 绘制分组柱状图
ax = cross_tab.plot(kind='bar', figsize=(12, 8), rot=0)
plt.title("糖尿病患者血压与年龄分布", fontsize=14)
plt.ylabel("人数(人)")
plt.xlabel("血压分类")
plt.legend(title="年龄段")

# 添加数据标签
for p in ax.patches:
    height = p.get_height()
    if height > 0:  # 只添加非零值的标签
        ax.annotate(f"{int(height)}", 
                    (p.get_x() + p.get_width() / 2, height), 
                    ha='center', va='bottom', xytext=(0, 3),
                    textcoords='offset points')
                    
plt.tight_layout()
plt.show()

代码分析:

  1. 简化数据处理

    • 使用 pd.cut() 函数代替手动分类,更高效且不易出错
    • 直接筛选糖尿病患者 (data[data['Outcome'] == 1])
  2. 改进分组逻辑

    • 血压分组:
      • 低血压 (≤60 mmHg)
      • 血压正常 (60-90 mmHg)
      • 高血压 (>90 mmHg)
    • 年龄分组:
      • 21-30岁
      • 31-40岁
      • 41-50岁
      • 51-60岁
      • 61-70岁
  3. 高效计数

    • 使用 pd.crosstab() 创建交叉表,替代手动计数变量
    • 自动处理分组间的计数关系
  4. 可视化优化

    • 添加数据标签,提高图表可读性
    • 优化图例标题 ("年龄段")
    • 调整图表尺寸和布局
    • 添加图表标题和轴标签
  5. 错误修复

    • 原代码中 continue 语句导致索引错误的问题已解决
    • 正确处理边界值 (如 60, 61 的处理)

运行结果:

五、找出对患糖尿病影响最大的因素

python 复制代码
# 找出对患糖尿病影响最大的因素
x = data.iloc[:,0:8]
y = data.iloc[:,8:9]
bestfeatures = SelectKBest(score_func=chi2,k = len(x.columns))
fit = bestfeatures.fit(x,y)
df_scores = pd.DataFrame(fit.scores_)
df_columns = pd.DataFrame(['怀孕次数','口服葡萄糖耐量试验中血浆葡萄糖浓度','舒张压','三头肌组织褶厚度','2小时血清胰岛素','身体质量指数(BMI)','糖尿病系统功能','年龄'])
df_feature_scores = pd.concat([df_scores,df_columns],axis = 1)
df_feature_scores.columns = ["得分","指标"]
df_sort =df_feature_scores.sort_values(by = "得分",ascending= False)
df_sort

数据准备

python 复制代码
x = data.iloc[:, 0:8]  # 选取前8列作为特征(怀孕次数、血糖等)
y = data.iloc[:, 8:9]  # 选取第9列(Outcome)作为目标变量
  • x:包含所有特征(自变量)。
  • y:包含标签(因变量,是否患糖尿病)。

卡方检验

python 复制代码
bestfeatures = SelectKBest(score_func=chi2, k=len(x.columns))
fit = bestfeatures.fit(x, y)
  • SelectKBest:选择得分最高的 k 个特征。
  • score_func=chi2:使用卡方检验计算特征重要性(适用于分类问题)。
  • k=len(x.columns):评估所有特征,不进行筛选。

整理结果

python 复制代码
df_scores = pd.DataFrame(fit.scores_)  # 卡方检验得分
df_columns = pd.DataFrame(['怀孕次数', '葡萄糖浓度', '舒张压', '皮肤厚度', 
                         '胰岛素', 'BMI', '糖尿病遗传函数', '年龄'])
df_feature_scores = pd.concat([df_scores, df_columns], axis=1)
df_feature_scores.columns = ["得分", "指标"]

排序输出

python 复制代码
df_sort = df_feature_scores.sort_values(by="得分", ascending=False)
  • 按得分从高到低排序,得分越高表示特征对糖尿病的影响越大。

卡方检验的原理

  • 用途:检验分类变量之间的独立性(此处是特征与糖尿病结果的关联性)。
  • 得分计算:卡方统计量越高,特征与目标变量的相关性越强。
  • 适用条件:特征必须是非负的(如计数、频率、二值化数据)。如果数据包含负数或连续值,需先进行分箱(离散化)。

运行结果:

相关推荐
Swizard9 分钟前
拒绝“狗熊掰棒子”!用 EWC (Elastic Weight Consolidation) 彻底终结 AI 的灾难性遗忘
python·算法·ai·训练
Spider赵毅10 分钟前
python实战 | 如何使用海外代理IP抓取Amazon黑五数据
python·tcp/ip·php
月光技术杂谈16 分钟前
基于Python的网络性能分析实践:从Ping原理到自动化监控
网络·python·性能分析·ping·时延·自动化监控
龘龍龙20 分钟前
Python基础学习(四)
开发语言·python·学习
洵有兮1 小时前
python第四次作业
开发语言·python
kkoral1 小时前
单机docker部署的redis sentinel,使用python调用redis,报错
redis·python·docker·sentinel
BoBoZz191 小时前
IterativeClosestPoints icp配准矩阵
python·vtk·图形渲染·图形处理
test管家2 小时前
PyTorch动态图编程与自定义网络层实战教程
python
laocooon5238578862 小时前
python 收发信的功能。
开发语言·python
清水白石0082 小时前
《Python 责任链模式实战指南:从设计思想到工程落地》
开发语言·python·责任链模式