2026年4月15日 研究日志¶

研究内容:总结数据集的患者及样本数据。今天做不完全部的工作,先做一部分再说。我打算今天在博客里从一个侧面介绍一下,为什么单细胞测序是必要的,为何组织级别的测序可能会将结果引向与事实完全相反的结果。

首先 先从“肥胖悖论”开始吧¶

考虑到不是所有来看我的博客的朋友都有生物学相关的学术背景,这里我先来举个例子作为导入:在慢性病研究中,“肥胖悖论”长期以来都是一个令人困惑的现象:在许多大型队列中,超重甚至轻度肥胖患者的死亡率竟然低于正常体重人群。这一结果看似挑战了传统医学常识,也一度被解读为“脂肪可能具有保护作用”。

然而,随着越来越多高质量研究的积累,科学界逐渐意识到:
所谓的“肥胖保护效应”并不是真实的生物学现象,而是统计偏差的产物。

其中最关键的偏差来自 反向因果关系(reverse causality) 与 混杂偏倚(confounding bias),尤其是由严重慢性疾病驱动的 恶病质(cachexia)。

恶病质是一种由心衰、癌症、终末期肾病等晚期疾病引发的系统性消耗综合征,其核心特征是 无法逆转的肌肉与脂肪丢失,伴随炎症、代谢紊乱和功能衰退。
在包含此类患者的临床队列中,非肥胖组往往富集了大量病情最重、预后最差的恶病质患者。这会显著抬高该组的死亡率,从而在统计上制造出“肥胖组更健康”的假象。

换句话说,肥胖悖论并不是脂肪在保护患者,而是:

重症患者因为体重下降被错误地归入“非肥胖组”,导致死亡风险被系统性高估。

这是一种典型的 患病率–发病率偏倚(prevalence–incidence bias) 或 幸存者偏倚(survivor bias):
只有那些“活得足够久”的患者才会被纳入研究,而早期死亡者被系统性排除。

大量研究已经验证了这一点。
例如,在冠心病监护病房(CCU)患者中,初步分析似乎支持肥胖悖论,但作者明确指出:未校正基线前体重变化是主要局限,提示结果可能受到反向因果影响。
更直接的证据来自心源性休克与 STEMI 患者的研究:恶病质患者的死亡率始终最高,远高于肥胖或超重组。这说明低体重并非保护性因素,而是疾病严重程度的标志。


为什么要从这里讲起?¶

因为肥胖悖论揭示了一个关键事实:

统计偏差可以制造出完全错误的生物学结论。

如果我们只依赖“整体平均值”或“群体水平数据”,就可能被这些偏差误导,得出与真实机制相反的结论。

而这正是现代生物医学研究中越来越强调 高分辨率数据(如单细胞测序) 的原因。

单细胞技术的出现,本质上就是为了避免类似辛普森悖论、肥胖悖论这样的 聚合数据陷阱。


为何是单细胞?¶

对于测序来说,组织就是整体,细胞就是个体。我接下来将要用一个简单的例子(只有A和B两种细胞,并只研究一种基因在某种刺激前后的表达量变化)来模拟一次批量RNA测序。

In [1]:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings("ignore", category=FutureWarning)

np.random.seed(42)

# -----------------------------
# 1. 设定参数:两种细胞类型 + 刺激前后
# -----------------------------
n_cells_before = 5000
n_cells_after  = 5000

# 细胞类型比例:刺激前 A 少 B 多,刺激后 A 大量增殖
prop_A_before, prop_B_before = 0.2, 0.8
prop_A_after,  prop_B_after  = 0.7, 0.3

# 基因表达均值(未刺激)
mu_A_before = 10.0   # A 型细胞:高表达
mu_B_before = 3.0    # B 型细胞:低表达

# 刺激后:每种细胞内表达都下降(关键设定)
mu_A_after = 7.0     # A 内部下降
mu_B_after = 1.5     # B 内部下降

sigma = 1.0          # 表达噪声

# -----------------------------
# 2. 生成单细胞数据
# -----------------------------
def simulate_condition(n_cells, prop_A, mu_A, mu_B, sigma, label):
    n_A = int(n_cells * prop_A)
    n_B = n_cells - n_A
    
    expr_A = np.random.normal(mu_A, sigma, n_A)
    expr_B = np.random.normal(mu_B, sigma, n_B)
    
    df = pd.DataFrame({
        "condition": label,
        "cell_type": ["A"] * n_A + ["B"] * n_B,
        "expression": np.concatenate([expr_A, expr_B])
    })
    return df

