最近在学习Nilearn包的使用,现将学习笔记和思考发布在这里,供大家参考。
以下训练的数据均来自于官网的练习数据 haxby2001的数据

一、导入核磁数据

这个没啥特别的,指定图像地址就好了,唯一要注意的是,需要是4D的nii.gz文件格式,这个可以通过其他软件转换。

#导入数据就是命名nii.gz的数据地址
file_name = r'D:\jupyter\nilearn\haxby2001\subj2\bold.nii.gz'

可选教程:如何查看图像

#查看数据的方法,用 plotting.view_img函数
from nilearn import plotting
plotting.view_img(file_name)

二、定义一个mask

这个定义的mask,就是ROI。
需要注意的是:是不是一定需要mask?
答案是:不是必须,但是建议。

定义mask的好处在于,能容易出结果,范围小了,也更适合讲故事了。
如果不要mask,那就是全脑的体素进行分析,那矩阵量就太大了,但是也可以分析,这是另一种方法,后面会介绍。这里先介绍简单的。

mask_filename = r'D:\jupyter\nilearn\haxby2001\subj2\mask4_vt.nii.gz'

可选教程:如何查看ROI

#如何查看ROI
anatomical_image = r'D:\jupyter\nilearn\haxby2001\subj2\anat.nii.gz'
# cmap:The colormap to use
plotting.plot_roi(mask_filename, bg_img=anatomical_image, cmap='Paired')

mask_filename的图像:
plotting.view_img(mask_filename)

anatomical_image的图像:
plotting.view_img(anatomical_image)

补充:
1、这个anatomical image图像,其实就是T1像,就是患者的结构像
2、plot_roi函数的用法:plot_roi(roi_img, bg_img=, cut_coords=None, output_file=None, display_mode=‘ortho’, figure=None, axes=None, title=None, annotate=True, draw_cross=True, black_bg=‘auto’, threshold=0.5, alpha=0.7, cmap=<matplotlib.colors.LinearSegmentedColormap object at 0x000002144F1BD490>, dim=‘auto’, vmin=None, vmax=None, resampling_interpolation=‘nearest’, view_type=‘continuous’, linewidths=2.5, **kwargs)

3、加载标签 Label

把标签存储在 CSV 文件中,以空格分隔,然后使用 Pandas 将它们加载到数组中。

import pandas as pd
# Load behavioral information
target = r'D:\jupyter\nilearn\haxby2001\subj2\labels.txt'
behavioral = pd.read_csv(target, delimiter=' ')
print(behavioral)


labels.txt文件:

conditions = behavioral['labels']

输出的conditions是panda的序列:pandas.core.series.Series,一共有1452个数字,刚好对应bold.nii.gz的1452个时间点。
这里我需要跟新手提一嘴,一般常规的功能像分析,是要去除前10个时间点的,所以使用自己的数据的时候,就需要和去除后的时间点对应上。

4、将分析限制为猫和人脸

上面的labels里面包含了很多conditions。因此,数据相当大。并非所有这些数据都对我们感兴趣进行解码,因此我们将仅保留与人脸或猫对应的fmri信号。我们创建属于条件的样本的掩码;然后将此掩码应用于fmri数据,以将分类限制为面部与猫的区分。

condition_mask = conditions.isin(['face', 'cat'])

pandas库Series的函数的isin函数(A的元素是否在B当中),输出True和False.
由于数据在一张大的4D图像中,我们需要使用index_img来轻松进行拆分。

from nilearn.image import index_img
fmri_niimgs = index_img(fmri_filename, condition_mask)

label_mask输出的是True和False,需要得到具体的label

conditions = conditions[condition_mask] #conditions剩下216行
# Convert to numpy array
conditions = conditions.values #把conditions的值提取出来,就是216个face或cat的字符串,numpy.ndarray格式

5、定义评估器

前面我们得到了目标label,得到了label对应的激活时间点,也得到了局部的ROI体素。首先,有一个很基础知识需要知道,就是在bold信号里,大脑某个体素值增高,就代表该区域被激活,反之就是抑制。
因此,事实上,以上这么多步骤,其目的就是:把某区域的体素的灰度值增高与降低同标签label进行建模预测。如果能预测成功,那这块区域激活或者抑制就与这类标签具有很强的关系,也就达到了我们的目的。
上面是废话,下面开始继续:
1.定义评估器:

from nilearn.decoding import Decoder
decoder = Decoder(estimator='svc', mask=mask_filename, standardize=True)

