Harmony算法原理:软聚类与迭代调整的核心思想

好,在动手跑代码之前,咱们先把Harmony的黑盒拆开看一眼。

我当年第一次用Harmony时,心里就犯嘀咕:这玩意儿凭什么能把不同批次的细胞cluster对齐在一起?后来看了论文才明白——它干的其实是个很聪明的「轮流改错」的活。

说白了,Harmony的核心就两件事:软聚类和迭代调整。听起来玄乎,其实就是「假设-校正-再假设」的循环。

2.1 软聚类:不再是「非此即彼」

你用过K-means吧?每个点硬邦邦地只属于一个簇。Harmony可不这么干——它给每个细胞发一张「概率卡」,上面写着它属于各个簇的可能性。

为什么非得软?因为批次效应往往只影响部分细胞。你硬把它分给某一个中心,那批次差异就会「漏」到聚类结果里。软聚类让细胞可以同时沾多个簇,拟合时才知道偏差到底来自哪个方向。

  • 硬聚类:0 或 1,非黑即白
  • 软聚类:0.1 给A簇,0.7给B簇,0.2给C簇
  • 关键:每个细胞有一组概率,和为1

我在做小鼠脑单细胞数据时遇到过:同一个细胞类型在两个批次里被分开,硬聚类死活拉不回来。换成Harmony后,那些概率值在0.4~0.6之间晃荡的细胞,正好是批次差异最严重的部分——软聚类第一周就把它揪出来了。

2.2 迭代调整:就像两个人互相校准

软聚类只是第一步。接下来Harmony进入一个循环:

  1. E步(Expectation):根据当前的聚类中心和批次矫正向量,重新计算每个细胞对各簇的概率。
  2. M步(Maximization):用这些概率做权重,重新估计聚类中心,同时调整每个批次的偏移量。

E和M轮流干,干一次细胞坐标就会挪一点。直到所有批次在同一个簇内的分布变得不可区分。

我个人的看家经验:迭代次数不是越多越好。我曾在淋巴瘤数据上跑了200步,结果过度对齐把真实的亚群差异给抹掉了。一般15~20步就够了,你可以在输出日志里看convergence那个值,跌到1e-5以下基本就稳了。

2.3 藏在背后的数学直觉

Harmony用的损失函数我简单翻译一下:

它想最小化的其实有两项——

目标 数学含义 现实意义
紧凑性 每个细胞尽可能靠近它所属的簇中心 同类细胞聚在一起
混杂性 每个簇里各批次的细胞数量尽量均匀 批次差异被消除

这两项是互斥的:你让细胞往cluster中心靠,那批次偏移就凸显出来了;你把批次拉匀,细胞又容易散开。Harmony用软聚类权重做杠杆,每一次迭代都会重新平衡这两个力量。

我习惯把这过程想象成「拔河比赛」——左边是生物学差异的绳子,右边是批次效应的绳子。软聚类就是一个裁判,每次喊「停」,然后重算两边的力。

2.4 Harmony的实际运作流程

下面这张图你可以存下来,跑Harmony时脑子里过一遍:

Harmony 软聚类与迭代调整流程 输入PCA嵌入+批次标签 初始化 聚类中心 (K个) E步:计算每个细胞对各簇的概率 M步:更新聚类中心 & 批次校正向量 收敛?或达到最大迭代 否 是 校正后嵌入 下游分析 关键点:软聚类权重同时参与M步的聚类中心和批次偏移更新,实现交互修正

2.5 代码层面怎么体现?

Harmony在R包里只有一行核心调用,但内部循环我们其实可以手动拆着玩。我用Python的harmony-pytorch做过一个迷你版本,核心逻辑就几十行:

# 伪代码示意:一次迭代
def harmony_iteration(Z, batch_labels, K, theta):
    # E步:计算软聚类概率
    distances = compute_pairwise_distances(Z, cluster_centers)
    probabilities = softmax(-distances / theta, axis=1)

    # M步:更新聚类中心(加权平均)
    cluster_centers = (probabilities.T @ Z) / probabilities.sum(axis=0)

    # 更新批次校正向量(每个批次一个偏移)
    for b in unique_batches:
        mask = (batch_labels == b)
        batch_offset[b] = Z[mask].mean(axis=0) - cluster_centers_offset

注意那个theta参数——它控制软分配的「软度」。theta越大,概率越平均,细胞越模糊;theta越小,越接近硬聚类。我一般设0.4~0.8,具体看你的数据离散度。

我曾经踩过一个坑:theta设成0.1,结果每个细胞概率几乎都是1,软聚类退化成了硬聚类,批次效应纹丝不动。所以啊,theta太小就白做了。

2.6 为什么Harmony能胜过传统方法?

传统批次校正(比如ComBat)假设批次效应是线性可加的,但单细胞数据里批次偏移往往是非线性的、局部的。Harmony的软聚类让每个细胞可以「半推半就」地归入一个簇,迭代调整时只修正那些批次间不一致的部分,不碰生物学信号。

你想想看:一个细胞在批次1里属于cluster A的概率是0.7,在批次2里却是0.2——那Harmony就知道这个细胞的坐标需要往A簇方向拉一拉。而如果两个批次里概率一样,它就不动。这就是它聪明的点。

我个人习惯把Harmony的迭代过程输出成动画看一下——每次迭代细胞颜色的混杂度逐渐升高,看着很解压。


好了,算法原理就到这里。下一章我们会用真实数据集一步一步跑通Harmony,并对比校正前后的UMAP图。到时候你就能用眼睛验证我刚才讲的所有东西了。

好了,算法原理就到这里。你心里应该有数了:软聚类让批次效应无处藏身,迭代调整让细胞坐标一点点往对的方向挪。这就是Harmony能成为单细胞批次校正头号选手的秘密。