Nilearn汇总之我的理解(一文通览Nilearn绝大部分功能)

wuchangjian2021-11-03 00:42:38编程学习

前面学习完带ROI的mask的预测(入门教程),以及group mask的预测(anova-SVM),把这些前置内容融汇贯通后,就可以开始看我下面的个人理解了。

首先回顾下前面的内容:

对于机器学习的基础:机器学习,说白了,就是用模型去拟合X和Y。作为医学生,我们没必要去弄明白这些模型内部的实现原理,只需要记住分类和回归中,最经典的几个模型,反正有skitlearn,API全部统一太方便了。因此,机器学习就是沟通X和Y的桥梁,这么去理解。Y好说,要么是离散数据,比如脸、猫,用来分类;要么是连续数据,比如1,2,3…,用来回归。重点来了,那么X是啥?在skitlearn里,X就是二维数据,列标签代表特征值,行标签代表样本(可以理解为每一个病人)。所以在skitlearn里,X就是二维,Y是一维(序列)。
Nilearn包,操作起来简单,它的实现原理其实很简单:核磁是三维数据,加上时间点就是四维数据,所以func数据就是四维的。要把它拿去机器学习,怎么办呢?很简单,就是降维!那么降维怎么实现的呢?看看下面,我结合具体例子解释。(仅供医学生去理解,统计学同学请忽略这篇文章)
降维有2种方法:
第一种是把体素,还有时间点作为特征值,(体素1,体素2,体素…10000)数据量很大,还好numpy对于矩阵处理非常棒。这种方法用于多个samples(这里的samples就是我们实验中的受试者)。
第二种是把体素作为sample,(体素1,体素2…体素10000),时间点作为特征值。这种方法用于单个受试者,但是需要这个受试者在实验中进行任务态功能核磁的重复刺激。

第一章 MVPA

MVPA :multi-variate pattern analysis 多变量模式分析
对于入门教程:

# 1.导入数据
bold_file = bold.nii.gz
mask_roi_file = mask_roi.nii.gz
anatomical_file = anatomical.nii.gz
labels = labels.txt
condition_mask = labels.isin(['face', 'cat'])
# 2.数据预处理
#=== 去除不相干时间点 ###
#=== 如果实验中没有不相干时间点,就不用这步 ###
from nilearn.image import index_img
bold_prepared = index_img(fmri_filename, condition_mask)
# 3.分成训练集和测试集
# 4.设置评估器 evaluator
from nilearn.decoding import Decoder
decoder = Decoder(
    estimator='svc', mask=mask_roi_file,
    standardize=True, cv=5,
    scoring='accuracy'
)
# 5.拟合数据,同时进行交叉验证
decoder.fit(bold_prepared, labels)
print(decoder.cv_scores_) #查看交叉验证分数,可以做AUC图
# 6.构建评估函数,评估上述模型的性能
dummy_decoder = Decoder(estimator='dummy_classifier',mask=mask_filename,
cv=cv)
######这里的dummy分类器strategy参数有5个选项,随机、均匀、最高次、自定义。很有用!
# 7.查看权重
weight_img = decoder.coef_img_['face'] # difine权重图
decoder.coef_img_['face'].to_filename('haxby_svc_weights.nii.gz') #保留权重图

from nilearn.plotting import plot_stat_map, show
plot_stat_map(weight_img, bg_img=anatomical_image, title='SVM weights') #权重图可视化一

from nilearn.plotting import view_img
view_img(weight_img, bg_img=anatomical_image,
         title="SVM weights", dim=-1) #权重图可视化二

这里其实就是把体素当成samples了,所以label就是对应的时间点,而且只用于单个受试者。

对于anova-SVM

# 1.准备数据
mask_file = grou_mask.nii.gz
# 2.数据预处理
# 3.分成训练集和测试集
# 4.设置评估器
decoder = Decoder(estimator='svc', mask=mask_img, standardize=True, screening_percentile=5, scoring='accuracy', cv=cv)
###### screening_percentile参数:选择百分位,单位 %,顺序 最高。
# 5.拟合数据,同时进行交叉验证
# 6.构建评估函数,评估上述模型的性能
# 7.权重可视化
from nilearn.plotting import plot_stat_map, show
plot_stat_map(weight_img, bg_img=anatomical_image, title='SVM weights')
show()

这里和上面的基本一样,不同点是,如果用的group mask,那么就要设置下screening_percentile参数,不然几万个体素全部显示的话,人都没了。实现screening_percentile的方式就是方差分析的F1值大小。当然啦,选择的体素越多,准确率也会越高,这是肯定的。

以上是入门基础。掌握了入门了,下面开始越来越深入。

第二章 Evaluator

首先是分类器:nilearn.decoding.Decoder
分类器的选择:svc、svc_L1、logistic、logistic_L1、ridge_classifier、dummy classifier
三类及以上 —— 一对一 sklearn.multiclass.OneVsRestClassifier 将每个类别与所有其他类别区分开来;一对一 sklearn.multiclass.OneVsOneClassifier 区分每对类。
其次是回归器: nilearn.decoding.DecoderRegressor
回归器的选择:svr、ridge_regressor、dummy_regressor
注意点:
1、SVC-l2 (即SVC)对正则化参数的选择相当不敏感,这使得它成为大多数问题的首选方法
2、在应用估计量之前,对数据做了什么通常比选择估计器更重要。通常,对数据进行标准化很重要,平滑通常很有用,并且必须消除诸如会话(sessions)效应之类的有害影响
3.官网说可以使用skitlearn的所有evaluators,这个我暂时保持存疑,我还没有尝试行不行,如果可以的话,那就还挺好的,还有常用的bagging和voting classifier,如果能用那就太棒了。