standardize=True , 对每个体素上的时间序列数据做0-1归一化。
2.拟合数据

decoder.fit(fmri_niimgs, conditions)

3.检测预测

prediction = decoder.predict(fmri_niimgs)
print(prediction)


当然,这种流程的预测是没有意义的,原因是没有划分测试集和验证集,相当于提高告诉答案,然后再考试,准确率当然是1了。

6、使用交叉验证测量预测分数

让我们忽略训练期间的最后 30 个数据点,并测试对这最后 30 个点的预测:

fmri_niimgs_train = index_img(fmri_niimgs, slice(0, -30))
fmri_niimgs_test = index_img(fmri_niimgs, slice(-30, None))
conditions_train = conditions[:-30]
conditions_test = conditions[-30:]
decoder = Decoder(estimator='svc', mask=mask_filename, standardize=True)
decoder.fit(fmri_niimgs_train, conditions_train)
prediction = decoder.predict(fmri_niimgs_test)
# The prediction accuracy is calculated on the test data: this is the accuracy
# of our model on examples it hasn't seen to examine how well the model perform
# in general.
print("Prediction Accuracy: {:.3f}".format((prediction == conditions_test).sum() / float(len(conditions_test))))


0.767的准确率看起来还不错,接下来需要进行手动的K折交叉验证,然后输出AUC曲线下面积来正确评估这个ROI mask来预测行为的准确率。

from sklearn.model_selection import KFold
cv = KFold(n_splits=5)
# The "cv" object's split method can now accept data and create a
# generator which can yield the splits.
fold = 0
for train, test in cv.split(conditions):fold += 1decoder = Decoder(estimator='svc', mask=mask_filename, standardize=True)decoder.fit(index_img(fmri_niimgs, train), conditions[train])prediction = decoder.predict(index_img(fmri_niimgs, test))print("CV Fold {:01d} | Prediction Accuracy: {:.3f}".format(fold,(prediction == conditions[test]).sum() / float(len(conditions[test]))))


AUC曲线下面积的代码日后补充进来。

6.2 与解码器的交叉验证

这一节还是说交叉验证的事儿,上一节是手动进行K折交叉验证,这里是用评估器默认的功能来实现交叉验证。
解码器还默认实现交叉验证循环并返回一个形状数组(交叉验证参数,n_folds),其中将准确度定义为 评分参数来使用准确度分数来衡量其性能。

n_folds = 5
decoder = Decoder(estimator='svc', mask=mask_filename,standardize=True, cv=n_folds,scoring='accuracy'
)
decoder.fit(fmri_niimgs, conditions)

以上是根据时间点来计算的,事实上,静息态功能磁共振在设计上,经常会有block设计,block就是组块的意思,通俗来讲,就是静息-任务-静息-任务-静息。。。这样的实验。
那么来说,对于这种组块设计的实验,其实应该加上组块的信息进行多个事件组的分析,也就是group(在这里应该是block)分析,其结果会更好点。
详细解释:
试想一下,把bold.nii.gz里面单个时间点当成1个人,那么就有216个人,我们去预测哪些人是cat,哪些人是face。
在传统临床上,一般是把216个人使用随机抽样的方法,变成训练集和验证集(有人会提到应该分3个集合,但是216的数据量还达不到那个程度),然后在训练集上使用K折交叉验证,最后用验证集去验证。
但是在核磁里,时间点是连续的,我们没办法确定具体这个时间点,这个患者的大脑状态就对应着cat或者face,时间分辨率就不是核磁的长处,所以这里就产生了误差。
所以更好的方法是,因为时间点是连续的,静息-任务-静息的block是设计好的,那么研究组间差异,会比研究单个时间点更有价值。即这里的216个人是按号码排好的,face和cat是固定出现的,那么我们去用单个block去机器学习,然后统计单个block的预测准确率,这种方法会更适用于核磁。所以这里的交叉验证方法也就相应的使用留一法,即留下一个block。但是要记住,对单个时间点进行留一法是非常错误的。
官网数据的block重复出现了12次,每次出现的时候face和cat包含了9个时间点。如果是自己的数据的话,block重复的次数肯定要2和更高,不然就会报错。
block留一法:

session_label = behavioral['chunks'][condition_mask]
from sklearn.model_selection import LeaveOneGroupOut
cv = LeaveOneGroupOut()
decoder = Decoder(estimator='svc', mask=mask_filename, standardize=True, cv=cv)
decoder.fit(fmri_niimgs, conditions, groups=session_label)
print(decoder.cv_scores_)


