当前位置: 首页 > news >正文

day18 python聚类分析对数据集模型性能影响

聚类后的分析:推断簇的类型

知识点回顾:

  1. 推断簇含义的2个思路:先选特征和后选特征
  2. 通过可视化图形借助ai定义簇的含义
  3. 科研逻辑闭环:通过精度判断特征工程价值

作业:参考示例代码对心脏病数据集采取类似操作,并且评估特征工程后模型效果有无提升。

聚类分析的概念

聚类分析是根据在数据中发现的描述对象及其关系的信息,将数据对象分组。目的是,组内的对象相互之间是相似的(相关的),而不同组中的对象是不同的(不相关的)。组内相似性越大,组间差距越大,说明聚类效果越好。

也就是说, 聚类的目标是得到较高的簇内相似度和较低的簇间相似度,使得簇间的距离尽可能大,簇内样本与簇中心的距离尽可能小

聚类得到的簇可以用聚类中心、簇大小、簇密度和簇描述等来表示

  • 聚类中心是一个簇中所有样本点的均值(质心)

  • 簇大小表示簇中所含样本的数量

  • 簇密度表示簇中样本点的紧密程度

  • 簇描述是簇中样本的业务特征

聚类的过程

  • 数据准备:包括特征标准化和降维;

  • 特征选择:从最初的特征中选择最有效的特征,并将其存储于向量中;

  • 特征提取:通过对所选择的特征进行转换形成新的突出特征;

  • 聚类(或分组):首先选择合适特征类型的某种距离函数(或构造新的距离函数)进行接近程度的度量,而后执行聚类或分组;

  • 聚类结果评估:是指对聚类结果进行评估,评估主要有3种:外部有效性评估、内部有效性评估和相关性测试评估。

1.导入库

#导入库
import pandas as pd 
import seaborn as sns
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler,MinMaxScaler
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC #支持向量机分类器
from sklearn.neighbors import KNeighborsClassifier #K近邻分类器
from sklearn.linear_model import LogisticRegression #逻辑回归分类器
import xgboost as xgb #XGBoost分类器
import lightgbm as lgb #LightGBM分类器
from sklearn.ensemble import RandomForestClassifier #随机森林分类器
from catboost import CatBoostClassifier #CatBoost分类器
from sklearn.tree import DecisionTreeClassifier #决策树分类器
from sklearn.naive_bayes import GaussianNB #高斯朴素贝叶斯分类器
from sklearn.metrics import  make_scorer,accuracy_score, precision_score, recall_score, f1_score # 用于评估分类器性能的指标
from sklearn.metrics import classification_report, confusion_matrix #用于生成分类报告和混淆矩阵
import warnings #用于忽略警告信息
warnings.filterwarnings("ignore") # 忽略所有警告信息

2.数据预处理:

from sklearn.preprocessing import StandardScaler,MinMaxScaler
data=pd.read_csv('heart.csv')
#定义离散变量与连续变量
discrete_features=['sex', 'cp', 'fbs', 'restecg', 'exang','slope','thal']
continuous_features=['age','trestbps','chol','thalach','oldpeak']
print('离散变量:',discrete_features)
print('连续变量:',continuous_features)#对连续变量进行归一化
min_max_scaler=MinMaxScaler()
data[continuous_features]=min_max_scaler.fit_transform(data[continuous_features])
print(data.head())
from sklearn.model_selection import train_test_split
X = data.drop(['target'], axis=1)  # 特征,axis=1表示按列删除
y = data['target'] # 标签

3.KMeans聚类结果

import numpy as np
import pandas as pd
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
import matplotlib.pyplot as plt
import seaborn as sns
from scipy.stats import zscore# 标准化数据(聚类前通常需要标准化)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# 评估不同 k 值下的指标
k_range = range(2, 21)  # 测试 k 从 2 到 20
inertia_values = []
silhouette_scores = []
ch_scores = []
db_scores = []for k in k_range:kmeans = KMeans(n_clusters=k, random_state=42)#计算K值kmeans_labels = kmeans.fit_predict(X_scaled)#kmeans_labels包含了X_scaled中每个样本所属的聚类标签inertia_values.append(kmeans.inertia_)  # 惯性(肘部法则)(簇内误差平方和wcss)惯性值越小说明效果越好silhouette = silhouette_score(X_scaled, kmeans_labels)  # 轮廓系数,取值范围在 -1 到 1 之间,越接近 1 表示聚类效果越好。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 指数衡量了不同聚类之间的相似度,值越小表示聚类效果越好。db_scores.append(db)print(f"k={k}, 惯性: {kmeans.inertia_:.2f}, 轮廓系数: {silhouette:.3f}, CH 指数: {ch:.2f}, DB 指数: {db:.3f}")

