PSGRN | 单细胞扰动数据专属的GRN方法

基因调控网络 (GRNs) 对于理解基因如何协调细胞过程至关重要。如今大规模的单细胞扰动研究为GRNs推断提供了机遇,但目前许多方法未能充分利用干预信息。因此,作者提出了PSGRN,该方法通过自训练框架结合合成金标准,整合了干预和观测的单细胞数据。

PSGRN推断基因调控网络的核心原理:利用“自训练”框架,将基因表达的“相关性”转化为可迭代优化的“伪标签”,并通过机器学习模型来捕捉超越简单相关性的高阶调控模式。其原理可以拆解为以下四个关键步骤:

  1. 生成初始伪标签
    对于所有可能的基因对 (Gene A → Gene B),PSGRN首先计算它们在表达数据中的相关性。具体计算时,会将干预数据(A基因被扰动时的B表达)和观测数据(未扰动时的B表达)合并。
  • 若某基因对的绝对相关系数大于阈值,则将其初始标注为“正例”(存在调控关系),否则标注为“负例”。
  • 这一步提供的只是粗略的“伪黄金标准”,并非真实标签。
  1. 提取基因对特征
    PSGRN并不直接把表达值输入模型,而是为每一对基因 <g_i, g_j> 提取四个统计特征:
  • g_ig_j 在观测数据中的平均表达水平。
  • g_ig_j 在干预数据 (即人为扰动某个基因后) 中的平均表达水平。
  • 这些特征包含了基因的基础表达量和对外界扰动的响应信息。
  1. 分类模型训练与自训练
    利用步骤1生成的“伪标签”作为监督信号,步骤2提取的特征作为输入,训练一个LightGBM分类模型。
  • 关键机制:模型在训练过程中,不仅看到了相关性,还学习到了基因表达水平和扰动响应模式。训练完成后,模型会对全部基因对 (包括之前作为训练集的同一批数据) 重新进行预测打分。
  • 这被称为“自训练”或“自监督”——模型试图利用额外的表达水平信息,自动“纠正”第一步中相关性产生的噪声标签。
  1. 输出最终调控网络
    模型预测出所有基因对的概率分数后,按分数从高到低排序。用户可以选择输出排名前topN的基因对,作为最终推断的基因调控网络。

PSGRN之所以有效,是因为它跳出了“直接预测因果关系”的复杂数学约束,转而采用“相关性粗略排序 + 机器学习精细矫正”的策略。当有更多的干预数据加入时,模型提取的“扰动前后表达变化”特征会更加丰富,从而使自训练过程能更有效地提升真实调控关系的排名 (文献中的秩位移分析证明了这一点)。这种方法使其在处理含干预数据的单细胞数据时,显著优于纯因果发现算法和纯相关性方法。

下面的命令行代码用来跑文章的测试数据没有问题,并不能直接用来跑自有数据:

export PYTHONPATH="."
python causalscbench/apps/main_app.py \
        --dataset_name weissmann_k562 \
        --output_directory output \
        --exp_id psgrn_rpe1_1_1 \
        --data_directory data \
        --training_regime "partial_interventional" \
        --partial_intervention_seed 0 \
        --fraction_partial_intervention 1.0 \
        --model_name "custom" \
        --inference_function_file_path "./src/main.py" \
        --subset_data 1.0 \
        --model_seed 0 \
        --omission_estimation_size 2000 \
        --do_filter

因为软件里面很多代码都是针对weissmann_k562weissmann_rpe1这两个数据集而写成了硬编码。想要自己分析使用只能动一动流程来适应自有数据了:

import warnings
warnings.filterwarnings('ignore')
import sys
sys.path.insert(0, '.')
from causalscbench.apps import main_app

ds = main_app.CreateDataset('data', filter=True)
dataset = ds.preprocess_and_save(path_k562, summary_stats_k562, "dataset_k562")
app = main_app.MainApp(output_directory='output', data_directory='data', model_name='custom', inference_function_file_path='src/main.py', dataset_name='dataset_k562', training_regime=main_app.training_regimes.TrainingRegime('partial_interventional'), exp_id='k562_result', omission_estimation_size=2000, filter=Ture)
app.dataset_splitter = main_app.DatasetSplitter(dataset, app.subset_data)
app.load_evaluators()
app.load_model()
metrics = app.train_and_evaluate()
INFO [1785481659.1561604]: Loading and preprocessing data.
INFO [1785481661.3930368]: Loading and processing evaluators.
INFO [1785482246.3828545]: Loading model.
INFO [1785482247.5626926]: Starting model training.
Cache observations: 100%|████████████████████████████| 1158/1158 [00:27<00:00, 42.76it/s]
Cache self interventions: 100%|██████████████████████| 1158/1158 [00:13<00:00, 84.16it/s]
 26%|████████                                        | 306/1158 [1:22:19<3:43:37, 15.75s/it]

如果filter为真时需要提前准备好一个统计表格,然后流程会用其来过滤数据,否则为NoneMainApp类的所有参数解释如下:

Args:
    output_directory (str): Directory for output results
    data_directory (str): Directory to store the datasets
    model_name (str, optional): Which method to run. Defaults to METHODS[0].
    inference_function_file_path (str, optional): Path to file for custom inference function. Default to empty string.
    dataset_name (List[str], optional): Which dataset to use. Defaults to DATASET_NAMES[0].
    model_seed (int, optional): Seed for model reproducibility. Defaults to 0.
    training_regime (training_regimes.TrainingRegime, optional): Choice of training regime. Defaults to training_regimes.Interventional.
    partial_intervention_seed (int, optional): If training_regime is partial intervention, seed for random selection of perturbed genes. Defaults to 0.
    fraction_partial_intervention (float, optional):  If training_regime is partial intervention, fraction of genes which should have interventional data. Defaults to 1.0.
    subset_data (float, optional): Option to subset the whole dataset for easier training. Defaults to 1.0.
    exp_id (str, optional): Unique experiment id (6 digit number). Default to randomly generated.
    max_path_length (int, optional): Maximum length of path to consider for statistical evaluation. Default to -1 (all paths).
    omission_estimation_size (int, optional): Number of negative samples to draw to estimate the false omission rate. If 0, the FOR is not checked.
    filter (bool, optional): controls whether to select only the strong perturbations

其中model_name参数的可选值如下:

METHODS = [
    "random100",
    "random1000",
    "random10000",
    "fully-connected",
    "lasso",
    "random_forest",
    "grnboost",
    "genie",
    "ges",
    "gies",
    "pc",
    "mvpc",
    "gsp",
    "igsp",
    "notears-lin",
    "notears-lin-sparse",
    "notears-mlp",
    "notears-mlp-sparse",
    "DCDI-G",
    "DCDI-DSF",
    "DCDFG-LIN",
    "DCDFG-MLP",
    "corum",
    "lr",
    "string_network",
    "string_physical",
    "custom",
    "chipseq",
    "pooled_biological_networks",
    "sortnregress",
]

文章实现的方法在main.py文件中,里面有一个N变量用来控制获取的调控基因对数量,默认为1000。文章的模型底层依托于LightGBM包来实现,程序的运行速度还可以,在拥有24核的环境里面5个小时跑完测试集k562 (310385 × 8563)。

软件链接:
https://github.com/GuanLab/PSGRN

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容