Skip to content
Blog Index
318 posts
ActivityLast 12 months
Sep 2026
September 14, 2026
SpaTalk

SpaTalk ​

#R #CellCellCommunication #SpaTalk

loadData() → createSpaTalk() → dec_celltype() → find_lr_path() → dec_cci() / dec_cci_all()

  • loadData()
  • createSpaTalk()
  • dec_celltype()
  • find_lr_path()
  • dec_cci() / dec_cci_all()

Load Data ​

SpaTalk 不提供文件读盘函数 。需要在 R 里把数据加载进来,再传给它的接口。

  • gene × spot/cell
  • data structure: data.frame / matrix / dgCMatrix
r
   # 你的空间转录组数据
   st_data   <- ...   # gene × spot/cell 矩阵(data.frame / matrix / dgCMatrix)
   st_meta   <- ...   # spot-based:  data.frame(spot, x, y)
                      # single-cell: data.frame(cell, x, y)
   # scRNA-seq 参考(解卷积用,选传)
   sc_data    <- ...  # gene × cell 矩阵
   sc_celltype <- ... # 每个 cell 的 cell-type 标签向量

createSpaTalk() ​

r
   obj <- createSpaTalk(
     st_data       = st_data,
     st_meta       = st_meta,
     species       = "Human",       # or "Mouse"
     if_st_is_sc   = FALSE,         # TRUE=ST, FALSE=spot ST
     spot_max_cell = 10,            # spot 模式:每个 spot 最多重建 N 个细胞
     celltype      = NULL           # 已知 celltype 时跳过解卷积
   )

Two Branch

  • if_st_is_sc = TRUE → st_type = "single-cell",后续直接对原始细胞做 CCC
  • if_st_is_sc = FALSE → st_type = "spot",必须先解卷积 + 重建伪单细胞

dec_celltype() ​

  • dec_celltype() 在 celltype = NULL 时强制需要调用,无论 ST 数据是单细胞分辨率还是 spot 分辨率。
    • 单细胞 ST + celltype = NULL → 做 非负回归,给每个细胞分配细胞类型(不是严格意义上的"解卷积")
    • Spot ST + celltype = NULL → 做 真正的解卷积 + 伪单细胞重建
  • 若 celltype 已知 → 两步都跳过,直接进入 find_lr_path()
r
   obj <- dec_celltype(
     object      = obj,
     sc_data     = sc_data,
     sc_celltype = sc_celltype,
     min_percent = 0.5,              # 单细胞:>此比例才赋予type
     iter_num    = 1000,             # spot:抽样轮数
     method      = 1,                # 1=SpaTalk内置, 2=RCTD, 3=Seurat...
   )

内部发生了什么:

  • 所有模式:先对 scRNA 参考按 cell type 求均值 → NNLM::nnlm() 非负回归 → 得到每个 spot/cell 的 cell-type 比例
  • 单细胞 ST:归一化比例 > 0.5 → 赋予 cell type;否则 "unsure" 排除
  • Spot ST:比例 × spot_max_cell → 整数分配 + 小数抽签 → iter_num 轮从 scRNA 参考中抽样 → 选与真实 spot 表达最像的组合 → 伪细胞的表达来自参考细胞

find_lr_path() ​

过滤可用 LR

r
  obj <- find_lr_path(
    object   = obj,
    lrpairs  = lrpairs,      # 内置 CellTalkDB,也可自定义
    pathways = pathways,      # 内置 KEGG + Reactome + AnimalTFDB
    max_hop  = NULL           # Human=3, Mouse=4
  )

只保留:

  • 物种匹配
  • 配体/受体都在表达矩阵中
  • receptor 能在 max_hop 步内连接到 TF

这步不涉及空间,是纯知识图谱预过滤。

dec_cci() / dec_cci_all() ​

推断 CCC

对 sender → receiver 这个 cell-type pair:

r
  # 一对指定类型
  obj <- dec_cci(obj, celltype_sender = "T_cell", celltype_receiver =
"Macrophage")

  # 全部 cell-type pair(自动枚举)
  obj <- dec_cci_all(obj)

