简介:本资源是一套面向计算机、电子信息工程及数学等专业本科生的跨模态神经影像分析工具包,聚焦于将结构MRI脑图与艾伦人类大脑图谱(AHBA)微阵列基因表达数据进行空间关联建模,适用于课程设计、期末大作业及毕业设计等实践场景。压缩包共4个文件(3个MATLAB脚本文件用于网络可视化、PLS回归建模与受体分布映射,1个Markdown格式说明文档),总大小仅24KB,轻量易部署,适配MATLAB 2014a至2021a多个版本。已有116人学习下载,代码采用参数化编程范式,关键参数集中定义、注释详尽、逻辑清晰,附赠可直接运行的案例数据,显著降低入门门槛。使用者可快速复现基因表达-脑结构关联分析流程,掌握AHBA数据预处理、空间标准化、多模态对齐及统计建模等核心技能,为后续开展脑连接组学或计算精神病学研究奠定实操基础。 看到“将MRI脑图与来自微阵列数据的基因表达艾伦人类大脑图谱相关联matlab代码.zip”这个标题,我心想:又是一个典型的影像转录组学项目。这种项目的本质,是把MRI扫描看到的脑结构或功能指标,与艾伦人类大脑图谱(AHBA)微阵列数据测到的基因表达放在同一个空间里做关联分析。代码用MATLAB写,处理对象是AHBA的微阵列表达矩阵和预处理后的MRI脑图,适合研究基因表达如何在大脑宏观尺度上塑造结构差异、或者反过来用影像指标反推分子机制的人参考。这套流程目前在神经影像与基因组学交叉领域已经不算新鲜,但真要自己从零搭一遍,坑比想象中多得多。
1. 项目到底解决什么问题:影像转录组学的核心思路
1.1 什么是MRI与基因表达关联分析
先给不熟悉这个方向的朋友解释一下背景。MRI在临床和科研里看的是脑的宏观属性:灰质体积、皮层厚度、白质纤维走向、血氧信号变化、功能连接强度等等。这些属性归根到底受分子水平调控,基因的表达差异会通过蛋白质合成、突触可塑性、髓鞘化等途径影响脑区的大小和活跃程度。
艾伦人类大脑图谱(Allen Human Brain Atlas,AHBA)把“基因表达”放进了三维脑空间里:它用微阵列芯片,在离体脑组织上按照立体定位坐标采集了大量样本点,每个样本点测出全基因组范围的表达丰度。于是理论上你就能做这样一件事——把MRI图像放到同一个标准空间,在每个AHBA样本点上提取MRI指标,再跟该点的基因表达量做统计关联,找出“哪些基因的表达模式与某种影像特征的空间分布最同步”。
这类分析在文献里通常叫imaging transcriptomics(影像转录组学),也有人叫transcriptome-neuroimaging association,核心就是建立宏观影像表型与微观转录组特征之间的桥梁。这类研究要回答的典型问题包括:阿尔茨海默病中萎缩最严重的脑区,是否恰好富集了某种炎症相关基因的表达?精神分裂症的功能连接异常,是否与突触相关基因的分布有重叠?这些如果只做MRI或者只做基因表达,都无法回答,必须把两类数据放到同一个框架里对齐。
1.2 这段MATLAB代码的实际价值
标题里的代码包,本质上就是把这条分析管线封装成了MATLAB实现。为什么要用MATLAB而不是Python?很大的原因在于:影像数据的读取、配准、体素操作在MATLAB里有SPM、FSL的MATLAB接口、BrainNet Viewer等比较成熟的生态;如果研究者本身就习惯SPM批处理,直接用MATLAB做完整条线,省去跨语言导数据的心智负担。
根据我拿这类代码的惯例,我会先去解压看有没有完整的数据读取脚本、坐标对齐脚本、关联计算脚本和结果可视化脚本。这种项目你很难找到一版能“一键跑通所有数据集”的代码,因为它依赖AHBA的原始文件路径、MRI数据的预处理产物、甚至MATLAB版本。代码包更常见的价值是逻辑参考:它告诉你每一步应该怎么组织数据、怎么处理索引、怎么避免常见的坐标错位。
2. 数据准备:AHBA微阵列数据到底长什么样
2.1 数据集核心文件与字段
AHBA的人类微阵列数据,一般从艾伦脑科学研究所官网(human.brain-map.org)下载,或者从一些重新整理过的镜像包获取。你需要重点关注的文件有四类:
| 文件/变量 | 作用 | 关键字段 |
|---|---|---|
| MicroarrayExpression.csv | 表达量矩阵,行是探针,列是样本 | probe_id, 样本表达值 |
| SampleAnnot.csv | 每个样本的注释信息 | sample_id, donor, structure, mni_x, mni_y, mni_z |
| Probes.csv | 探针注释,描述每个探针对应哪个基因 | probe_name, gene_symbol, gene_id, chromosome |
| PACall.csv | 探针检出概率(present call) | probe_id, 每个样本的检出概率 |
这个数据集在脑区覆盖上很细,整个大脑约3700个微阵列样本点,探针数在6万左右,注释到约2万个基因。第一个要记住的数字是:这些样本只来自6个捐赠者的大脑,其中2个捐赠者只提供了左半球数据,所以它的左右半球覆盖并不对称。这个点后面做统计时会非常要命,很多人忽略了它,直接把3700个样本当作独立观测,结果自由度被严重高估——这是这个领域被审稿人攻击最多的问题之一。
另一个容易忽略的是表达矩阵没有做基因名的行标签,探针和基因是多对一关系。同一个基因可能对应多个探针,而不同探针的灵敏度和特异性不同,选取策略直接决定下游结果。所以先不要急着算相关,数据侧准备工作占了整个项目的工作量至少一半。
2.2 MATLAB读取和探针过滤
大CSV文件在MATLAB里读取,我建议用readtable而不是csvread,后者对混合字段无能为力。读取前可以先确认文件分隔符,AHBA标准的导出文件是逗号分隔,但偶尔有带引号的字符串,readtable对这种格式更稳。
% 读取表达矩阵(假设已经解压到本地) exprTable = readtable('MicroarrayExpression.csv', 'PreserveVariableNames', true); sampleAnnot = readtable('SampleAnnot.csv', 'PreserveVariableNames', true); probeInfo = readtable('Probes.csv', 'PreserveVariableNames', true); pacTable = readtable('PACall.csv', 'PreserveVariableNames', true);读进来之后,第一步通常是过滤探针。微阵列芯片上并不是所有探针都能可靠检出目标基因,尤其对于离体脑组织,RNA质量、杂交效率都会影响信号。PACall文件给出每个探针在每个样本中的检出概率,取值0到1。一个常见策略是保留在所有样本中平均检出概率大于某个阈值的探针,比如0.5或者0.4。
pacMean = mean(pacTable{:, 2:end}, 2); keepProbe = pacMean > 0.5; exprFilt = exprTable{keepProbe, 2:end}; probeFilt = exprTable{keepProbe, 1};这个步骤看起来简单,但阈值选择会直接影响后续基因数量。阈值取得太高,很多在特定脑区才表达的基因会被误杀;取得太低,又会带入大量噪声。我自己的习惯是先看表达量分布,用0.5作为初筛,然后单独检查目标基因是否被保留。如果你研究的是一组已知的候选基因,甚至可以针对它们单独放宽阈值,避免因为全局过滤太狠把关键基因丢掉。
2.3 MRI数据侧的预处理要求
MRI数据侧要做的事情其实很明确:把它配准到AHBA样本坐标所在的标准空间。AHBA样本注释里的mni_x、mni_y、mni_z用的是MNI152立体定位空间,如果你的MRI数据不是这个空间,关联前必须完成空间标准化。
在MATLAB里,用SPM12的Coregister和Normalise模块可以做这件事。如果用的是CAT12处理的结构像,输出通常会直接给到MNI空间,且带灰质密度图(mwp1开头)。这种灰质密度图很适合做全脑关联,因为它在体素水平表示局部灰质比例,与AHBA样本点的组织学取材具有较好的对应关系。
这里有一个实操建议:MRI指标尽量选在MNI空间里平滑程度适中、且具有明确生物学意义的图。比如灰质密度、皮层厚度(投影到体积空间后)、ALFF(静息态低频振幅)都可以。尽量避免选对预处理参数极其敏感的指标,比如未做平滑的原始T1加权强度,这种图噪声大,跟基因表达作相关时会得到一堆伪显著结果。
3. 核心实现:样本坐标与MRI体素的精准对应
3.1 坐标对齐这一步为什么容易出错
我在第一次做类似项目时,花了大半天排查一个诡异问题:左右半球的结果完全对称地反了。后来发现是MRI图像的体素到世界坐标的变换矩阵没有正确读取,导致体素索引取到的位置发生了镜像翻转。
AHBA样本坐标是毫米级的MNI空间坐标,MRI图像在NIfTI格式里也带有4×4的仿射变换矩阵(qform/sform),从体素索引到世界坐标是线性关系。MATLAB里用niftiinfo和niftiread读取NIfTI时,niftiinfo返回的Transform是体素到世界坐标的变换,一定要用它,而不是自己手写坐标映射。
坐标对齐有两个层次的需求。第一种是“样本点取体素值”:直接用AHBA给出的mni_x/y/z坐标,借助interp3或者spm_sample_vol提取MRI在该位置的数值。第二种是“样本点归属到脑区”:通常用AAL、Desikan-Killiany或DK-ROI模板,把样本点投影到最近的脑区标号,再求每个脑区内样本的平均表达量。大多数文献采用第二种方式做脑区水平分析,因为脑区水平可以缓解单一取样点的测量噪声,也更容易跟常用影像指标对齐。
3.2 从探针表达量到基因表达矩阵
探针过滤之后,下一步是把探针水平数据聚合到基因水平。这个操作在MATLAB里用grpstats或者accumarray都能做,逻辑很简单:同一个基因名下的多个探针表达量取平均,或者取在样本间变异最大的那个探针。
两种策略的选择其实是有讲究的。取平均在信号稳定的时候表现好;取最大变异探针能突出基因的区域差异,但受离群样本影响大。文献里两类做法都有,但如果你要跟已发表的结果做对比,尽量对齐对方采用的聚合策略。我在代码里更常用的是取平均,配合对每个基因做z-score标准化,这样不同基因之间的表达量量纲差异不会影响后续相关计算。
% 假设exprFilt的行与probeFilt一一对应 geneList = probeInfo.gene_symbol(keepProbe); % 剔除空基因名 validGene = ~cellfun(@isempty, geneList); exprFilt = exprFilt(validGene, :); geneList = geneList(validGene); % 按基因名取均值 [uniGenes, ~, geneIdx] = unique(geneList); geneExpr = zeros(length(uniGenes), size(exprFilt, 2)); for g = 1:length(uniGenes) geneExpr(g, :) = mean(exprFilt(geneIdx == g, :), 1); end如果你数据量大,还可以用splitapply替代循环。但基因数通常在2万这个量级,矩阵是2万×3700左右,循环也不算慢。需要提醒的是,这个循环里的mean是沿着样本维度的,如果你误写成mean(exprFilt(geneIdx == g, :)),在MATLAB新版里会沿着第一个非单例维度计算,结果就是每个探针在全部样本上的均值,而不是每个样本在多个探针上的均值,一不留神就错。
3.3 构建“表达-影像”数据矩阵的MATLAB实现
假设你已经有了基因表达矩阵geneExpr,维度是基因数×样本数;同时你从SampleAnnot里整理出了对应的样本坐标列表,下一步就是把MRI指标按照同样的样本顺序取出来。
% nifti读取 info = niftiinfo('mwp1_gm.nii'); V = niftiread(info); % 坐标矩阵 coords = [sampleAnnot.mni_x, sampleAnnot.mni_y, sampleAnnot.mni_z]; % 取体素值,注意世界坐标->体素坐标的转换 vox = worldToVoxel(info, coords); % 如果R2021a之后版本可用 x = round(vox(:,1)); y = round(vox(:,2)); z = round(vox(:,3)); n = size(coords, 1); mriAtSamples = zeros(n, 1); for i = 1:n mriAtSamples(i) = V(x(i), y(i), z(i)); end如果你的MATLAB版本没有worldToVoxel,可以用info.Transform的逆矩阵手动算:
T = info.Transform; invT = inv(T.T); vox = round([coords, ones(n,1)] * invT');但这里有一个非常大的坑:info.Transform是体素到世界坐标的变换,行的向量表示方式要搞清楚。在MATLAB里,[x,y,z,1]乘以变换矩阵得到世界坐标,所以反过来需要用逆变换。我见过不少人把Transform直接拿过来乘坐标,结果坐标全飞了。
更稳健的方式是用SPM工具。如果你已经装了SPM12,可以用spm_sample_vol,它能直接处理坐标和插值,不需要手动做体素索引转换。
% 用SPM读取图像卷 Vg = spm_vol('mwp1_gm.nii'); mriAtSamples = spm_sample_vol(Vg, coords(:,1), coords(:,2), coords(:,3), 1);第三个输入参数1表示三线性插值。我比较推荐这种方法,因为它绕开了坐标精度问题,而且代码可读性好。你只需要保证coords的列顺序是x、y、z,SPM内部会处理仿射变换。唯一要注意的是MNI坐标方向,AHBA用的是RAS+坐标,SPM同样遵循这个约定,因此理论上一致,但如果你的MRI是从别的软件导出的,要确认一下是否也是RAS+,否则可能出现镜像翻转。
4. 关联计算与统计检验:不能只算一个相关性
4.1 常用关联模型:从皮尔逊相关到PLS
数据矩阵构建好之后,核心分析就是计算基因表达与影像指标的空间关联。最简单也最常用的是逐基因的皮尔逊相关:对每个基因,计算它在所有样本点上的表达向量与MRI指标向量的相关系数。
r = corr(geneExpr', mriAtSamples); % r维度:基因数×1这里corr的输入需要每一列是一个观测,所以要把geneExpr转置。得到的是每个基因与MRI指标的空间相关r值。如果你想做偏相关,控制掉例如全脑体积、白质分数、甚至捐赠者身份等变量,可以用partialcorr。
covariates = [donorIdx, brainVolume, age]; % 示例 [r_partial, p_partial] = partialcorr(geneExpr', mriAtSamples, covariates);偏相关能减少一些已知混杂因素的影响,但不要指望它能完全解决数据内在的非独立性,因为样本来自6个捐赠者,本来就不是独立观测。
除了相关,还有一种常见做法是偏最小二乘回归(PLS),思路是寻找基因表达矩阵与影像指标之间协方差最大的潜变量,再解释哪些基因在这个潜变量上负载高。PLS的优势是能同时处理多个影像指标,比如你不仅想看灰质体积,还想看皮层厚度和白质分数,PLS可以构建一个基因表达与多维影像表型之间的联合模式。MATLAB里用plsregress函数就能做,但解释起来比相关复杂,如果不是写论文,先用相关把路走通更实际。
4.2 置换检验与空间自相关校正的MATLAB思路
算完相关之后,必然要回答统计显著性。这里的核心困境是:空间数据不满足独立观测假设。相邻脑区的基因表达高度相似,MRI指标也高度平滑,常规的t检验或者Fisher z变换都会给出膨胀的p值。换句说,全脑3700个点,其实有效自由度远小于这个数量。
业内比较公认的校正策略是空间置换检验,其中最流行的一种是“spin test”。基本想法是保留脑区或样本点的空间结构,把表达谱对应的空间标签做球面旋转,破坏表达值与空间位置的对应关系,然后重算相关,得到零分布。
在MATLAB里实现一个简化版,可以用球坐标旋转的方法:
% 将样本坐标单位化到球面 [Xs, Ys, Zs] = sphere_coords; % 假设是每个样本点的球面单位向量 % 随机旋转三个欧拉角 phi = rand*2*pi; theta = rand*pi; psi = rand*2*pi; Rx = [1 0 0; 0 cos(phi) -sin(phi); 0 sin(phi) cos(phi)]; Ry = [cos(theta) 0 sin(theta); 0 1 0; -sin(theta) 0 cos(theta)]; Rz = [cos(psi) -sin(psi) 0; sin(psi) cos(psi) 0; 0 0 1]; R = Rz * Ry * Rx; rotated_coords = [Xs, Ys, Zs] * R'; % 用旋转后的坐标重新建立与表达谱的对应,再计算相关但这里要注意:spin test通常是在脑区层面做,用于皮层表面坐标比较合理;如果你用的是体积MNI坐标而不是球面坐标,直接旋转会出问题。更保险的做法是保留样本坐标,随机打乱样本与MRI值的对应关系,做普通的置换检验。虽然这种置换没有显式建模空间自相关,但它通过打乱空间位置关系,能在一定程度上反映“如果基因表达模式在空间中随机重排,还会不会得到这么强的相关量级”的问题。这种简单置换得到的p值通常比参数检验保守一些,也更受审稿人认可。
4.3 多重比较校正与结果可视化
全基因组做关联,基因数接近2万,就算用置换检验,也不能每个基因独立看p值。常用的做法是FDR控制,MATLAB里可以用mafdr函数,如果你有统计工具箱的话。
p_perm = zeros(length(r), 1); % ... 置换循环生成零分布 ... fdr_q = mafdr(p_perm, 'BHFDR', true);置换次数一般至少1000次,更稳是5000或10000次。你可以用parfor并行,因为每个置换之间相互独立,这一步能大幅缩短时间。
结果的可视化方面,MATLAB基本绘图组件够用,但要画到脑表面上,通常推荐把显著基因的关联结果投影到皮层表面或者体积脑模板上。如果你只是展示相关模式的总体形态,可以用scatter3按样本坐标画点,颜色映射r值,比用切片图更直观。
scatter3(coords(:,1), coords(:,2), coords(:,3), 20, r_selected, 'filled'); colormap(jet); colorbar;如果想更专业一点,可以导出到BrainNet Viewer或者用FSL的atlasquery做区域富集分析。不过那属于扩展功能了,基础版代码到这个程度已经能回答“哪些基因与这个MRI指标显著相关”这个核心问题。
5. 我踩过的坑和排查经验
5.1 常见问题速查表
| 现象 | 可能原因 | 解决办法 |
|---|---|---|
| 左右半球结果完全镜像 | 坐标方向约定不一致 | 检查MRI数据是RAS+还是LPS+,必要时翻转x轴 |
| 大量NaN表达值 | 未做探针过滤,或基因匹配错误 | 检查PACall,剔除低检出探针 |
| 相关r值普遍过高 | 样本非独立、存在空间自相关 | 用置换检验,而不是直接看原始p值 |
| 基因表达矩阵聚合后基因数减少过多 | 探针过滤阈值太严 | 单独检查目标基因,适当放宽阈值 |
| 读取CSV耗时极长 | 文件太大(几百MB) | 用datastore,或者先转成MAT文件再分析 |
| MRI体素值大量为0 | 坐标落在脑外或灰质概率为0 | 用interp3/spm_sample_vol的零填充处理,注意脑外点排除 |
第一个问题是最伤时间的。如果你发现左右半球关联模式高度对称但方向相反,第一时间去查MRI世界坐标系的轴向;AHBA用RAS坐标,部分第三方软件输出的NIfTI可能是LPS,需要把x取反。
5.2 几点实操心得
这个项目跑了几个数据集之后,我有两个很深的体会。第一个是:除非你明确要做体素水平的精细分析,否则尽量先在脑区水平上做。把3700个样本点归并到AAL或Desikan脑区,对每个脑区求平均表达量和平均MRI值,然后以脑区为样本做关联。这样虽然样本数骤降,但噪声也被压低了,结果的可解释性反而更强,而且spin test做起来也更顺滑。
第二个是:不要迷信全局最优的探针过滤策略。基因表达数据的预处理方法选择非常多,不同方法算出来的显著基因列表可能只有一半重叠。唯一的建议是代码里要把预处理参数全部保留下来,最好能在输出结果里带上基因版本的注释信息,这样后来人(包括你自己)还能追溯。
另外我强烈建议在代码里加入中间结果的保存。比如把过滤后的表达矩阵、样本坐标、MRI取样值都分别存成MAT文件,这样你不需要每次重启分析都重新加载几百MB的原始CSV。MATLAB在大IO上是弱项,一次性把数据整理成分析格式往往能省一半以上的时间。
还有一个细节:如果代码里用到了特定版本的MATLAB函数,比如worldToVoxel是R2021a引入的,spm_sample_vol则需要安装SPM12,运行前最好在代码开头做一个环境检查:
try niftiinfo('example.nii'); catch error('需要Image Processing Toolbox或SPM支持'); end这些小检查看起来不起眼,但在你换电脑、换实验室、隔半年再跑这份代码的时候,能帮你快速定位环境问题,而不是对着报错信息干瞪眼。
6. 这个代码包还能往哪些方向扩展
基础版本的MRI-基因表达关联算完之后,后续还有几个非常值得做的扩展。第一个是基因集富集分析:如果显著基因列表里富集了某个通路,比如突触传递、免疫应答、线粒体代谢,那你就不只是报一堆基因名,而是能讲一个生物学故事。MATLAB里做富集分析不太方便,通常是导出基因列表后用外部工具或者R包做,但这属于标准的后续步骤。
第二个扩展是反过来建立预测模型:用基因表达模式去预测MRI指标的空间分布,或者用MRI指标去反推基因表达特征。这类模型在临床上可能用于识别那些与疾病相关脑区变化最一致的分子标记物。但注意,这种预测依然不能等同于因果关系,毕竟宏观影像和基因表达只是相关关系。
第三个是纳入更多模态的AHBA数据。AHBA除了微阵列数据,还有RNA测序数据和人脑发育转录组数据。如果研究问题聚焦在发育阶段变化,可以换用发育转录组图谱;如果聚焦在神经精神疾病的精细分子分型,RNA-seq的敏感度和动态范围可能更好。代码主体流程差不多,只是数据解析格式不同。
从我个人的使用体验讲,这类代码包最大的价值不是算法多么高深,而是把数据对齐这件枯燥容易出错的事情整理得清晰明了。只要坐标对齐、探针聚合、统计检验这三步做扎实,后续任何高级分析都有稳固的地基。如果你准备在自己的数据上跑这套流程,我建议先从单个候选基因入手,把整条管线走通,再扩展到全基因组分析,否则中间一旦出问题,排查的复杂度会乘十倍。
本文还有配套的精品资源,点击获取