如何在Python中为不同数值范围数据集生成带独立刻度的聚类热力图?
嘿,这个问题太典型了——当两个数据集尺度差得这么多的时候,直接丢进clustermap聚类,结果肯定会被1000-5000那组数据完全主导,0-1的特征根本发挥不了作用。我给你一套可行的方案,既能保证聚类的公平性,又能画出带独立刻度的合并热力图:
第一步:先给数据做标准化,确保聚类公平
聚类算法是基于距离计算的,大数值的特征会把小数值的特征的影响完全掩盖。所以咱得先把两个数据集放到同一尺度下,再进行行聚类。常用的方法有两种:
- Z-score标准化:把每个特征转换成均值为0、方差为1的分布,适合大部分聚类场景
- Min-Max缩放:把所有特征缩到0-1范围,适合对数值范围敏感的情况
这里我用Z-score举例子,用sklearn的StandardScaler就能搞定:
import seaborn as sns import matplotlib.pyplot as plt import pandas as pd import numpy as np from sklearn.preprocessing import StandardScaler from scipy.cluster.hierarchy import linkage, leaves_list # 先构造两个示例数据集(你替换成自己的真实数据就行) df_small = pd.DataFrame(np.random.uniform(0, 1, (15, 6)), columns=[f'S_{i}' for i in range(6)]) df_large = pd.DataFrame(np.random.uniform(1000, 5000, (15, 6)), columns=[f'L_{i}' for i in range(6)]) # 合并成一个完整的DataFrame(行是样本,列是两个数据集的特征) combined_df = pd.concat([df_small, df_large], axis=1) # 标准化所有特征,让两个数据集在同一尺度下参与聚类 scaler = StandardScaler() scaled_data = scaler.fit_transform(combined_df)
第二步:计算行聚类的顺序
用标准化后的数据计算层次聚类,得到样本的聚类顺序,这样后面画热力图的时候就能按聚类结果排列行:
# 计算行的层次聚类链接(用ward方法最小化类内方差,效果比较好) row_linkage = linkage(scaled_data, method='ward') # 获取聚类后的行索引顺序 row_order = leaves_list(row_linkage) # 把原始数据按聚类顺序重新排列 ordered_df = combined_df.iloc[row_order, :]
第三步:绘制带独立刻度的合并热力图
Seaborn的clustermap默认只能用一个颜色刻度,所以咱用matplotlib的子图来实现双刻度效果,两个子图共享y轴,各自用对应的颜色条:
# 创建画布和子图,设置宽度比例,给颜色条留位置 fig, (ax_small, ax_large, cbar_small, cbar_large) = plt.subplots(1, 4, figsize=(14, 9), gridspec_kw={'width_ratios': [6, 6, 0.3, 0.3]}) # 绘制第一个数据集(0-1范围)的热力图 sns.heatmap(ordered_df.iloc[:, :6], ax=ax_small, cmap='viridis', cbar=False, yticklabels=ordered_df.index, xticklabels=df_small.columns) ax_small.set_title('Dataset 1 (0-1 Range)') ax_small.set_ylabel('Samples') # 绘制第二个数据集(1000-5000范围)的热力图,隐藏y轴标签(因为和左边共享) sns.heatmap(ordered_df.iloc[:, 6:], ax=ax_large, cmap='plasma', cbar=False, yticklabels=False, xticklabels=df_large.columns) ax_large.set_title('Dataset 2 (1000-5000 Range)') # 给两个热力图分别添加独立的颜色条 sns.colorbar(ax_small.collections[0], cax=cbar_small) sns.colorbar(ax_large.collections[0], cax=cbar_large) plt.tight_layout() plt.show()
为啥要这么做?
- 聚类用标准化后的数据:保证两个数据集的特征对聚类结果的贡献是公平的,不会被大数值碾压
- 可视化用原始数据:保留了每个数据集的真实数值范围,独立的颜色条能清晰展示各自的分布差异
- 共享y轴:两个热力图的行顺序完全一致,方便对比同一聚类组在两个数据集里的表现
如果你更喜欢用Seaborn的clustermap框架,也可以先跑一次clustermap得到聚类后的行顺序,再按上面的方法拆分绘制,效果是一样的。
内容的提问来源于stack exchange,提问作者MEhsan
相关产品推荐
相关产品推荐