可以看出,在第八次的block中,预测有点问题,其他block都非常棒。
下面是12个block中,cat和face的分布:

暂时没看出第八次block有啥特别的地方,不负责盲猜可能和头动有一定关系。

8、检查模型权重,并转换成nii图像

coef_ = decoder.coef_
print(coef_)

这是一个 numpy 数组,每个体素只有一个系数,所以就是[1, 464]的shape。

coef_img = decoder.coef_img_['face']
decoder.coef_img_['face'].to_filename('haxby_svc_weights.nii.gz')

保存带有权重的nii图像

plotting.view_img(decoder.coef_img_['face'], bg_img=anatomical_image,title="SVM weights", dim=-1
)


使用虚拟分类器(dummy_classification)来作为底线(假设基线)检验上面的SVC分类器性能。

dummy_decoder = Decoder(estimator='dummy_classifier', mask=mask_filename, cv=cv)
dummy_decoder.fit(fmri_niimgs, conditions, groups=session_label)
# Now, we can compare these scores by simply taking a mean over folds
print(dummy_decoder.cv_scores_)


可以看出,虚拟分类器的预测率很低,这就是随便使用一个分类器能达到的底线预测率,而SVC确实提高了很多。
关于虚拟分类器(dummy_classification)的解释:
虚拟分类器为您提供了一种“基准”性能测量 - 即,即使只是猜测,也应该达到预期的成功率。
假设您想确定某个给定的对象是拥有还是不具有某种属性。如果您已经分析了大量这些对象并且发现90%包含目标属性,那么猜测该对象的每个未来实例都拥有目标属性,这使您有90%的正确猜测的可能性。以这种方式构建您的猜测等同于您在引用的文档中使用most_frequent方法。由于许多机器学习任务试图增加(例如)分类任务的成功率,所以评估基线成功率可以为分类器应该超出的最小值提供底限值。在上面讨论的假设中,您会希望分类器的准确率达到90%以上,因为即使是“虚拟”分类器,成功率也可达到90%。
如果使用上面讨论的数据训练带有stratified参数的虚拟分类器,则该分类器将预测其遇到的每个对象都有90%的概率拥有目标属性。这与训练具有most_frequent参数的虚拟分类器不同,因为后者会猜测未来对象具有目标属性。

理解以上,简单的Nilearn就算入门了,后续会继续更新我的学习笔记。我认为,这个方法还是很不错的,简单不复杂,而且契合现在机器学习的热潮,具有应用潜力,比如在我的领域,我准备用这个方法找分类针刺刺激的真假穴的脑区。

我学习完这个初步教程,我还有两个问题:
1、对于机器学习方法来说,使用原始未经处理的数据还是使用转换后的数据,对于结果预测率来说没有区别,重要的是,输入的变量有没有包含决定性变量。那么,在核磁领域,是经过slice timing、head motion、realign、segmentation等等步骤后的数据用来预测好点,还是原始数据好点?
个人见解:其实没太大区别,未处理的数据和处理后的数据,只要他们都是nii.gz格式的图像,那就能用上述方法分析,然后看那种分析准确率更高。
2、需不需要做slice timing,把时间点基线统一?
个人见解:这个等我通过学习了更高阶的nilearn方法,阅读了他们团队的文章后,再回答这个问题。
3、对于非block设计,如病人干预前后,那么1个病人有2个核磁状态,假如有100个病人,对于这种实验,该怎么使用nilearn去分类不同干预措施呢?
个人见解:等我后续学完更高阶的nilearn,学习完后,我再来更新这个问题。
提供一个思路:对于严格遵循随机对照方法的随机对照试验,因为其基线是差异很小的,如果这个时候,基线的差异小到可以忽略,那么就可以把干预后的结果作为label,然后抽样就在100个病人里随机抽,这样就回到了传统的机器学习方法。值得一试。

Over.
clancy wu

