当前位置:首页 > 技术 > 正文内容

基于 KMeans 聚类的特征重要性分析:使用 SHAP 和随机森林

访客 技术 2026年7月6日 18

本文演示了如何结合 KMeans 聚类、随机森林分类器和 SHAP 值,对心脏病数据集进行特征重要性分析。核心流程包括数据预处理、聚类评估、特征重要性排序和可视化。

1. 数据准备

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
from sklearn.model_selection import train_test_split

warnings.filterwarnings("ignore")
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 加载数据
df = pd.read_csv('heart.csv')

# 处理缺失值:使用中位数填充
missing_features = df.columns[df.isnull().any()].tolist()
for feat in missing_features:
    median_val = df[feat].median()
    df[feat] = df[feat].fillna(median_val)

# 分割特征和标签
features = df.drop('target', axis=1)
target = df['target']

# 划分训练集和测试集 (8:2)
X_train, X_test, y_train, y_test = train_test_split(features, target, test_size=0.2, random_state=42)

2. 数据标准化与聚类评估

from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.metrics import silhouette_score, calinski_harabasz_score, davies_bouldin_score

# 标准化
scaler = StandardScaler()
scaled_data = scaler.fit_transform(features)

# 评估不同 k 值 (2-10)
k_values = range(2, 11)
inertia_list = []
sil_list = []
ch_list = []
db_list = []

for k in k_values:
    km = KMeans(n_clusters=k, random_state=42)
    labels = km.fit_predict(scaled_data)
    inertia_list.append(km.inertia_)
    sil_list.append(silhouette_score(scaled_data, labels))
    ch_list.append(calinski_harabasz_score(scaled_data, labels))
    db_list.append(davies_bouldin_score(scaled_data, labels))
    print(f"k={k}, 惯性:{km.inertia_:.2f}, 轮廓:{silhouette_score(scaled_data, labels):.3f}, CH:{ch_list[-1]:.2f}, DB:{db_list[-1]:.3f}")

# 选择 k=3(实际应用中可根据肘部法则或指标选择)
final_k = 3
kmeans = KMeans(n_clusters=final_k, random_state=42)
cluster_labels = kmeans.fit_predict(scaled_data)
features['Cluster'] = cluster_labels

# PCA 降维可视化
pca = PCA(n_components=2)
pca_data = pca.fit_transform(scaled_data)

plt.figure(figsize=(6, 5))
sns.scatterplot(x=pca_data[:, 0], y=pca_data[:, 1], hue=cluster_labels, palette='viridis')
plt.title(f'KMeans 聚类结果 (k={final_k})')
plt.xlabel('主成分1')
plt.ylabel('主成分2')
plt.show()

print("各簇样本数:")
print(features['Cluster'].value_counts())

3. 使用随机森林和 SHAP 分析特征重要性

首先构建随机森林模型,然后用 SHAP 解释器计算特征重要性。

import shap
from sklearn.ensemble import RandomForestClassifier

# 除去聚类标签列
X_cluster = features.drop('Cluster', axis=1)
y_cluster = features['Cluster']

# 训练随机森林
rf_model = RandomForestClassifier(n_estimators=100, random_state=42)
rf_model.fit(X_cluster, y_cluster)

# SHAP 解释器
explainer = shap.TreeExplainer(rf_model)
shap_vals = explainer.shap_values(X_cluster)

# 处理多维 SHAP 值(多分类)
shap_vals_array = np.array(shap_vals)
print(f"SHAP 值形状: {shap_vals_array.shape}")

# 绘制特征重要性条形图(取第一个类别)
shap.summary_plot(shap_vals[0], X_cluster, plot_type="bar", show=False)
plt.title("SHAP 特征重要性(条形图)")
plt.show()

4. 选定特征分布分析

选取年龄、性别、胸痛类型、静息血压四个特征进行分布分析。

selected_feats = ['age', 'sex', 'cp', 'trestbps']

# 判断变量类型
for feat in selected_feats:
    unique_cnt = df[feat].nunique()
    feat_type = "离散型" if unique_cnt < 10 else "连续型"
    print(f"{feat}: {unique_cnt} 个唯一值 -> {feat_type}")

# 总样本分布
fig, axes = plt.subplots(2, 2, figsize=(12, 8))
for idx, feat in enumerate(selected_feats):
    ax = axes[idx//2, idx%2]
    ax.hist(df[feat], bins=20)
    ax.set_title(f'{feat} 分布')
    ax.set_xlabel(feat)
    ax.set_ylabel('频数')
plt.tight_layout()
plt.show()

5. 按簇分析特征分布

# 按簇拆分数
clusters = features['Cluster'].unique()
for cluster in clusters:
    subset = features[features['Cluster'] == cluster]
    fig, axes = plt.subplots(2, 2, figsize=(12, 8))
    for idx, feat in enumerate(selected_feats):
        ax = axes[idx//2, idx%2]
        ax.hist(subset[feat], bins=20)
        ax.set_title(f'簇 {cluster} - {feat} 分布')
        ax.set_xlabel(feat)
        ax.set_ylabel('频数')
    plt.tight_layout()
    plt.show()

通过以上步骤,我们成功将数据分为 3 个簇,并利用 SHAP 和随机森林识别出对聚类贡献最大的特征,进一步观察了这些特征在不同簇中的分布差异。这有助于理解数据的内部结构。

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。