AHBA基因表达数据处理全流程:从探针重注释到脑区映射的实战指南

AHBA基因表达数据处理全流程:从探针重注释到脑区映射的实战指南

最近在整理一批脑影像数据时,遇到了一个经典问题:如何将艾伦人脑图谱(Allen Human Brain Atlas, AHBA)中的基因表达数据,与我自己研究的脑区或体素坐标对应起来?网上搜了一圈,发现很多教程要么是零散的代码片段,要么直接丢给你一个复杂的命令行工具,但很少有人讲清楚从原始数据到最终可用矩阵,中间到底要经历哪些“坑”,以及为什么必须这么处理。

比如,你可能会直接运行abagen.get_expression_data(),然后得到一个看似完美的矩阵。但如果你没注意探针重注释、样本质量控制、半球对称化这些步骤,你的分析结果可能从一开始就建立在有偏差的数据上。更麻烦的是,这种偏差在后续的统计分析中很难被察觉,直到你发现结果无法重复时,才回头排查数据预处理的问题。

这篇文章,我就结合abagen这个 Python 工具包,把处理 AHBA 基因表达数据的完整流程、核心决策点和常见陷阱梳理一遍。我们的目标不是简单地“跑通代码”,而是理解每一步操作背后的生物学和统计学意义,最终获得一份可靠、可解释、可用于后续分析的基因表达数据。

1. 为什么处理 AHBA 数据不能直接“拿来就用”?

在深入代码之前,我们必须先理解 AHBA 数据本身的复杂性。这决定了我们后续所有处理步骤的必要性。

艾伦人脑图谱提供了六名捐献者死后大脑的微阵列基因表达数据。听起来很直接,但每个环节都引入了需要处理的变异:

  • 样本来源的异质性:六名捐献者的年龄、性别、死因、死后间隔时间(PMI)都不同。这些因素都可能影响基因表达水平。
  • 取样位置的挑战:大脑样本并非均匀采集。某些脑区(如皮层)取样点密集,而深部核团可能样本很少。此外,左右半球的取样点并不完全对称。
  • 探针与基因的映射:微阵列技术测量的是“探针”的信号强度,一个基因可能对应多个探针。我们需要决定是选择最具代表性的探针,还是合并多个探针的信号。
  • 数据归一化:不同样本、不同批次间的基因表达信号需要进行标准化,才能进行跨样本的比较。

如果忽略这些,直接把所有样本的原始表达值取平均,就相当于默认所有大脑、所有脑区、所有探针都是同质的,这显然会引入巨大的噪声和偏差。abagen工具的核心价值,就在于它提供了一套标准化、可复现的流程来处理这些异质性,让不同研究之间的结果具有可比性。

2. 搭建环境与理解abagen的核心工作流

abagen是一个 Python 包,它的安装很简单:

pip install abagen

但比安装更重要的是理解它的输入和输出。abagen的核心任务可以概括为:将一组大脑空间坐标(或脑区标签)映射到 AHBA 的基因表达数据上,并输出一个结构化的表达矩阵

它的核心函数get_expression_data()主要需要两类输入:

  1. 大脑空间定义:你要研究哪些位置?这可以是一个 Nifti 格式的脑图谱文件(每个体素有一个编号),也可以是一个包含脑区标签的列表。
  2. 处理参数:你打算如何解决上一节提到的那些异质性问题?这通过一系列参数来控制。

一个最简化的调用如下:

import abagen # 假设你有一个名为 'atlas.nii.gz' 的脑图谱文件 expression_matrix = abagen.get_expression_data('atlas.nii.gz')

执行这行代码后,abagen会在后台自动完成一系列复杂操作:

  1. 数据获取:如果本地没有缓存,它会自动下载 AHBA 的原始数据。
  2. 探针重注释:使用最新的基因信息来更新老版本微阵列的探针定义。
  3. 样本匹配:将 AHBA 的每个样本点匹配到你的脑图谱中最近似的脑区。
  4. 质量控制:根据设定的标准(如 RNA 完整性)过滤掉质量差的样本。
  5. 基因聚合:处理一个基因对应多个探针的情况。
  6. 区域聚合:将一个脑区内所有匹配样本的表达值进行汇总(默认是中位数)。
  7. 返回矩阵:最终得到一个DataFrame,行是脑区,列是基因。

然而,直接使用默认参数通常不是最佳实践。接下来我们就拆解每个关键步骤,看看如何根据你的研究目标进行调整。

3. 关键步骤拆解与参数决策:从“能用”到“可靠”

abagen的强大之处在于其高度的可定制性。下面我们逐一剖析几个最关键的处理环节及其对应参数。

3.1 探针选择与基因重注释:确保你测量的是正确的基因

这是数据可靠性的第一道关。AHBA 使用的微阵列芯片设计基于某个特定版本的基因数据库。随着时间推移,许多探针的注释可能已过时(例如,探针可能映射到非编码区,或对应基因已更名)。

abagen默认使用reannotate=True,它会利用alleninf包提供的最新注释信息来更新探针。强烈建议不要关闭此选项

