Python实战:用sklearn的GaussianMixture搞定身高体重聚类(附完整代码)

张开发
2026/4/16 12:08:36 15 分钟阅读

分享文章

Python实战:用sklearn的GaussianMixture搞定身高体重聚类(附完整代码)
Python实战用sklearn的GaussianMixture搞定身高体重聚类附完整代码最近在分析一个健身俱乐部的会员数据时遇到了一个有趣的问题如何根据会员的身高体重数据自动识别出不同的体型群体传统的K-means聚类在这个场景下表现不佳因为数据分布明显不是球形的。这时高斯混合模型(GMM)进入了我的视线——它能够识别出更复杂的簇形状正好解决我的问题。1. 准备工作与环境配置在开始之前我们需要确保环境配置正确。推荐使用Python 3.8版本并安装以下必要的库pip install numpy pandas matplotlib scikit-learn对于数据科学项目我习惯使用Jupyter Notebook进行交互式开发但本文的代码在常规Python脚本中同样适用。让我们先导入所需的模块import numpy as np import pandas as pd import matplotlib.pyplot as plt from sklearn.mixture import GaussianMixture from sklearn.preprocessing import StandardScaler提示如果你在可视化时遇到中文显示问题可以添加以下代码plt.rcParams[font.sans-serif] [SimHei] # 用来正常显示中文标签 plt.rcParams[axes.unicode_minus] False # 用来正常显示负号2. 数据准备与探索性分析假设我们有一个包含1000名会员身高体重数据的CSV文件结构如下id,height_cm,weight_kg 1,175,68 2,168,72 3,182,85 ...让我们加载并查看数据的基本情况# 加载数据 data pd.read_csv(member_data.csv) print(data.describe()) # 可视化数据分布 plt.figure(figsize(10,6)) plt.scatter(data[height_cm], data[weight_kg], alpha0.5) plt.xlabel(身高(cm)) plt.ylabel(体重(kg)) plt.title(会员身高体重分布) plt.grid(True) plt.show()从描述性统计和散点图中我们可以初步观察到身高范围大约在150-200cm之间体重范围大约在45-100kg之间数据点分布呈现多个密集区域3. 数据预处理在应用GMM之前我们需要对数据进行适当的预处理特征选择我们只需要身高和体重两列标准化虽然GMM对特征的尺度不敏感但标准化可以加速EM算法的收敛# 提取特征 X data[[height_cm, weight_kg]].values # 标准化 scaler StandardScaler() X_scaled scaler.fit_transform(X) # 查看标准化后的数据 print(标准化后的前5个样本) print(X_scaled[:5])4. 构建GMM模型现在我们可以开始构建高斯混合模型了。关键步骤包括确定合适的簇数量(n_components)选择协方差类型(covariance_type)训练模型并评估# 初始化GMM模型 gmm GaussianMixture( n_components3, # 假设我们想分成3个体型类别 covariance_typefull, # 允许每个簇有不同的形状和方向 random_state42 ) # 训练模型 gmm.fit(X_scaled) # 预测簇标签 labels gmm.predict(X_scaled) # 查看预测结果 print(前10个样本的预测标签, labels[:10])注意在实际应用中确定最佳簇数量是一个重要问题。我们可以使用以下方法肘部法则观察BIC/AIC值的变化轮廓系数业务需求指导5. 结果可视化与分析让我们将聚类结果可视化并分析每个簇的特征# 可视化聚类结果 plt.figure(figsize(12,8)) plt.scatter(X[:,0], X[:,1], clabels, cmapviridis, alpha0.6) plt.xlabel(身高(cm)) plt.ylabel(体重(kg)) plt.title(基于GMM的身高体重聚类结果) # 绘制簇中心反标准化后 centers scaler.inverse_transform(gmm.means_) plt.scatter(centers[:,0], centers[:,1], cred, s200, alpha0.8, markerX) plt.grid(True) plt.colorbar(label簇标签) plt.show()我们可以进一步分析每个簇的统计特征# 将聚类结果添加到原始数据 data[cluster] labels # 按簇分组统计 cluster_stats data.groupby(cluster).agg({ height_cm: [mean, std, min, max], weight_kg: [mean, std, min, max], id: count }) print(cluster_stats)6. 模型评估与调优为了评估模型性能我们可以查看模型的收敛情况和信息准则print(f模型收敛于 {gmm.n_iter_} 次迭代) print(fBIC值: {gmm.bic(X_scaled):.2f}) print(fAIC值: {gmm.aic(X_scaled):.2f})为了找到最佳的簇数量我们可以尝试不同的n_componentsn_components_range range(1, 8) bic_values [] for n in n_components_range: gmm GaussianMixture(n_componentsn, covariance_typefull, random_state42) gmm.fit(X_scaled) bic_values.append(gmm.bic(X_scaled)) # 绘制BIC曲线 plt.figure(figsize(10,6)) plt.plot(n_components_range, bic_values, bo-) plt.xlabel(簇数量) plt.ylabel(BIC值) plt.title(不同簇数量对应的BIC值) plt.grid(True) plt.show()7. 高级应用概率聚类与异常检测GMM的一个强大功能是它可以提供概率输出而不仅仅是硬分类。这在某些应用场景中非常有用# 获取样本属于各簇的概率 probs gmm.predict_proba(X_scaled) print(前5个样本的簇概率分布) print(probs[:5]) # 异常检测基于低概率密度 log_probs gmm.score_samples(X_scaled) threshold np.percentile(log_probs, 5) # 取最低5%作为异常值 outliers X[log_probs threshold] # 可视化异常值 plt.figure(figsize(12,8)) plt.scatter(X[:,0], X[:,1], clabels, cmapviridis, alpha0.6) plt.scatter(outliers[:,0], outliers[:,1], cred, s100, markerx, label异常值) plt.xlabel(身高(cm)) plt.ylabel(体重(kg)) plt.title(聚类结果与异常检测) plt.legend() plt.grid(True) plt.show()8. 完整代码示例以下是本案例的完整代码方便读者直接使用# 导入必要的库 import numpy as np import pandas as pd import matplotlib.pyplot as plt from sklearn.mixture import GaussianMixture from sklearn.preprocessing import StandardScaler # 设置中文显示 plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False # 1. 加载数据 data pd.read_csv(member_data.csv) # 2. 数据预处理 X data[[height_cm, weight_kg]].values scaler StandardScaler() X_scaled scaler.fit_transform(X) # 3. 训练GMM模型 gmm GaussianMixture(n_components3, covariance_typefull, random_state42) gmm.fit(X_scaled) labels gmm.predict(X_scaled) # 4. 结果可视化 plt.figure(figsize(12,8)) plt.scatter(X[:,0], X[:,1], clabels, cmapviridis, alpha0.6) centers scaler.inverse_transform(gmm.means_) plt.scatter(centers[:,0], centers[:,1], cred, s200, alpha0.8, markerX) plt.xlabel(身高(cm)) plt.ylabel(体重(kg)) plt.title(基于GMM的身高体重聚类结果) plt.grid(True) plt.colorbar(label簇标签) plt.show() # 5. 模型评估 print(f模型收敛于 {gmm.n_iter_} 次迭代) print(fBIC值: {gmm.bic(X_scaled):.2f}) print(fAIC值: {gmm.aic(X_scaled):.2f}) # 6. 概率输出示例 probs gmm.predict_proba(X_scaled) print(样本属于各簇的概率分布示例) print(probs[:5])在实际项目中应用这个模型时我发现调整协方差类型对结果影响很大。full类型虽然灵活但可能导致过拟合而tied或diag有时能提供更稳定的结果。

更多文章