核磁的机器学习——Nilearn包的教程相关推荐

  1. 小象python培训班_小象最新Python机器学习升级版视频学习教程 共24节精品课

    小象最新Python机器学习升级版视频学习教程 共24节精品课 本课程特点是从数学层面推导最经典的机器学习算法,以及每种算法的示例和代码实现(Python).如何做算法的参数调试.以实际应用案例分析各 ...

  2. Python表情包处理教程:如何过滤和替换emoji表情?

    Python表情包处理教程:如何过滤和替换emoji表情? Python是一种高级编程语言,它也是一个非常流行的用于数据分析.机器学习和自然语言处理的工具.在这些领域中使用文字和符号非常重要,但是有时 ...

  3. R语言机器学习Caret包(Caret包是分类和回归训练的简称)、数据划分、数据预处理、模型构建、模型调优、模型评估、多模型对比、模型预测推理

    R语言机器学习Caret包(Caret包是分类和回归训练的简称).数据划分.数据预处理.模型构建.模型调优.模型评估.多模型对比.模型预测推理 目录

  4. 我的世界java材质包转基岩_Minecraft我的世界基岩版材质包导入教程

    Minecraft我的世界基岩版材质包导入教程!大家好这里是千羽,今天为大家带来Minecraft基岩版材质包的导入方法,包括Win10版以及安卓版的材质包导入教程视频,不知道材质包怎么导入的同学可参 ...

  5. 手机数据抓包入门教程

    手机数据抓包入门教程 试读地址:http://pan.baidu.com/s/1hqf9N9a 介绍:本教程从专业的角度讲解手机抓包的各种方式,同时也对常见的UDP.TCP通信模式详细讲解.最后针对H ...

  6. java poi jar maven_导出maven项目依赖的jar包(图文教程)

    注意使用mvn命令是需要配置好maven的环境变量 一.导出到自定义目录中 在maven项目下创建lib文件夹,输入以下命令: mvn dependency:copy-dependencies -Do ...

  7. Fiddler抓包使用教程-扫盲篇

    Fiddler抓包使用教程-扫盲篇 转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/72823370 本文出自[赵彦军的博客] 1.什 ...

  8. 是什么包_包粽子教程,喜欢的收藏,以后想吃什么样的都可以自己包

    包粽子,就是这2步难,学会了这个技巧,轻松包出好吃的糯米粽子,大家好我是傻姐,今天端午习俗是吃粽子和鸡蛋,小时候每到端午节,小孩子都会在书包里带几个鸡蛋,到学校里,吃之前先和小伙伴碰鸡蛋,谁的蛋壳先碎 ...

  9. php框架使用教程,php框架laravel excel包使用教程介绍

    Laravel是一套简洁.优雅的PHP Web开发框架(PHP Web Framework).它可以让你从面条一样杂乱的代码中解脱出来:它可以帮你构建一个完美的网络APP了,下面我们来看看larave ...

最新文章

  1. 谢文睿:西瓜书 + 南瓜书 吃瓜系列 9. 集成学习(上)
  2. Beautiful Subarrays (01字典树 瞎搞)
  3. 2010年终总结---戏说茅台酒涨价
  4. 算法------四数相加 II (java 版本)
  5. SQLIOSim 模拟SQLServer的行为来测试IO性能
  6. 线程:synchronized
  7. getResources()方法
  8. 易语言写c盘配置文件,易语言写配置文件的方法
  9. 关于F5的一些基础话题
  10. 使用FragmentTabHost出现的错误!
  11. git bash linux 命令,Git Bash的妙用 - 使用Linux命令
  12. linux下mongodb 安装,linux下mongodb安装
  13. linux tensorflow demo_独家 | 在浏览器中使用TensorFlow.js和Python构建机器学习模型(附代码)...
  14. windows server2012在已有.net4.5框架的基础上安装.net3.5的方法
  15. python中3个while循环_Python3 里怎么让一个包含 while 循环的异步函数不断运行,而不阻塞正常的代码流程...
  16. iis php 知乎,设置 | WeCenter创建你的知乎
  17. 基于阿里云生活物联网平台的智能家居(物联网,智能家居,STM32,阿里云生活物联网平台,人脸识别,语音识别,语音交互)
  18. java graphics2d旋转_JAVA用Graphics2D实现图片旋转,缩放,合成
  19. 从软件保护到软件授权
  20. 我的世界服务器删除启动文件夹,服务器删MOD之后就启动不了了

热门文章

  1. C语言入门:快递费用计算
  2. php四舍五入法, 进一取整法,舍去取整法
  3. windows下安装pytorch报错InvalidArchiveError(‘Error with archive D:\\anaconda\\pkgs\\pytorch-1.2.0
  4. IviewUI form校验number类型有值却提示无效问题
  5. Godot Engine:马里奥食人花三部曲(三)用SkeletonIK实现食人花捕食目标
  6. 在SNAP中用sentinel-1数据制作DEM
  7. S2-057,S2-059,s2-061,s2-062漏洞复现
  8. 想了解工业大数据,不得不看的一篇
  9. 燕山大学工控软件复习资料
  10. R720 ESXi6.5 raid5磁盘阵列扩容