df_before = simulate_condition(
    n_cells_before, prop_A_before,
    mu_A_before, mu_B_before, sigma,
    label="Before"
)

df_after = simulate_condition(
    n_cells_after, prop_A_after,
    mu_A_after, mu_B_after, sigma,
    label="After"
)

df = pd.concat([df_before, df_after], ignore_index=True)

# -----------------------------
# 3. 计算:按细胞类型 vs bulk 的均值
# -----------------------------
# Before 在左,After 在右
df["condition"] = pd.Categorical(df["condition"], categories=["Before", "After"], ordered=True)

group_means = (
    df.groupby(["condition", "cell_type"])["expression"]
      .mean()
      .reset_index()
)

bulk_means = (
    df.groupby("condition")["expression"]
      .mean()
      .reset_index()
      .assign(cell_type="Bulk")
)

pivot_table = group_means.pivot(index="cell_type", columns="condition", values="expression")

#display(group_means)
display(pivot_table)
display(bulk_means)

# -----------------------------
# 4. 可视化
# -----------------------------
sns.set(style="whitegrid", context="talk")

fig, axes = plt.subplots(1, 2, figsize=(12, 5))

# (1) 每种细胞类型内:表达都下降
sns.barplot(
    data=group_means,
    x="cell_type", y="expression", hue="condition",
    ax=axes[0]
)
axes[0].set_title("Within each cell type\n(expression decreases after stimulus)")

# (2) bulk:总体表达反而上升
sns.barplot(
    data=bulk_means,
    x="cell_type", y="expression", hue="condition",
    ax=axes[1]
)
axes[1].set_title("Bulk measurement\n(overall expression increases)")

for ax in axes:
    ax.set_xlabel("")
    ax.set_ylabel("Expression")

plt.tight_layout()
plt.show()
condition Before After
cell_type
A 10.019332 6.983551
B 3.002169 1.505469
condition expression cell_type
0 Before 4.405602 Bulk
1 After 5.340126 Bulk
No description has been provided for this image

来吧,看看上图,A和B中某种基因的表达量在两个群体中都下降了,然而,到了整体中,表达量却上升了。如果你仔细观察代码,就会发现这是因为我调整了细胞的占比,

# 细胞类型比例:刺激前 A 少 B 多,刺激后 A 大量增殖
prop_A_before, prop_B_before = 0.2, 0.8
prop_A_after,  prop_B_after  = 0.7, 0.3

让本来就高表达此种基因的细胞群A在刺激后比例明显增大,使得即使这种刺激使每种细胞都表达下降,总体表达量却是上升的。


我决非故意捉弄你才这样设计的,这并不是一种假设的情况,而是对一种真实情况的模拟。事实上,细胞组成偏倚引发的辛普森悖论已经在多个生物医学场景中被直接观测到,而不仅仅是理论推演。

一个最典型的例子来自肿瘤免疫微环境研究。设想这样一种情形:某种治疗或病理刺激会抑制癌细胞内部某个炎症基因的表达,但与此同时,它又会强烈促进天然高表达该基因的免疫细胞(如炎性中性粒细胞或巨噬细胞)的大量浸润与扩增。
从细胞内在调控的角度看,这个基因在癌细胞中是被“关掉”的;
但从组织整体的角度看,这个基因的表达却因为免疫细胞的涌入而被“推高”了。

于是,当我们对整个肿瘤组织进行 bulk RNA‑seq 时,看到的反而是该基因的整体表达水平上升。
这就导致一个完全相反的结论:

细胞层面是下调,组织层面却呈现上调。

这就是辛普森悖论在生物学中的典型表现:
个体趋势与总体趋势方向相反。

2021 年发表在 Nature Communications 的研究提供了一个极其清晰的实证案例。研究人员发现,脂多糖(LPS)刺激会抑制单核细胞亚群中 Il1b 的表达,但同时又强烈驱动一个高表达 Il1b 的炎性中性粒细胞亚群的扩增。
最终,当这些细胞混合在一起进行 bulk 测序时,Il1b 的整体表达量显著升高,完美复现了辛普森悖论的“反转效应”。