对于多探针基因,你有几种聚合策略(通过probe_selection参数控制):

  • 'diff_stability'(默认且推荐):选择在不同大脑样本间表达最稳定的探针。稳定性高的探针更能反映真实的生物学变异,而非技术噪声。
  • 'average':取所有探针表达值的平均值。简单,但可能混合了不同亚型或非特异性信号。
  • 'max_intensity':选择平均表达强度最高的探针。可能偏向于高表达基因,但未必最具代表性。
# 示例:使用默认的差异稳定性选择探针 expression_matrix = abagen.get_expression_data( 'atlas.nii.gz', probe_selection='diff_stability' )

3.2 样本质量控制:剔除不可靠的数据点

不是所有 AHBA 样本都质量上乘。RNA 降解、取样问题都可能导致数据不可靠。abagen提供了基于 RNA 完整性数(RIN)的过滤。

  • sample_norm:如何对样本进行归一化?'srs'(scaled robust sigmoid) 是默认方法,它对异常值不敏感,效果通常优于简单的 Z-score。
  • donor_probes:是否只保留在所有供体中均被检测到的探针?'intersect'(默认) 会这样做,确保基因在所有人中都可测量,这增强了结果的普遍性,但会损失一些个体特异性信息。
  • norm_structure:是否分别对大脑皮层和皮层下结构进行归一化?由于这两类组织的细胞构成和表达谱差异巨大,建议设置为True
# 示例:进行严格的样本质量控制 expression_matrix = abagen.get_expression_data( 'atlas.nii.gz', sample_norm='srs', donor_probes='intersect', norm_structure=True, # 可以设置RIN阈值,例如剔除RIN<5的样本(如果元数据可用) )

3.3 脑区匹配与表达值汇总:空间映射的核心

这是将离散的样本点映射到你定义的脑区的关键一步。abagen使用欧几里得距离寻找每个样本点最近的脑区体素。

  • region_agg:如何汇总一个脑区内所有样本点的表达值?'median'(中位数,默认) 比'mean'(平均数) 更能抵抗异常值的影响。
  • tolerance:匹配距离的容差(单位:mm)。如果一个样本点与最近脑区的距离超过此值,它将被丢弃。默认是2mm。如果你的图谱分辨率很低或脑区很小,可能需要调大此值,否则大量样本会被丢弃。

一个常见陷阱:默认情况下,abagen会独立处理每个供体的大脑,然后将结果在供体间平均。但 AHBA 的样本在左右半球是不对称的。如果你的图谱包含对称的左右半球区域,而某个半球样本点缺失,直接平均会导致偏差。

3.4 处理半球不对称性:容易被忽略的关键一步

AHBA 的取样点在左右半球并非镜像对称。例如,左半球可能有某个脑区的样本,而右半球没有。如果你有一个包含左右对称区域(如“左额上回”和“右额上回”)的图谱,并且希望得到每个区域独立的表达值,就必须处理这个问题。

abagen提供了lr_mirror参数:

  • False(默认):不进行镜像处理。可能导致一侧脑区因缺乏样本而数据缺失。
  • True:进行镜像处理。将一侧半球的样本点镜像对称到另一侧,用于填充缺失的数据。这对于研究左右半球差异或需要完整对称数据集的分析至关重要。
# 示例:启用镜像处理以填充半球不对称的样本 expression_matrix = abagen.get_expression_data( 'atlas.nii.gz', lr_mirror=True, # 关键参数! region_agg='median', tolerance=2 )

4. 完整实战流程与结果验证

现在,我们将所有步骤串联起来,形成一个稳健的流程。假设我们使用广泛使用的 Schaefer 400 脑区图谱。

import abagen import numpy as np import pandas as pd from nilearn import datasets import matplotlib.pyplot as plt # 1. 加载一个标准脑图谱(例如Schaefer 400区) schaefer_atlas = datasets.fetch_atlas_schaefer_2018(n_rois=400, yeo_networks=7) atlas_filename = schaefer_atlas['maps'] # 2. 使用一套经过考虑的参数获取表达矩阵 expression_df = abagen.get_expression_data( atlas_filename, # 探针与基因设置 probe_selection='diff_stability', # 选择稳定探针 reannotate=True, # 使用最新注释 # 样本质量控制 sample_norm='srs', # 稳健归一化 donor_probes='intersect', # 保留共有探针 norm_structure=True, # 分皮层/皮层下归一化 # 脑区聚合设置 region_agg='median', # 使用中位数抗异常值 tolerance=2, # 2mm匹配容差 # 处理半球不对称 lr_mirror=True, # 镜像样本以填充缺失半球数据 # 其他 verbose=1 # 打印处理进度 ) # 3. 查看结果 print(f"表达矩阵形状: {expression_df.shape}") # 应为 (400脑区, ~15000基因) print(f"前5个脑区,前5个基因:\n{expression_df.iloc[:5, :5]}") print(f"是否有缺失值: {expression_df.isnull().any().any()}")

