DAY 18 簇

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

知识点回顾:

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

现在需要给这个簇赋予实际的含义,一般当你赋予实际含义的时候,你需要根据某几个特征来赋予,但是源数据特征很多,如何选择特征呢?有2种思路:

1. 你最开始聚类的时候,就选择了你想最后用来确定簇含义的特征,那么你需要选择一些特征来进行聚类,那么你最后确定簇含义的特征就是这几个特征,而非全部。如你想聚类消费者购买习惯,那么他过去的消费记录、购买记录、购买金额等等,这些特征都与消费者购买习惯有关,你可以使用这些特征来确定簇含义,一些其他的特征,如消费者年龄,工作行业则不考虑。----适用于你本身就有构造某些明确含义的特征的情况。

2. 最开始用全部特征来聚类,把其余特征作为 x,聚类得到的簇类别作为标签构建监督模型,进而根据重要性筛选特征,来确定要根据哪些特征赋予含义。---使用于你想构造什么,目前还不清楚。

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

输入

## 预处理流程回顾
#1. 导入库
import pandas as pd
import pandas as pd    #用于数据处理和分析,可处理表格数据。
import numpy as np     #用于数值计算,提供了高效的数组操作。
import matplotlib.pyplot as plt    #用于绘制各种类型的图表
import seaborn as sns   #基于matplotlib的高级绘图库,能绘制更美观的统计图形。

# 设置中文字体(解决中文显示问题)
plt.rcParams['font.sans-serif'] = ['SimHei']  # 设置字体为黑体
plt.rcParams['axes.unicode_minus'] = False    # 正常显示负号

#2. 读取数据查看数据信息--理解数据
data = pd.read_csv(r'heart.csv')    #读取数据
print("数据基本信息:")
data.info()
print("\n数据前5行预览:")
print(data.head())

#3. 缺失值处理
# 先筛选字符串变量 
discrete_features = data.select_dtypes(include=['object']).columns.tolist()
print("\n离散变量:")
print(discrete_features)
# 依次查看内容
for feature in discrete_features:
    print(f"\n{feature}的唯一值:")
    print(data[feature].value_counts())
#本数据集中不纯在离散变量
# thal 标签编码
thal_mapping = {
    1: 1,
    2: 2,
    3: 3,
}
data['thal'] = data['thal'].map(thal_mapping)
# slope的独热编码,记得需要将bool类型转换为数值
data = pd.get_dummies(data, columns=['slope'])
data2 = pd.read_csv(r"heart.csv") # 重新读取数据,用来做列名对比
list_final = [] # 新建一个空列表,用于存放独热编码后新增的特征名
for i in data.columns:
    if i not in data2.columns:
       list_final.append(i) # 这里打印出来的就是独热编码后的特征名
for i in list_final:
    data[i] = data[i].astype(int) # 这里的i就是独热编码后的特征名
print(list_final) # 打印出来的就是独热编码后的特征名
# 布尔矩阵显示缺失值,这个方法返回一个布尔矩阵
print(data.isnull()) 
print(data.isnull().sum())   # 统计每一列缺失值的数量
#填补缺失值
continuous_features = data.select_dtypes(include=['int64', 'float64']).columns.tolist()  #把筛选出来的列名转换成列表
print("\n连续变量:")
print(continuous_features)

for feature in continuous_features:     
    mode_value = data[feature].mode()[0]            #获取该列的众数。
    data[feature] = data[feature].fillna(mode_value)          #用众数填充该列的缺失值,inplace=True表示直接在原数据上修改。
print(data.isnull().sum())   # 统计每一列缺失值的数量
# 4. 异常值处理
#异常值一般不处理,或者结合对照试验处理和不处理都尝试下,但是论文中要写这个,作为个工作量
data.info()  #查看数据基本信息
#此数据集无缺失值
#划分数据集
from sklearn.model_selection import train_test_split
X = data.drop('target', axis=1)  # 特征
y = data['target']  # 目标变量
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)  # 划分训练集和测试集,test_size表示测试集占比,random_state表示随机种子,保证每次划分结果一致。

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

