别再只用K-means了!用Python手把手实现分裂层次聚类,轻松搞定基因数据可视化

张开发
2026/4/9 4:08:34 15 分钟阅读

分享文章

别再只用K-means了!用Python手把手实现分裂层次聚类,轻松搞定基因数据可视化
超越K-means用Python实战分裂层次聚类解锁基因数据隐藏层次当面对基因表达矩阵时传统K-means算法就像用剪刀裁剪复杂的家族谱系——虽然能快速分组却彻底丢失了关键的层次关系信息。这正是分裂层次聚类(Divisive Hierarchical Clustering)大显身手的场景它能像剥洋葱一样逐层揭示数据的内在结构最终呈现完整的数据家谱。1. 为什么基因数据需要层次聚类在生物信息学领域基因表达数据本质上是高维度的层次化结构。假设我们有一组来自不同物种的基因表达谱import pandas as pd gene_data pd.DataFrame({ Human: [5.2, 3.8, 7.1, 1.5], Mouse: [5.1, 3.9, 7.0, 1.6], Chicken: [4.9, 8.2, 2.3, 0.7], Rice: [1.2, 9.5, 0.3, 2.8], Wheat: [1.1, 9.6, 0.4, 2.7] }, index[GeneA, GeneB, GeneC, GeneD])K-means可能给出这样的扁平化聚类结果物种聚类标签Human0Mouse0Chicken1Rice2Wheat2而分裂层次聚类则能构建出反映真实进化关系的树状结构所有物种 ├── 动物 │ ├── 哺乳动物 (Human, Mouse) │ └── 鸟类 (Chicken) └── 植物 (Rice, Wheat)关键差异对比维度K-means分裂层次聚类结构保留完全丢失层次信息完整保留层级关系结果解读需要预先指定K值可动态观察不同切割高度可视化散点图分组交互式树状图(Dendrogram)适用场景大规模均匀分布数据小规模层次化数据提示当你的数据存在天然层级关系(如生物分类、组织架构、文档主题)时分裂层次聚类往往能发现更有意义的模式。2. 分裂层次聚类的Python实战框架让我们构建一个完整的实现框架包含以下关键组件import numpy as np from scipy.cluster.hierarchy import dendrogram, linkage from sklearn.base import BaseEstimator, ClusterMixin class DivisiveHierarchical(BaseEstimator, ClusterMixin): def __init__(self, min_cluster_size3, linkageward): self.min_cluster_size min_cluster_size self.linkage linkage def _recursive_split(self, X): clusters [X] while True: # 找到最需要分裂的簇(最大SSE) sse_list [self._calculate_sse(c) for c in clusters] target_idx np.argmax(sse_list) if clusters[target_idx].shape[0] self.min_cluster_size: break # 使用二分K-means进行分裂 sub_clusters self._bisecting_kmeans(clusters.pop(target_idx)) clusters.extend(sub_clusters) return clusters def _calculate_sse(self, cluster): centroid np.mean(cluster, axis0) return np.sum((cluster - centroid) ** 2) def _bisecting_kmeans(self, cluster, n_splits2): from sklearn.cluster import KMeans kmeans KMeans(n_clustersn_splits) labels kmeans.fit_predict(cluster) return [cluster[labels i] for i in range(n_splits)] def fit(self, X, yNone): self.clusters_ self._recursive_split(X) return self核心参数解析min_cluster_size控制分裂停止条件影响最终簇的粒度linkage可选ward(默认)、complete或average决定簇间距离计算方式n_splits每次分裂产生的子簇数(通常保持为2)实际应用示例# 生成模拟基因数据(50个样本1000个基因特征) np.random.seed(42) X np.vstack([ np.random.normal(0, 1, (20, 1000)), # 哺乳动物类 np.random.normal(5, 1, (15, 1000)), # 鸟类 np.random.normal(10, 1, (15, 1000)) # 植物类 ]) # 训练模型 dh DivisiveHierarchical(min_cluster_size10) dh.fit(X) # 查看聚类结果 print(f最终得到 {len(dh.clusters_)} 个簇) for i, c in enumerate(dh.clusters_): print(f簇{i1}包含 {c.shape[0]} 个样本)3. 专业级树状图可视化技巧树状图(Dendrogram)是层次聚类的灵魂可视化但默认输出往往不够专业。以下是提升可读性的关键技巧进阶可视化代码from scipy.cluster.hierarchy import set_link_color_palette import matplotlib.pyplot as plt def plot_dendrogram(model, **kwargs): # 创建链接矩阵 counts np.zeros(model.children_.shape[0]) n_samples len(model.labels_) for i, merge in enumerate(model.children_): current_count 0 for child_idx in merge: if child_idx n_samples: current_count 1 # 叶子节点 else: current_count counts[child_idx - n_samples] counts[i] current_count linkage_matrix np.column_stack([model.children_, model.distances_, counts]).astype(float) # 定制化绘图 set_link_color_palette([#2ecc71, #3498db, #e74c3c, #f1c40f]) plt.figure(figsize(12, 6)) dendrogram(linkage_matrix, orientationright, labelsgene_columns, leaf_font_size10, color_threshold0.7*max(model.distances_)) plt.title(基因表达数据的层次聚类, pad20, fontsize14) plt.xlabel(聚类距离, fontsize12) plt.grid(axisx, linestyle--, alpha0.5) plt.tight_layout()关键定制参数参数作用推荐值orientation树状图方向right(适合长标签)color_threshold颜色分割阈值0.5-0.7*最大距离leaf_font_size叶标签字体大小10-12ptlink_color链接线颜色方案使用对比明显的色系注意对于基因数据建议添加热图与树状图的组合可视化可以使用seaborn.clustermap()实现更专业的生物信息学图表。4. 生物信息学中的实战案例解析让我们分析一个真实的RNA-seq数据集展示完整分析流程数据准备import scanpy as sc adata sc.datasets.pbmc3k() # 单细胞RNA-seq数据 sc.pp.filter_genes(adata, min_counts1) # 基础过滤 sc.pp.normalize_total(adata, target_sum1e4) # 标准化 sc.pp.log1p(adata) # 对数变换层次聚类分析# 计算距离矩阵 distance_matrix sc.pp.neighbors(adata, n_neighbors15, methodumap) # 层次聚类 Z linkage(distance_matrix[connectivities].toarray(), ward) # 动态切割树状图 from scipy.cluster.hierarchy import cut_tree clusters cut_tree(Z, height0.5) adata.obs[hcluster] clusters.astype(str) # 可视化 sc.pl.umap(adata, colorhcluster, legend_locon data)关键发现解读高度可变的基因簇通过树状图分支长度识别表达模式独特的基因群长分支表示该簇基因表达谱与其他差异显著细胞类型注释marker_genes { T细胞: [CD3D, CD3E], B细胞: [CD79A, MS4A1], 单核细胞: [CD14, LYZ] } for cell_type, genes in marker_genes.items(): sc.pl.umap(adata, colorgenes, titlecell_type)进化关系推断通过保守基因簇的分支模式推测物种分化时间快速进化的基因会形成远离主干的独立分支性能优化技巧当处理大规模单细胞数据时(10k细胞)传统方法会遇到内存问题。此时可以采用# 近似算法加速 from sklearn.neighbors import NearestNeighbors nbrs NearestNeighbors(n_neighbors30, algorithmball_tree).fit(adata.X) sparse_distance nbrs.kneighbors_graph(modedistance) Z linkage(sparse_distance.toarray(), ward)5. 超越基础高级应用与陷阱规避混合策略提升效果预降维层次聚类from sklearn.decomposition import PCA pca PCA(n_components50) X_pca pca.fit_transform(adata.X) Z linkage(X_pca, ward)多分辨率分析heights [0.3, 0.5, 0.7] # 不同切割高度 for h in heights: clusters cut_tree(Z, heighth) adata.obs[fcluster_h{h}] clusters sc.pl.umap(adata, colorfcluster_h{h})常见陷阱与解决方案问题现象根本原因解决方案树状图呈现链式结构数据存在渐变趋势改用谱聚类或DBSCAN分支长度差异过大特征量纲不一致进行Z-score标准化计算时间过长样本量过大(O(n²))先使用K-means粗聚类小簇过度分裂min_cluster_size设置过小根据业务知识调整停止条件生物信息学特殊考量批次效应处理from combat.py import combat adata_corrected combat(adata, batch_keyexperiment_date)基因权重调整# 根据基因表达方差赋予权重 gene_vars np.var(adata.X, axis0) weights np.log1p(gene_vars) weighted_X adata.X * weights[np.newaxis, :]在实际分析中我发现结合UMAP可视化与层次聚类能产生最佳效果——先用层次聚类确定主要分支再用UMAP验证簇的紧密度。例如在处理癌症亚型分型时这种方法能清晰区分恶性细胞群与正常细胞。

更多文章