聚类后的分析:推断簇的类型
知识点回顾:
1. 推断簇含义的2个思路:先选特征和后选特征
2. 通过可视化图形借助ai定义簇的含义
3. 科研逻辑闭环:通过精度判断特征工程价值
作业:参考示例代码对心脏病数据集采取类似操作,并且评估特征工程后模型效果有无提升。
# 先运行之前预处理好的代码
import pandas as pd
import pandas as pd #用于数据处理和分析,可处理表格数据。
import numpy as np #用于数值计算,提供了高效的数组操作。
import matplotlib.pyplot as plt #用于绘制各种类型的图表
import seaborn as sns #基于matplotlib的高级绘图库,能绘制更美观的统计图形。
import warnings
warnings.filterwarnings("ignore")
# 设置中文字体(解决中文显示问题)
plt.rcParams['font.sans-serif'] = ['SimHei'] # Windows系统常用黑体字体
plt.rcParams['axes.unicode_minus'] = False # 正常显示负号
data = pd.read_csv('D:\python学习\学习资源(代码)\python60-days-challenge-master\python60-days-challenge-master\heart.csv') #读取数据
from sklearn.model_selection import train_test_split
X = data.drop(['target'], axis=1) # 特征,axis=1表示按列删除
y = data['target'] # 标签
# # 按照8:2划分训练集和测试集
# X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # 80%训练集,20%测试集
import numpy as np
import pandas as pd
from sklearn.cluster import KMeans, DBSCAN, AgglomerativeClustering
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
import seaborn as sns
# 标准化数据(聚类前通常需要标准化)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# X_scaled
import numpy as np
import pandas as pd
from sklearn.cluster import DBSCAN
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.metrics import silhouette_score, calinski_harabasz_score, davies_bouldin_score
import matplotlib.pyplot as plt
import seaborn as sns
# 评估不同 k 下的指标
k_range = range(2, 11) # 测试k从 2 到 10
inertia_values = []
silhouette_scores = []
ch_scores = []
db_scores = []
for k in k_range:
kmeans = KMeans(n_clusters=k, random_state=42)
kmeans_labels = kmeans.fit_predict(X_scaled)
inertia_values.append(kmeans.inertia_) # 惯性(肘部法则)
silhouette = silhouette_score(X_scaled, kmeans_labels) # 轮廓系数
silhouette_scores.append(silhouette)
ch = calinski_harabasz_score(X_scaled, kmeans_labels) # CH 指数
ch_scores.append(ch)
db = davies_bouldin_score(X_scaled, kmeans_labels) # DB 指数
db_scores.append(db)
print(f"k={k}, 轮廓系数: {silhouette:.3f}, 惯性: {kmeans.inertia_:.2f}, CH 指数: {ch:.2f}, DB 指数: {db:.3f}")
selected_k = 3 # 示例值,根据图表调整
# 使用选择的k进行kmeans聚类
kmeans = KMeans(n_clusters=selected_k, random_state=42)
kmeans_labels = kmeans.fit_predict(X_scaled)
X['KMeans_Cluster'] = kmeans_labels
# 使用 PCA 降维到 2D 进行可视化
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_scaled)
# KMeans聚类结果可视化
plt.figure(figsize=(6, 5))
sns.scatterplot(x=X_pca[:, 0], y=X_pca[:, 1], hue=kmeans_labels, palette='viridis')
plt.title(f'KMeans Clustering with k={selected_k} (PCA Visualization)')
plt.xlabel('PCA Component 1')
plt.ylabel('PCA Component 2')
plt.show()
# 打印 KMeans聚类标签的前几行
print(f"KMeans Cluster labels (k={selected_k}) added to X:")
print(X[['KMeans_Cluster']].value_counts())
print(X.columns)
x1= X.drop('KMeans_Cluster',axis=1) # 删除聚类标签列
y1 = X['KMeans_Cluster']
# 构建随机森林,用shap重要性来筛选重要性
import shap
import numpy as np
from sklearn.ensemble import RandomForestClassifier # 随机森林分类器
model = RandomForestClassifier(n_estimators=100, random_state=42) # 随机森林模型
model.fit(x1, y1) # 训练模型,此时无需在意准确率 直接全部数据用来训练了
shap.initjs() # 初始化JavaScript环境,用于SHAP值的可视化
explainer = shap.TreeExplainer(model) # 创建一个TreeExplainer对象,用于解释模型的输出
shap_values = explainer.shap_values(x1) # 计算SHAP值,用于解释模型的预测结果
shap_values.shape # 第一维是样本数,第二维是特征数,第三维是类别数
print("--- 1. SHAP 特征重要性条形图 ---")
shap.summary_plot(shap_values[:,:,0],x1,plot_type="bar",show=False) # 这里的show=False表示不直接显示图形,这样可以继续用plt来修改元素,不然就直接输出了
plt.title("SHAP Feature Importance Bar Plot")
print(plt.show())
# 此时判断一下这几个特征是离散型还是连续型
import pandas as pd
selected_features = ['thalach', 'fbs',
'exang', 'slope','oldpeak']
for feature in selected_features:
unique_count = X[feature].nunique() # 唯一值指的是在某一列或某个特征中,不重复出现的值
# 连续型变量通常有很多唯一值,而离散型变量的唯一值较少
print(f'{feature} 的唯一值数量: {unique_count}')
if unique_count < 10: # 这里 10 是一个经验阈值,可以根据实际情况调整
print(f'{feature} 可能是离散型变量')
else:
print(f'{feature} 可能是连续型变量')
# X["Purpose_debt consolidation"].value_counts() # 统计每个唯一值的出现次数
import matplotlib.pyplot as plt
# 总样本中的前四个重要性的特征分布图
fig, axes = plt.subplots(3, 2, figsize=(12, 8))
axes = axes.flatten()
for i, feature in enumerate(selected_features):
axes[i].hist(X[feature], bins=20)
axes[i].set_title(f'Histogram of {feature}')
axes[i].set_xlabel(feature)
axes[i].set_ylabel('Frequency')
plt.tight_layout()
print(plt.show())
# 绘制出每个簇对应的这四个特征的分布图
X[['KMeans_Cluster']].value_counts()
# 分别筛选出每个簇的数据
X_cluster0 = X[X['KMeans_Cluster'] == 0]
X_cluster1 = X[X['KMeans_Cluster'] == 1]
X_cluster2 = X[X['KMeans_Cluster'] == 2]
# 先绘制簇0的分布图
import matplotlib.pyplot as plt
# 总样本中的前四个重要性的特征分布图
fig, axes = plt.subplots(3, 2, figsize=(12, 8))
axes = axes.flatten()
for i, feature in enumerate(selected_features):
axes[i].hist(X_cluster0[feature], bins=20)
axes[i].set_title(f'Histogram of {feature}')
axes[i].set_xlabel(feature)
axes[i].set_ylabel('Frequency')
plt.tight_layout()
print(plt.show())
# 先绘制簇1的分布图
import matplotlib.pyplot as plt
# 总样本中的前四个重要性的特征分布图
fig, axes = plt.subplots(3, 2, figsize=(12, 8))
axes = axes.flatten()
for i, feature in enumerate(selected_features):
axes[i].hist(X_cluster1[feature], bins=20)
axes[i].set_title(f'Histogram of {feature}')
axes[i].set_xlabel(feature)
axes[i].set_ylabel('Frequency')
plt.tight_layout()
print(plt.show())
# 先绘制簇2的分布图
import matplotlib.pyplot as plt
# 总样本中的前四个重要性的特征分布图
fig, axes = plt.subplots(3, 2, figsize=(12, 8))
axes = axes.flatten()
for i, feature in enumerate(selected_features):
axes[i].hist(X_cluster2[feature], bins=20)
axes[i].set_title(f'Histogram of {feature}')
axes[i].set_xlabel(feature)
axes[i].set_ylabel('Frequency')
plt.tight_layout()
print(plt.show())
三个簇的总结与定义
簇0
- Thalach(最大心率):集中在140-170,偏高,说明具有较强的运动耐力和心脏功能。
- Fbs(空腹血糖):绝大多数为0,血糖水平正常或偏低。
- Exang(运动后胸痛):多为0(无胸痛),心血管风险较低。
- Slope(心电图坡度):多为1和2,表示不同心电活动状态。
- Oldpeak(旧峰值):大都在0.5以下,说明心肌缺血低,心脏健康状态较好。
总结与定义:
健康状态较佳的群体,心脏功能良好,血糖正常,无运动诱发胸痛,心肌缺血风险较低。
簇1
- Thalach(最大心率):主要在120-150,偏中等偏低。
- Fbs(空腹血糖):大部分偏高(非0),提示血糖略高或可能有糖尿病前期。
- Exang(运动后胸痛):主要为1,表示存在运动诱发的胸痛,心血管风险增加。
- Slope(心电图坡度):多为1,反映心电活动状态。
- Oldpeak(旧峰值):多在1.0-2.0,说明存在一定的心肌缺血。
总结与定义:
潜在风险群体,心脏负荷较大,血糖偏高,有运动诱发胸痛,存在心肌缺血风险。
簇2
- Thalach(最大心率):偏高,集中在140-160。
- Fbs(空腹血糖):为1,提示血糖略高或可能有糖尿病前期。
- Exang(运动后胸痛):多为0,少为1,存在运动诱发胸痛。
- Slope(心电图坡度):多为2,显示心电变化较为显著。
- Oldpeak(旧峰值):多在1及以下,心肌缺血不太严重。
总结与定义:
高风险群体,心电变化明显,心肌缺血不太严重,血糖可能偏高,需密切监控和干预。
总体概述:
- 簇0:健康、心脏功能良好、血糖正常、无显著心肌缺血。
- 簇1:存在潜在心血管风险,血糖偏高,运动引发胸痛,心肌缺血迹象明显。
- 簇2:高风险群体,心电变化明显,血糖可能偏高,需重点关注。