# 评估不同 k 值下的指标
k_range = range(2, 11)  # 测试 k 从 2 到 10
inertia_values = []
silhouette_scores = []
ch_scores = []
db_scores = []
agglo_scores = []
from sklearn.metrics import silhouette_score, calinski_harabasz_score, davies_bouldin_score
for k in k_range:
    # KMeans
    kmeans = KMeans(n_clusters=k, random_state=42)
    kmeans_labels = kmeans.fit_predict(X_scaled)
    inertia_values.append(kmeans.inertia_)  # 计算 KMeans 的轮廓系数
    silhouette = silhouette_score(X_scaled, kmeans_labels)  # 计算 KMeans 的轮廓系数
    silhouette_scores.append(silhouette)
    ch = calinski_harabasz_score(X_scaled, kmeans_labels)  # 计算 KMeans 的 CH 指数
    ch_scores.append(ch)
    db = davies_bouldin_score(X_scaled, kmeans_labels)  # 计算 KMeans 的 DB 指数
    db_scores.append(db)
    print(f"k={k}, 惯性: {kmeans.inertia_:.2f}, 轮廓系数: {silhouette:.3f}, CH 指数: {ch:.2f}, DB 指数: {db:.3f}")

# # 绘制评估指标图
# plt.figure(figsize=(15, 10))

# # 肘部法则图(Inertia)
# plt.subplot(2, 2, 1)
# plt.plot(k_range, inertia_values, marker='o')
# plt.title('肘部法则确定最优聚类数 k(惯性,越小越好)')
# plt.xlabel('聚类数 (k)')
# plt.ylabel('惯性')
# plt.grid(True)

# # 轮廓系数图
# plt.subplot(2, 2, 2)
# plt.plot(k_range, silhouette_scores, marker='o', color='orange')
# plt.title('轮廓系数确定最优聚类数 k(越大越好)')
# plt.xlabel('聚类数 (k)')
# plt.ylabel('轮廓系数')
# plt.grid(True)

# # CH 指数图
# plt.subplot(2, 2, 3)
# plt.plot(k_range, ch_scores, marker='o', color='green')
# plt.title('Calinski-Harabasz 指数确定最优聚类数 k(越大越好)')
# plt.xlabel('聚类数 (k)')
# plt.ylabel('CH 指数')
# plt.grid(True)

# # DB 指数图
# plt.subplot(2, 2, 4)
# plt.plot(k_range, db_scores, marker='o', color='red')
# plt.title('Davies-Bouldin 指数确定最优聚类数 k(越小越好)')
# plt.xlabel('聚类数 (k)')
# plt.ylabel('DB 指数')
# plt.grid(True)

# plt.tight_layout()  # 调整子图间距
# plt.show()

# 1. 肘部法则图: 找下降速率变慢的拐点,这里都差不多
# 2. 轮廓系数图:找局部最高点,这里选6
# 3. CH指数图: 找局部最高点,这里都差不多
# 4. DB指数图:找局部最低点,这里选4 5 6都行

# 综上,选择6比较合适。

# 提示用户选择 k 值
selected_k = 6

# 使用选择的 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)
X_pca_df = pd.DataFrame(X_pca, columns=['PCA1', 'PCA2'])
X_pca_df['KMeans_Cluster'] = kmeans_labels