selected_k = 2# 使用选择的 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())

KMeans Cluster labels (k=2) added to X:

KMeans_Cluster

0 194 1 109

Name: count,

dtype: int64

4.判断簇类型:

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)  # 随机森林模型n_estimators=100代表随机森林模型中包含多少颗决策树
model.fit(x1, y1)  # 训练模型,此时无需在意准确率 直接全部数据用来训练了
shap.initjs()
# 初始化 SHAP 解释器
explainer = shap.TreeExplainer(model)
shap_values = explainer.shap_values(x1) # 这个计算耗时
shap_values.shape # 第一维是样本数,第二维是特征数,第三维是类别数
# --- 1. SHAP 特征重要性条形图 (Summary Plot - Bar) ---
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)")
plt.show()


选择前9个重要的特征进行分析 

# 此时判断一下这几个特征是离散型还是连续型(特征比较多的情况下用)
import pandas as pd
selected_features = ['thalach', 'exang','cp','slope',
'oldpeak', 'ca','age','thal','trestbps']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} 可能是连续型变量')

import matplotlib.pyplot as plt# 总样本中的前9个重要性的特征分布图
fig, axes = plt.subplots(3, 3, 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()
plt.show()


 绘制簇0的分布图
# 分别筛选出每个簇的数据
X_cluster0 = X[X['KMeans_Cluster'] == 0]
X_cluster1 = X[X['KMeans_Cluster'] == 1]
# 先绘制簇0的分布图import matplotlib.pyplot as plt# 总样本中的前四个重要性的特征分布图
fig, axes = plt.subplots(3, 3, 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()
plt.show()

 绘制簇1的分布图
# 先绘制簇1的分布图import matplotlib.pyplot as plt# 总样本中的前四个重要性的特征分布图
fig, axes = plt.subplots(3, 3, figsize=(12, 8))for i, feature in enumerate(selected_features):row=i//3col=i%3axes[row,col].hist(X_cluster1[feature], bins=20)axes[row,col].set_title(f'Histogram of {feature}')axes[row,col].set_xlabel(feature)axes[row,col].set_ylabel('Frequency')plt.tight_layout()
plt.show()

     

   

当然,以下是对两个簇特征分布的简洁分析:

X_cluster0 分析:
X_cluster0 群体的特征显示出一种相对一致的模式。大多数成员的最大心率(thalach)和年龄(age)都处于较低的区间,表明这一群体可能较为年轻且心脏反应温和。静息血压(trestbps)和运动引起的ST段变化(oldpeak)也普遍较低,这通常与较低的心血管疾病风险相关。此外,胸痛类型(cp)和ST段坡度(slope)的集中趋势暗示该群体可能经历较少或较轻微的心脏问题。总体来看,X_cluster0 可能代表了一个心脏健康风险较低的群体。

X_cluster1 分析:
相比之下,X_cluster1 群体的特征分布更为广泛和多变。最大心率(thalach)、运动诱发心绞痛(exang)、胸痛类型(cp)和ST段坡度(slope)的分布表明该群体的心脏健康状况差异较大。特别是,运动诱发心绞痛的发生率较高,可能意味着这一群体的心脏疾病风险较高。此外,年龄(age)和主要血管数量(ca)的广泛分布进一步表明该群体的健康状况复杂多变。X_cluster1 可能包含了一些具有较高心脏疾病风险的个体,需要进一步的医疗评估和关注。

5.利用随机森林模型看看特征工程后模型性能是否增强

默认随机森林
import time
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report, confusion_matrix# 假设 X 和 y 已经被定义并包含了特征和目标变量# 按照8:2划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)  # 80%训练集,20%测试集start_time = time.time()  # 记录开始时间
rf_model = RandomForestClassifier(random_state=42)
rf_model.fit(X_train, y_train)  # 在训练集上训练
rf_pred = rf_model.predict(X_test)  # 在测试集上预测
end_time = time.time()  # 记录结束时间print(f"训练与预测耗时: {end_time - start_time:.4f} 秒")print("\n默认随机森林 在测试集上的分类报告:")
print(classification_report(y_test, rf_pred))print("默认随机森林 在测试集上的混淆矩阵:")
print(confusion_matrix(y_test, rf_pred))

聚类之后的随机森林
x1= X.drop('KMeans_Cluster',axis=1) # 删除聚类标签列
y1 = X['KMeans_Cluster']
x1_train, x1_test, y1_train, y1_test = train_test_split(x1, y1, test_size=0.2, random_state=42)
start_time = time.time() # 记录开始时间
rf_model = RandomForestClassifier(random_state=42)
rf_model.fit(x1_train, y1_train) # 在训练集上训练
rf_pred = rf_model.predict(x1_test) # 在测试集上预测
end_time = time.time() # 记录结束时间
print(f"训练与预测耗时: {end_time - start_time:.4f} 秒")
print("\n默认随机森林 在测试集上的分类报告:")
print(classification_report(y1_test, rf_pred))
print("默认随机森林 在测试集上的混淆矩阵:")
print(confusion_matrix(y1_test, rf_pred))

在我的分析过程中,我发现聚类分析对随机森林模型的表现有着显著的正面影响。在我没有应用聚类技术之前,模型在测试集上的准确率是85%,然而,在我对数据进行聚类处理之后,模型的准确率提高到了92%。具体到每个类别,类别0的召回率从86%显著提升至97%,而类别1的精确度也从87%上升到了96%,这说明经过聚类,模型在识别这两类样本方面变得更加精确和细致。此外,聚类后的模型在宏平均和加权平均指标上也显示出了全面提升,其中精确度、召回率和F1分数均达到了0.92,这进一步证实了模型整体性能得到了增强。通过对比混淆矩阵,聚类的效果更是显而易见:在聚类前,模型有9个分类错误,而在聚类后,这个数字减少到了5个,这表明模型的预测准确性有了显著的提升。这些结果让我相信,聚类过程有效地改善了数据的结构,使得随机森林模型能够更有效地捕捉数据中的模式,进而在分类任务中表现得更加出色。



@浙大疏锦行

参考文章

http://www.xdnf.cn/news/322003.html

相关文章:

  • Content-Type使用场景及示例
  • 阿里云2核2g安装nexus
  • KL散度(Kullback-Leibler Divergence):概率分布差异的量化利器
  • 同步 / 异步、阻塞 / 非阻塞
  • 基于STM32、HAL库的SCD41-D-R2 气体传感器驱动程序设计
  • 数据中心机电建设
  • 【论文阅读】Attentive Collaborative Filtering:
  • 【MongoDB篇】MongoDB的分片操作!
  • FAST-LIO笔记
  • 【北京迅为】iTOP-4412精英版使用手册-第十章 QtE5.7系统编译
  • [OpenManus]部署笔记
  • Mkdocs文档引用相对地址的一些问题
  • 使用OpenCV的VideoCapture播放视频文件示例
  • 偏导数和梯度
  • shell-sed
  • MCP 规范新版本特性全景解析与落地实践
  • 图片文件转base64存储在数据库
  • redis端口漏洞未授权访问漏洞
  • Rust 中 Arc 的深度分析:从原理到性能优化实践
  • 2020年NCA CCF-C,改进灰狼算法RSMGWO+大规模函数优化,深度解析+性能实测
  • 鸿蒙开发——4.ArkTS快速入门指南
  • 我的世界云端服务器具体是指什么?
  • Laravel 12 实现验证码功能
  • 代码随想录算法训练营第三十四天
  • WordPress个人博客搭建(三):WordPress网站优化
  • RabbitMq学习(第一天)
  • 5.7 react 路由
  • Go语言八股之并发详解
  • 管家婆实用贴-如何在Excel中清除空格
  • Go语言——error、panic