运行后,你应该关注以下几点进行验证:

  1. 矩阵维度:行数应等于你的脑区数量(如400),列数约为15000-20000(人类基因数量)。如果行数不对,检查脑区匹配;如果列数远少于此,检查donor_probesprobe_selection设置是否过于严格。
  2. 缺失值:理想情况下,整个矩阵应该没有缺失值(NaN)。如果出现缺失,通常是因为某个脑区没有匹配到任何样本点。这可能是因为:
    • 图谱分辨率太低,脑区体积太小。
    • tolerance设置太小。
    • 该脑区在 AHBA 中确实没有取样(如一些白质区域)。此时需要考虑是否从分析中剔除该脑区,或使用插值方法(谨慎使用)。
  3. 数据分布:可以简单绘制一个脑区或一个基因的表达值分布直方图,检查是否存在极端异常值。
# 快速检查第一个脑区的表达值分布 plt.figure(figsize=(10,4)) plt.subplot(1,2,1) plt.hist(expression_df.iloc[0, :].values, bins=50) plt.title(f'Expression Distribution for Region: {expression_df.index[0]}') plt.xlabel('Expression (normalized)') plt.ylabel('Frequency') # 快速检查一个高表达基因(如SNAP25,一种神经元标记物)在所有脑区的分布 if 'SNAP25' in expression_df.columns: plt.subplot(1,2,2) plt.hist(expression_df['SNAP25'].values, bins=50) plt.title('Expression Distribution of Gene SNAP25 across Regions') plt.xlabel('Expression (normalized)') plt.ylabel('Frequency') plt.tight_layout() plt.show()

5. 进阶议题与排错指南

当你掌握了基本流程后,可能会遇到更复杂的需求或问题。

5.1 获取个体水平的数据

默认情况下,abagen返回的是跨六名供体平均后的数据。如果你想进行个体差异分析,需要获取每个供体单独的数据。这可以通过设置return_donors=True来实现。

# 获取每个供体的表达矩阵列表 donor_expressions = abagen.get_expression_data( atlas_filename, lr_mirror=True, return_donors=True # 关键参数 ) print(f"供体数量: {len(donor_expressions)}") for i, df in enumerate(donor_expressions): print(f"供体 {i+1} 矩阵形状: {df.shape}") # 现在你可以分析个体间的差异了

5.2 常见错误与排查

  • 错误:MissingDependencyError:确保已安装所有依赖,特别是nibabel,pandas,numpy,scipy,以及可选的nilearn(用于图谱加载)。
  • 错误:下载数据失败或极慢abagen会从互联网下载数据。确保网络通畅。数据文件较大(约1GB),首次运行需要耐心。下载路径通常位于~/abagen-data
  • 问题:大量脑区出现缺失值(NaN)
    1. 检查你的图谱文件是否能被正确读取(用nibabel.load()试试)。
    2. 增大tolerance参数(例如从2mm增加到4mm)。
    3. 确认你的图谱坐标空间是否与abagen预期的一致(默认是MNI空间)。如果图谱是其他空间(如Talairach),需要使用atlas_info参数提供坐标转换信息,这属于高级用法。
    4. 考虑使用更低分辨率的图谱,或者接受某些脑区无数据的事实。
  • 问题:基因数量异常少
    1. 检查donor_probes参数。如果设为'intersect',则只保留所有6个供体共有的基因,这可能会减少基因数量。如果研究需要更多基因,可以考虑设为'union'(保留任何供体中出现的基因),但后续处理缺失值会更复杂。
    2. 检查probe_selection。如果使用'diff_stability'且稳定性阈值设置过高,也可能过滤掉大量基因。

5.3 结果的可解释性与局限性

最后,必须清醒认识到结果的局限性:

  • 样本量小:仅6名供体,个体差异可能很大。跨供体平均会抹除有价值的个体变异信息。
  • 死后数据:基因表达可能受死亡过程、PMI等因素影响。
  • 空间精度:微阵列样本点是宏观组织块(毫米级),无法反映细胞类型特异性的表达。新兴的单细胞测序数据能提供更精细的信息,但目前尚无全脑覆盖的数据集。
  • 静态快照:AHBA 是成年大脑某一时刻的快照,无法提供发育或动态过程的信息。

因此,基于 AHBA 的分析结果,更适合作为发现宏观尺度基因表达-脑结构/功能关联的起点,其结论需要其他技术(如 PET、转录组学关联研究)或在独立样本中进一步验证。

处理 AHBA 数据就像完成一次精密的考古拼接:我们手中有来自六个遗址的碎片(样本),需要根据一张现代地图(你的脑图谱),使用一套标准方法(abagen流程),将它们还原成一幅完整的基因表达壁画。每一步选择——用哪块碎片、如何修补缺失部分、如何统一色彩——都影响着最终画面的可信度。理解流程背后的“为什么”,远比记住参数命令更重要。当你拿到那份表达矩阵时,你应当清楚它包含了哪些信息,妥协了哪些细节,以及最适合用它来回答什么样的科学问题。