这不是统计学的恶作剧,而是细胞组成变化与平均值混淆共同制造的系统性错觉。肥胖悖论你或许可以通过观察具体的患者意识到那些非肥胖组的患者中的恶病质期患者干扰了研究结果,但你要怎么意识到bulk测序中的上升和下降是真实的表达量上升下降还是细胞含量变化呢?你只能两手一摊背过气去(笑)。


为什么单细胞测序是解决这一悖论的终极方案?¶

在前面的例子中,无论是肿瘤免疫微环境,还是 LPS 刺激下的骨髓细胞群体,我们看到的都是同一个核心问题:

bulk RNA‑seq 只能看到“平均值”,而平均值会被细胞比例变化严重误导。

只要样本之间的细胞组成发生变化,bulk 的表达量就会被“细胞数量”而不是“细胞状态”主导。
这意味着 bulk 数据天生容易掉进辛普森悖论的陷阱:
个体层面的真实趋势被群体层面的混合效应完全掩盖甚至反转。

单细胞测序(scRNA‑seq)的出现,正是为了解决这一根本性限制。


单细胞测序让我们第一次“看见”每个细胞,而不是平均值¶

bulk RNA‑seq 的本质是:

所有细胞 → 混合 → 打碎 → 测平均表达

而单细胞测序的本质是:

每个细胞 → 单独测序 → 单独建模 → 单独分析

这意味着:

  • 你不再需要猜测某个基因是因为“细胞变多”还是“表达变高”
  • 你可以直接看到每种细胞的表达趋势
  • 你可以识别新的细胞亚群、细胞状态、细胞轨迹
  • 你可以量化细胞比例变化,而不是被它误导

换句话说:

单细胞测序把辛普森悖论拆解成可解释的细胞层面现象。


单细胞测序天然避免细胞组成偏倚¶

在 scRNA‑seq 中,你可以:

  • 分离不同细胞类型
  • 分析每个细胞类型内部的表达变化
  • 独立建模细胞比例变化
  • 同时观察“细胞状态变化”和“细胞数量变化”这两个维度

这使得你能够回答 bulk 永远无法回答的问题:

  • 某基因在某类细胞中到底是上调还是下调?
  • 细胞比例变化是否驱动了 bulk 的假象?
  • 是否存在新的细胞亚群主导了组织层面的信号?
  • 细胞状态变化是否比细胞数量变化更重要?

这就是为什么在 LPS‑Il1b 的例子中:

  • 单核细胞:Il1b 下调
  • 中性粒细胞:Il1b 高表达 + 数量暴增
  • bulk:Il1b 上升(被中性粒细胞“淹没”)

单细胞数据不仅揭示了反转效应,还解释了反转的机制。


单细胞测序让我们第一次能够“解构”组织层面的信号¶

bulk 给你一个数字:

Il1b ↑

单细胞给你一个故事:

某类细胞内部 Il1b ↓,但另一类细胞数量 ↑ 且表达高 → 组织层面 Il1b ↑

这不是简单的“更高分辨率”,而是:

从平均值 → 机制层面的跃迁。

这也是为什么单细胞测序被认为是现代生物医学中最具革命性的技术之一。


最后,从肥胖悖论到单细胞测序,我们学到的是什么?¶

无论是肥胖悖论、肿瘤免疫微环境,还是 LPS‑Il1b 的反转效应,它们都在提醒我们:

当我们只看整体平均值时,世界会呈现出一种错觉般的简单。

统计偏差、细胞组成变化、幸存者偏倚、反向因果……
这些因素会让我们看到与真实生物学机制完全相反的趋势。

单细胞测序的意义就在于:

  • 它让我们第一次能够跳出平均值的陷阱
  • 它让我们看到组织内部的真实异质性
  • 它让我们能够从细胞层面理解疾病机制
  • 它让我们能够避免辛普森悖论式的误导

最终,它让我们能够更接近生命系统的真实结构。

如果说 bulk RNA‑seq 是“听一整个乐队的合奏”,
那么单细胞测序就是:

给每个细胞一个麦克风。

而只有当每个细胞都能发声,我们才能真正理解生命的复杂性。

好啦,今天的分享就到这里啦。文字部分使用了一些LLM应用(Microsoft Copilot 企业版的 不用白不用),感觉效果还不错,至少在我提供资料的情况下没有出现明显的事实性错误(笑)