第三章 FREM (多个被试静息态)

FREM :fast ensembling of regularized models for robust decoding用于稳健解码的快速聚集式正则化模型
FREM通过快速聚类使用隐式空间正则化,并聚合大量在训练集的各种分割上训练的估计器,从而以比其他空间正则化方法更低的计算成本返回非常强大的解码器。
2018年文献。
有两种:nilearn.decoding.FREMClassifier 和 nilearn.decoding.FREMRegressor

# 1.准备数据
func_file = bold.nii.gz # 不需要mask
background_img = mean_img(func_file)
# 2.数据预处理
# 3.分成训练集和测试集
# 4.设置评估器 FREM !!!!!!!!!!!!!!!
from nilearn.decoding import FREMClassifier
decoder = FREMClassifier(cv=10)
# 5.拟合数据,同时进行交叉验证
decoder.fit(X_train, y_train)
y_pred = decoder.predict(X_test)
accuracy = (y_pred == y_test).mean() * 100.
print("FREM classification accuracy : %g%%" % accuracy)
# 6.构建评估函数,评估上述模型的性能
# 7.权重可视化
from nilearn import plotting
plotting.plot_stat_map(decoder.coef_img_["face"], background_img, title="FREM: accuracy %g%%, 'face coefs'" % accuracy, cut_coords=(-52, -5), display_mode="yz")
plotting.show()

与每个折叠仅拟合一个模型相比,FREM 集成过程在这个简单示例上产生了解码精度的重要改进,并且即使在较重的示例上,聚类机制也保持其计算成本合理。在这里,我们集成了 l2-SVC 的几个实例,但 FREMClassifier 也适用于逻辑。FREMRegressor 对象也可用于解决回归问题。

注意:
1.相比传统skitlearn上的模型,更推荐使用FREM评估器,因为它聚类更加结构化,符合期望
2.这里是不需要mask_roi的,好像也不需要group mask,挺神奇的。值得试试。

第四章 SpaceNet(多个被试静息态)

SpaceNet:decoding with spatial structure for better maps使用空间结构解码以获得更好的地图
SpaceNet实施空间惩罚,以提高大脑解码能力以及解码器映射,结果是稀疏(即回归系数在任何地方都为零,预测体素除外)和结构化(斑点)的脑图,在产生更多可解释的地图和改进的预测分数方面的优越性现在已经得到很好的证实。
2013-2015文献
有两种:nilearn.decoding.SpaceNetRegressor 和 nilearn.decoding.SpaceNetClassifier

######### 以回归为例 ###########
# 1.准备数据
n_subjects = 200
# 2.数据预处理
# 3.分成训练集和测试集
# 4.设置评估器 SpaceNet !!!!!!!!!!!!!!!
from nilearn.decoding import SpaceNetRegressor
decoder = SpaceNetRegressor(memory="nilearn_cache", penalty="graph-net", screening_percentile=5., memory_level=2)
# 5.拟合数据,同时进行交叉验证
decoder.fit(X_train, y_train)
mse = np.mean(np.abs(age_test - y_pred))
print('Mean square error (MSE) on the predicted age: %.2f' % mse)
# 6.构建评估函数,评估上述模型的性能
# 7.权重可视化
####### weights map
plot_stat_map(coef_img, background_img, title="graph-net weights", display_mode="z", cut_coords=1)

第五章 Searchlight

Searchlight :finding voxels containing information 探照灯
searchlight原理:在大脑体积上扫描给定半径的球,并测量在相应体素上训练的分类器的预测精度。
2006-2013文献
探照灯我就跳过了,感觉多了几个步骤,比如mask切片啥的,需要知道切片索引,但是这种方法呈现的结果,我只能说一般般,所以后续需要的时候再学习把,目前看我觉得我用到的地方不多。
总结:就是规定一个框框,在这个框框里计算哪些体素预测性最强。前面的anova-SVM其实和searchlight很相似,前者是全脑的前5%去预测,所以散布在全;后者是划定的框框去预测,所以比较集中,总之比anova-SVM会好一点,前提是你得define这个框框的位置。

第六组 结合skitlearn的高级分析

1.要使用 scikit-learn 估计器执行交叉验证,您应该首先使用nilearn.input_data.NiftiMasker:屏蔽数据以仅提取感兴趣的掩码内的体素,并将 4D 输入fMRI 数据转换为二维数组(形状 (n_timepoints, n_voxels))估计员可以工作。
2.Anova - SVM是一个很好的基线,可以在常见设置中给出合理的结果。然而,探索scikit-learn 中各种各样的监督学习算法可能会很有趣 。这些可以很容易地替换您管道中的SVM,并且可能更适合某些用例。
3. sklearn.model_selection.GridSearchCV网格搜索

以上,这些都还算稍微简单的,偏入门后一点点的。

相关文章

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。