ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Python实战:K-Means聚类与关联规则挖掘肥胖风险因素分析

2026/9/29 14:17:21 拓冰建站 浏览量
Python实战:K-Means聚类与关联规则挖掘肥胖风险因素分析 肥胖风险因素分析这件事很多人第一反应是算个BMI不就行了。但真做过健康数据分析的人都知道BMI只是一个粗糙的截面指标它既解释不了为什么同样体重的人一个代谢正常一个已经胰岛素抵抗也回答不了哪几类人最容易同时踩中多个风险因素。我这次做的项目就是用K-Means聚类把人群先分成几类画像再用关联规则把风险因素之间的共现关系挖出来最后用可视化把结论呈现给非技术背景的人看。整套流程从数据清洗到聚类、关联规则、图表输出全部用Python跑通源码结构清晰适合做数据分析入门到进阶的实战参考也适合健康管理、公共卫生方向的人拿来改造成自己的课题。1. 先搞清楚这份数据到底能回答什么问题1.1 肥胖风险分析的常见误区很多人拿到一份健康问卷数据第一件事就是算相关系数然后发现吃甜食和肥胖的相关系数只有0.2出头就觉得数据没用。问题出在哪肥胖从来不是单一因素导致的它是饮食、运动、睡眠、遗传、心理状态多个维度长期叠加的结果。用线性相关系数去衡量这种多因素耦合关系本身就不合适。我在项目初期也踩过这个坑。最开始想用逻辑回归直接预测是否肥胖结果模型AUC只有0.68特征重要性排序也很平看不出重点。后来换了个思路先把人群按整体健康行为模式聚成几类再在每一类内部看风险因素的组合规律。这个转变是整个项目的关键转折点也是我建议所有做健康数据分析的人优先考虑的分析路径。1.2 数据集字段与业务含义这份数据来自公开的健康行为调查数据集经过脱敏处理包含约2000条个体记录。核心字段大致分为几组字段类别代表字段数据类型业务含义人口学Age, Gender, Height, Weight数值/类别基础身份与体型信息饮食习惯FAVC, FCVC, NCP, CAEC类别/数值高频蔬菜、主餐数、两餐间进食生活方式SMOKE, SCC, CALC, MTRANS类别吸烟、热量监测、饮酒、交通方式身体状态BMI, family_history数值/类别体重指数、家族肥胖史目标变量是NObeyesdad把人群分成Insufficient_Weight、Normal_Weight、Overweight_Level_I、Overweight_Level_II、Obesity_Type_I、Obesity_Type_II、Obesity_Type_III七档。这个七分类设计比简单的胖/不胖二分类信息量大得多也是后面聚类能出细粒度画像的基础。1.3 为什么选K-Means而不是其他聚类聚类算法一大堆DBSCAN、层次聚类、GMM都能用我最终选K-Means有三个现实理由。第一数据经过标准化后各维度量纲统一K-Means基于欧氏距离的假设成立第二K-Means的结果解释成本低质心可以直接翻译成这类人的典型特征第三数据量在2000条这个级别K-Means的收敛速度和稳定性都很好不需要调太多参数。DBSCAN我试过密度参数eps稍微变一点聚类结果就剧烈波动而且大量样本被划成噪声点对后续画像分析不友好。GMM理论上更灵活但需要假设每个簇服从高斯分布健康行为数据明显不满足这个假设。所以K-Means是这个场景下的务实选择不是因为它最先进而是因为它最匹配当前数据特征和业务解释需求。2. 数据预处理里那些不写进论文但必须做的事2.1 缺失值与异常值的处理逻辑原始数据里BMI字段有几条明显异常比如身高1.6米体重30公斤算出BMI只有11.7这种记录大概率是录入错误。我的处理方式是先按BMI的3倍标准差原则标记异常再人工核对原始记录确认是错误后直接剔除而不是用均值填充。健康数据里异常值往往携带真实信息盲目填充会污染整个分布。缺失值方面CAEC两餐间进食频率有少量缺失我用众数填充。这里有个细节不要用全局众数而是按NObeyesdad分组后取组内众数。因为不同体重档位的人两餐间进食习惯本身就不同用全局众数会把组间差异抹平。# 分组众数填充示例 df[CAEC] df.groupby(NObeyesdad)[CAEC].transform( lambda x: x.fillna(x.mode()[0] if not x.mode().empty else Sometimes) )2.2 类别变量的编码策略数据里有大量有序类别变量比如CAEC的取值是no、Sometimes、Frequently、Always这是典型的有序变量。很多人直接上One-Hot编码结果维度爆炸不说还丢掉了顺序信息。我的做法是有序变量用序数编码no0, Sometimes1, Frequently2, Always3无序变量如MTRANS交通方式才用One-Hot。这个选择直接影响聚类结果。如果CAEC用One-HotK-Means在计算距离时会把no和Always当成完全无关的两个维度而实际上它们在同一条轴上。序数编码保留了这种单调关系聚类出的画像更符合直觉。2.3 标准化别小看这一步K-Means对量纲极度敏感。Age范围是14到61FCVC范围是1到3如果不标准化Age会主导整个距离计算聚类结果基本就是按年龄分。我用的是StandardScaler做Z-score标准化让每个维度均值为0方差为1。注意标准化参数必须只在训练集上fit然后transform到全量数据。虽然这里是无监督学习没有严格意义上的训练测试划分但如果你后续要做聚类结果的稳定性验证这个习惯要养成。3. K-Means聚类的参数选择与画像解读3.1 确定K值肘部法则加轮廓系数双验证K值选多少这是聚类项目里最容易被拍脑袋决定的一步。我用了两个指标交叉验证。肘部法则看SSE簇内平方和随K变化的拐点轮廓系数看簇的分离度。实测下来K4时SSE下降明显放缓轮廓系数也在K4达到局部峰值0.31。轮廓系数0.31不算高但在健康行为这种高噪声数据里已经可以接受。我试过K3和K5K3时把Overweight和Obesity混在一起区分度不够K5时多出来的那个簇只有几十个样本没有业务解释价值。所以K4是统计指标和业务可解释性的平衡点。from sklearn.cluster import KMeans from sklearn.metrics import silhouette_score sse, sil [], [] for k in range(2, 9): km KMeans(n_clustersk, random_state42, n_init10) labels km.fit_predict(X_scaled) sse.append(km.inertia_) sil.append(silhouette_score(X_scaled, labels))3.2 四个簇的画像特征拆解跑完K-Means后我把每个簇的质心反标准化还原成原始量纲得到四类人群画像簇编号样本占比典型特征风险等级Cluster 028%年轻、运动少、高频外食、BMI偏高中高风险Cluster 135%饮食规律、有热量监测、BMI正常低风险Cluster 222%家族肥胖史、两餐间进食频繁、BMI高高风险Cluster 315%中年、吸烟、饮酒频繁、BMI中高中风险Cluster 2是我最关注的一类。他们的BMI均值达到32以上家族史阳性比例超过80%而且两餐间进食频率显著高于其他簇。这类人如果只靠少吃多动的通用建议效果往往很差因为他们的问题是多因素叠加的。3.3 聚类结果的稳定性验证聚类做完不能直接信得验证稳定性。我的做法是随机抽取80%样本重复聚类10次看每次的簇划分和原始划分的ARI调整兰德指数。实测平均ARI在0.75以上说明聚类结构比较稳定。如果ARI低于0.6就要考虑是不是K值选错了或者数据本身没有明显的簇结构。另一个验证角度是看簇内样本的分布是否合理。Cluster 3只有15%的样本但它的特征非常鲜明吸烟加饮酒这不是噪声簇而是真实存在的一个亚群体。判断标准是如果一个小簇在多个随机子样本中都能稳定出现它就是有意义的。4. 关联规则挖掘找出风险因素的共现模式4.1 Apriori算法的参数设定关联规则用Apriori算法核心参数是支持度、置信度和提升度。支持度设太低会挖出一堆偶然共现的规则设太高又什么都挖不到。我经过几轮测试最终定在最小支持度0.1、最小置信度0.6、最小提升度1.2。提升度大于1.2意味着规则的前件和后件有正相关不是随机共现。比如家族肥胖史 - 高频两餐间进食这条规则提升度1.8说明有家族史的人出现高频进食的概率是无家族史人群的1.8倍这个关联有实际意义。from mlxtend.frequent_patterns import apriori, association_rules freq_items apriori(df_encoded, min_support0.1, use_colnamesTrue) rules association_rules(freq_items, metricconfidence, min_threshold0.6) rules rules[rules[lift] 1.2].sort_values(lift, ascendingFalse)4.2 高价值规则的业务解读挖出来的规则里有几条特别值得说第一条{家族肥胖史, 高频两餐间进食} - {肥胖}支持度0.14置信度0.78提升度2.1。这条规则说明有家族史且爱吃零食的人肥胖概率极高。单独看家族史置信度只有0.55单独看高频进食置信度0.48。两个因素叠加后置信度跳到0.78这就是关联规则的价值——它捕捉到了交互效应。第二条{不运动, 常喝含糖饮料} - {超重}支持度0.11置信度0.71提升度1.6。这条规则对应的是典型的能量摄入高、消耗低模式。第三条比较反直觉{有热量监测, 肥胖}置信度0.65。乍一看监测热量的人反而胖很荒谬但结合业务一想就通了——很多人是因为已经胖了才开始监测热量这是因果方向的问题。这条规则提醒我们关联规则只能说明共现不能说明因果解读时必须结合业务背景。4.3 关联规则与聚类结果的交叉验证把关联规则的结果和聚类画像对照会发现高度一致。Cluster 2高风险簇的典型特征正好对应第一条高提升度规则的前件组合。这种交叉验证很有价值聚类从样本相似性角度分组关联规则从特征共现角度找规律两条路径指向同一个结论说明发现是稳健的。如果两者结论矛盾比如聚类说A和B总在一起但关联规则说A和B的提升度小于1那就要回头检查数据编码或参数设置是不是有问题。5. 可视化让非技术背景的人也能看懂结论5.1 聚类结果的降维可视化高维聚类结果直接画不出来我用PCA降到二维做散点图。虽然PCA会损失一部分信息但用于展示簇的分离程度足够了。四个簇在二维平面上有明显边界Cluster 2和其他簇的距离最远视觉上就能看出这类人群的特殊性。代码上用matplotlib加seaborn每个簇用不同颜色质心用大号标记标出。这里有个细节散点图要加透明度alpha0.6否则样本重叠严重时看不出密度分布。5.2 风险因素热力图与雷达图热力图用来展示各簇在关键特征上的均值差异。行是簇列是特征颜色深浅代表标准化后的均值高低。一眼就能看出Cluster 2在BMI、家族史、两餐间进食三个维度上颜色最深。雷达图适合展示单个簇的多维特征轮廓。我把四个簇的雷达图并排放在一张画布上每个轴是一个特征维度。Cluster 1的图形接近正多边形各维度均衡Cluster 2的图形在风险维度上明显外凸这种视觉对比比表格更有冲击力。5.3 关联规则的可视化呈现关联规则用网络图展示最直观。节点是特征项边是规则边的粗细代表提升度大小。用networkx加matplotlib绘制节点大小按支持度缩放。这样一张图能同时呈现几十条规则比逐条列文字高效得多。提示网络图节点超过20个时会很乱建议只展示提升度排名前15的规则或者按后件分组分图展示。6. 源码结构与复现要点6.1 项目目录组织源码按功能模块拆分不是把所有代码堆在一个notebook里obesity_analysis/ ├── data/ │ ├── raw/ # 原始数据 │ └── processed/ # 清洗后数据 ├── src/ │ ├── preprocess.py # 清洗、编码、标准化 │ ├── clustering.py # K-Means聚类与验证 │ ├── rules.py # 关联规则挖掘 │ └── visualize.py # 所有图表生成 ├── outputs/ │ ├── figures/ # 图表输出 │ └── reports/ # 分析报告 └── main.py # 主流程入口这样拆分的好处是每个模块可以独立测试。比如调聚类参数时不用重新跑数据清洗直接加载processed数据即可。6.2 复现时最容易卡住的三个点第一个坑是库版本。mlxtend的apriori函数在不同版本间API有变化老版本用apriori(df, min_support...)直接传DataFrame新版本要求传入one-hot编码后的布尔矩阵。建议锁定mlxtend0.19.0。第二个坑是中文显示。matplotlib默认字体不支持中文图表标题会变成方框。需要在代码开头设置import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False第三个坑是K-Means的随机初始化。不设random_state的话每次跑出来的簇编号可能不同导致图表颜色对不上。所有涉及随机的步骤都要固定种子。6.3 从分析到落地的延伸思路这套分析框架不止能用于肥胖风险。把字段换掉同样的流程可以套用到糖尿病风险、心血管风险等场景。核心逻辑是通用的先聚类分群再挖群内特征共现最后可视化呈现。如果要往产品化方向走可以把聚类模型持久化joblib保存然后做一个简单的输入表单用户填完问卷后实时输出所属风险群体和对应的风险因素提示。这个延伸不需要重构分析代码只是加一层推理接口。我在实际跑这个项目的过程中最大的体会是数据分析的价值不在于算法多复杂而在于你能不能把结论翻译成别人能听懂、能行动的语言。K-Means和Apriori都是教科书级别的老算法但用对了场景、解读到位了产出的洞察一点不比复杂模型差。另外提醒一句健康类数据分析涉及个人隐私即使用的是公开数据集在展示结果时也要注意不要暴露任何可识别到个人的信息这是做这类项目的基本底线。