# KMeans 聚类结果可视化
plt.figure(figsize=(6, 5))
sns.scatterplot(x='PCA1', y='PCA2', hue='KMeans_Cluster', data=X_pca_df, 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()
#初始化 SHAP 解释器
explainer = shap.TreeExplainer(model)  # 基于树模型的 SHAP 解释器
shap_values = explainer.shap_values(x1)  # 计算 SHAP 值
print(shap_values.shape)
#1. SHAP 特征重要性条形图 (Summary Plot - Bar)
shap.summary_plot(shap_values, x1, plot_type="bar",show=False)  # 这里的show=False表示不直接显示图形,这样可以继续用plt来修改元素,不然就直接输出了
plt.title("SHAP Feature Importance (Bar Plot)")
plt.show()

# 此时判断一下这几个特征是离散型还是连续型
selected_features = ['sex', 'cp','slope_1', 'slope_2']  # 选择的特征列表
for feature in selected_features:
    unique_count = X[feature].nunique() # 唯一值指的是在某一列或某个特征中,不重复出现的值
    print(f"\n{feature}的唯一值:")
    print(data[feature].value_counts())
    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(2, 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()
plt.show()

# 绘制出每个簇对应的这四个特征的分布图
print(X[['KMeans_Cluster']].value_counts())
X_cluster0 = X[X['KMeans_Cluster'] == 0]  # 簇0
X_cluster1 = X[X['KMeans_Cluster'] == 1]  # 簇1
X_cluster2 = X[X['KMeans_Cluster'] == 2]  # 簇2
X_cluster3 = X[X['KMeans_Cluster'] == 3]  # 簇3
X_cluster4 = X[X['KMeans_Cluster'] == 4]  # 簇4
X_cluster5 = X[X['KMeans_Cluster'] == 5]  # 簇5

# 簇0
fig, axes = plt.subplots(2, 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()
plt.show()

# 簇1
fig, axes = plt.subplots(2, 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()
plt.show()

# 簇2
fig, axes = plt.subplots(2, 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()
plt.show()

# 簇3
fig, axes = plt.subplots(2, 2, figsize=(12, 8))
axes = axes.flatten()

for i, feature in enumerate(selected_features):
    axes[i].hist(X_cluster3[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()

# 簇4
fig, axes = plt.subplots(2, 2, figsize=(12, 8))
axes = axes.flatten()

for i, feature in enumerate(selected_features):
    axes[i].hist(X_cluster4[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()

# 簇5
fig, axes = plt.subplots(2, 2, figsize=(12, 8))
axes = axes.flatten()

for i, feature in enumerate(selected_features):
    axes[i].hist(X_cluster5[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-5

六个簇的总结与定义

第一个簇 - 低风险心脏健康型

特征总结:sex 变量中某一性别特征占绝对主导(频数极高 );cp 变量呈现出特定几种类型分布相对集中;slope_1 和 slope_2 变量高度集中在某一数值附近,波动极小。整体表明心脏相关指标稳定,心脏病风险因素少。

定义依据:由于各项与心脏病相关指标都显示出良好且稳定的状态,风险因素少,所以定义为 “低风险心脏健康型”。

第二个簇 - 中等风险潜在隐患型

特征总结:sex 变量分布相对均衡;cp 变量各类型分布有一定分散性;slope_1 和 slope_2 变量虽有集中趋势,但取值范围略有扩大。意味着存在一些不确定因素,有潜在心脏病风险。

定义依据:因各项指标表现出一定的不确定性,存在潜在风险因素,但尚未达到高风险程度,因此定义为 “中等风险潜在隐患型”。

第三个簇 - 高风险症状明显型

特征总结:sex 变量中某一性别特征占比较突出;cp 变量分布显示多种胸痛类型占比较高;slope_1 和 slope_2 变量取值范围更广且离散。表明心脏病相关症状较为明显,风险程度较高。

定义依据:鉴于各项指标显示出明显的心脏病症状和较高风险特征,定义为 “高风险症状明显型”。

第四个簇 - 性别主导风险型

特征总结:sex 变量呈现极端分布,一种性别占绝对多数;cp 变量分布特征相对不突出;slope_1 和 slope_2 变量围绕特定值分布。风险表现受性别因素主导明显。

定义依据:由于性别变量的极端分布对整体风险特征影响显著,其他指标相对受其带动,故定义为 “性别主导风险型”。

第五个簇 - 症状复杂多变型

特征总结:sex 变量分布相对分散;cp 变量呈现多种胸痛类型复杂分布;slope_1 和 slope_2 变量取值离散且范围宽。意味着心脏病相关症状复杂多样,风险因素交织。

定义依据:根据各项指标呈现出的复杂症状和风险因素交织的特点,定义为 “症状复杂多变型”。

第六个簇 - 临界风险波动型

特征总结:sex 变量分布较为均衡;cp 变量各类型占比都不突出;slope_1 和 slope_2 变量取值有一定波动范围但不极端。处于风险临界状态,指标有波动但尚未恶化。

定义依据:基于各项指标处于风险临界状态且存在波动的特征,定义为 “临界风险波动型”。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值