内部 5 个子步骤:

  1. 空间 KNN:对每个 sender 细胞找最近 10 个细胞 → 筛出 receiver cell type
  2. LR 共表达:sender ligand × receiver receptor 二值共表达比例
  3. 置换检验:有放回抽样 1000 次 → 经验 p 值
  4. 胞内 KG:receptor → TF → target,仅在 receiver 细胞中算共表达比例过滤
  5. 随机游走:从 receptor 走 10000 次 → TF 命中概率 → intra 分数
  6. 合并分数:score=sqrt((1−p)×sigmoid(intra))
python
dec_cci(sender, receiver)
     │
     ├── 1. 取数据:st_meta, st_data, celltype_dist(距离矩阵)
     ├── 2. 验证 cell type 是否存在
     ├── 3. .get_cellpair()        ──→ 空间 KNN,选出 sender→receiver 的 cell pair
     ├── 4. 检查 cell pair 数量是否 ≥ min_pairs
     │
     ├── 5. .lr_distance()         ──→ LR 共表达比例 + 置换检验
     │     保留 p < 0.05 的 LR
     │
     ├── 6. .get_tf_res()          ──→ 对每个显著 receptor 做胞内通路
     │      ├─ .generate_ggi_res()     BFS 展开 receptor→TF
     │      ├─ .generate_tf_gene_all() 找可达 TF
     │      ├─ .generate_tf_res()      记录 n_hop, n_target
     │      └─ .random_walk()          10000 次随机游走 → TF score
     │
     ├── 7. .get_score()           ──→ 合并分数
     │     score = sqrt((1-p) × sigmoid(intra))
     │
     └── 8. 写回 object@lrpair, object@tf, object@cellpair

##SpaTalk 方法详解

核心 Pipeline ​

读取数据 → createSpaTalk() → dec_celltype() → find_lr_path() → dec_cci() / dec_cci_all()
NOTECCCSpaTalk
Apr 2026
April 3, 2026
PyG-Common GCN Layer

Common GCN Layer ​

GCNConv (Graph Convolutional Network) ​

核心思想:利用度矩阵进行归一化,解决节点度数差异导致的数值爆炸。

  • 数学本质:对称归一化。
xi(k)=∑j∈N(i)∪{i}1d^id^jWxj(k−1)
  • Matrix Form
    • A^: 包含自环的邻接矩阵 [N,N]。
    • D^: 对应的度矩阵。
    • D^−1/2A^D^−1/2: 这是归一化后的邻接矩阵
X(k)=D^−1/2A^D^−1/2X(k−1)W
  • PyG 特点:

    • 会自动处理 add_self_loops。
    • 计算归一化系数 αi,j=1/d^id^j 并缓存,提高效率。
  • 适用场景:经典的半监督节点分类,对图结构比较固定的任务效果稳健。

python
class GCNConv(MessagePassing):
    def __init__(self, in_channels, out_channels):
        super().__init__(aggr='add')
        self.lin = Linear(in_channels, out_channels, bias=False)

    def forward(self, x, edge_index):
        # 1. 添加自环
        edge_index, _ = add_self_loops(edge_index, num_nodes=x.size(0))
        # 2. 线性变换 (通常先做线性变换,减少 message 阶段计算量)
        x = self.lin(x)
        # 3. 计算归一化系数 (度矩阵 D)
        row, col = edge_index
        deg = degree(col, x.size(0), dtype=x.dtype)
        deg_inv_sqrt = deg.pow(-0.5)
        norm = deg_inv_sqrt[row] * deg_inv_sqrt[col] # 即 1/sqrt(di*dj)

        return self.propagate(edge_index, x=x, norm=norm)

    def message(self, x_j, norm):
        # 邻居特征乘以归一化系数
        return norm.view(-1, 1) * x_j
NOTEPyGMessagePassingGCNGATGraphSAGEGIN
Portrait of Junya Yang
Junya Yang
CUHK Computer Science · Bioinformatics · AI Agents
Latest posts