地址:
https://nbviewer.jupyter.org/github/NeuromatchAcademy/course-content/blob/master/projects/load_hcp.ipynb
人类Connectome Project(HCP)数据集
#导入相应的包
import os
import numpy as np
import matplotlib.pyplot as plt
# 可视化需要
!pip install nilearn --quiet
from nilearn import plotting, datasets
#设置风格
#@title Figure settings
%matplotlib inline
%config InlineBackend.figure_format = 'retina'
plt.style.use("https://raw.githubusercontent.com/NeuromatchAcademy/course-content/master/nma.mplstyle")
基本参数
# 数据存储目录
HCP_DIR = "./hcp"
if not os.path.isdir(HCP_DIR):
os.mkdir(HCP_DIR)
# NMA项目共享的数据是HCP数据集的完整子集
N_SUBJECTS = 339
# 数据已经从Glasesr分解汇总到ROI中
N_PARCELS = 360
# 所有任务的采集参数相同
TR = 0.72 # 时间分辨率,以秒为单位
# The parcels 在半球上的匹配顺序相同
HEMIS = ["Right", "Left"]
# 每个实验在每个主题中重复多次
N_RUNS_REST = 4
N_RUNS_TASK = 2
# 时间序列数据是按实验组织的,每个实验
#具有LR和RL(相位编码方向)采集
BOLD_NAMES = [
"rfMRI_REST1_LR", "rfMRI_REST1_RL",
"rfMRI_REST2_LR", "rfMRI_REST2_RL",
"tfMRI_MOTOR_RL", "tfMRI_MOTOR_LR",
"tfMRI_WM_RL", "tfMRI_WM_LR",
"tfMRI_EMOTION_RL", "tfMRI_EMOTION_LR",
"tfMRI_GAMBLING_RL", "tfMRI_GAMBLING_LR",
"tfMRI_LANGUAGE_RL", "tfMRI_LANGUAGE_LR",
"tfMRI_RELATIONAL_RL", "tfMRI_RELATIONAL_LR",
"tfMRI_SOCIAL_RL", "tfMRI_SOCIAL_LR"
]
# 您可能希望代码开发期间限制使用的主题。You may want to limit the subjects used during code development.
# 他将使用所有主题:
subjects = range(N_SUBJECTS)
下载资料
其余数据和任务数据在不同的文件中共享,但是它们将解压缩到相同的目录结构中。
每个文件都很大,需要一些时间来下载。如果仅关注静息或任务分析,则可能不希望仅下载该数据集。
我们还分别提供了一些可能有用的行为协变量信息。
#静息态
fname = "hcp_rest.tgz"
if not os.path.exists(fname):
!wget -qO $fname https://osf.io/bqp7m/download/
!tar -xzf $fname -C $HCP_DIR --strip-components=1
#任务态
fname = "hcp_task.tgz"
if not os.path.exists(fname):
!wget -qO $fname https://osf.io/s4h8j/download/
!tar -xzf $fname -C $HCP_DIR --strip-components=1
#行为协变量
fname = "hcp_covariates.tgz"
if not os.path.exists(fname):
!wget -qO $fname https://osf.io/x5p4g/download/
!tar -xzf $fname -C $HCP_DIR --strip-components=1
#脑区模板
fname = f"{HCP_DIR}/atlas.npz"
if not os.path.exists(fname):
!wget -qO $fname https://osf.io/j5kuc/download
加载区域信息
下载任意一个数据集都会创建region.npy文件,其中包含每个parcel的区域名称和网络分配。
Glasser等人的补编中提供了有关每个区域使用的名称的详细信息。 2016。Ji等人,2019年提供了有关网络分割的信息。
#脑区信息
regions = np.load(f"{HCP_DIR}/regions.npy").T
region_info = dict(
name=regions[0].tolist(),
network=regions[1],
myelin=regions[2].astype(np.float),
)
我们还提供了fsaverage5表面上的分割和每个区域的近似MNI坐标,这对于可视化很有用:
with np.load(f"{HCP_DIR}/atlas.npz") as dobj:
atlas = dict(**dobj)
帮助函数
数据导入
def get_image_ids(name):
"""获取给定实验中基于1的图像索引
Args:
name (str) :要加载的实验名称(“静息”或任务名称)
Returns:
run_ids (list of int) :实验图像文件的ID
"""
run_ids = [
i for i, code in enumerate(BOLD_NAMES, 1) if name.upper() in code
]
if not run_ids:
raise ValueError(f"Found no data for '{name}''")
return run_ids
def load_timeseries(subject, name, runs=None, concat=True, remove_mean=True):
"""加载单个主题的时间序列数据
Args:
subject (int): 从0开始的加载主题ID
name (str) : 要加载的实验名称(“静息”或任务名称)
run (None or int or list of ints):要加载的任务的基于0的运行,或无以加载所有运行
concat (bool) : 如果为True,则连接多个一起运行
remove_mean (bool) : 如果为True,则减去parcal均值
Returns
ts (n_parcel x n_tp array): BOLD数据值的数组
"""
# 获取列表的相对于0的索引
if runs is None:
runs = range(N_RUNS_REST) if name == "rest" else range(N_RUNS_TASK)
elif isinstance(runs, int):
runs = [runs]
# 获取此实验的第一个(从1开始)运行ID
offset = get_image_ids(name)[0]
# 加载每次运行的数据
bold_data = [
load_single_timeseries(subject, offset + run, remove_mean) for run in runs
]
# 选择连接
if concat:
bold_data = np.concatenate(bold_data, axis=-1)
return bold_data
def load_single_timeseries(subject, bold_run, remove_mean=True):
"""加载单个主题和单个运行的时间序列数据
Args:
subject (int): 从0开始的主题ID加载
bold_run (int): 所有任务均基于1的运行索引
remove_mean (bool): 如果为True,则减去parcel均值
Returns
ts (n_parcel x n_timepoint array): BOLD数组
"""
bold_path = f"{HCP_DIR}/subjects/{subject}/timeseries"
bold_file = f"bold{bold_run}_Atlas_MSMAll_Glasser360Cortical.npy"
ts = np.load(f"{bold_path}/{bold_file}")
if remove_mean:
ts -= ts.mean(axis=1, keepdims=True)
return ts
def load_evs(subject, name, condition):
"""加载一个任务条件的EV(解释性变量)数据
Args:
subject (int): 从0开始的主题ID加载
name (str) : 任务名称
condition (str) : 条件名称
Returns
evs (list of dicts): 每次运行的条件具有开始,持续时间和幅度的字典.
"""
evs = []
for id in get_image_ids(name):
task_key = BOLD_NAMES[id - 1]
ev_file = f"{HCP_DIR}/subjects/{subject}/EVs/{task_key}/{condition}.txt"
ev_array = np.loadtxt(ev_file, ndmin=2, unpack=True)
ev = dict(zip(["onset", "duration", "amplitude"], ev_array))
evs.append(ev)
return evs
基于任务的分析
def condition_frames(run_evs, skip=0):
"""确定每次运行中与给定条件相对应的时间点
Args:
run_evs (list of dicts) : 每次运行的事件的开始和持续时间
skip (int) : 在每次试用开始时忽略这么多帧,血流动力学滞后
Returns:
frames_list (list of 1D arrays): 每次运行的帧索引的平面数组
"""
frames_list = []
for ev in run_evs:
# 确定何时开始试用,四舍五入
start = np.floor(ev["onset"] / TR).astype(int)
# 使用试验持续时间来确定试验要包括多少帧
duration = np.ceil(ev["duration"] / TR).astype(int)
# 取与这个特定试验相对应的帧的范围
frames = [s + np.arange(skip, d) for s, d in zip(start, duration)]
frames_list.append(np.concatenate(frames))
return frames_list
def selective_average(timeseries_data, ev, skip=0):
"""取给定条件下帧间的时间平均值
Args:
timeseries_data (array or list of arrays): n_parcel x n_tp arrays
ev (dict or list of dicts): 条件时间信息
skip (int) : 在每次试验开始时忽略这许多帧,以说明血流动力学滞后
Returns:
avg_data (1D array): 基于条件时序在选定图像帧间平均的数据
"""
# 确保我们有相同长度的列表
if not isinstance(timeseries_data, list):
timeseries_data = [timeseries_data]
if not isinstance(ev, list):
ev = [ev]
if len(timeseries_data) != len(ev):
raise ValueError("Length of `timeseries_data` and `ev` must match.")
# 识别相关帧的索引
frames = condition_frames(ev, skip)
# 从每个图像中选择帧
selected_data = []
for run_data, run_frames in zip(timeseries_data, frames):
run_frames = run_frames[run_frames < run_data.shape[1]]
selected_data.append(run_data[:, run_frames])
# 取每个parcel的平均值
avg_data = np.concatenate(selected_data, axis=-1).mean(axis=-1)
return avg_data
静止态分析
加载一次静态态数据:
help(load_timeseries)
#为单个subject加载时间序列数据
timeseries = load_timeseries(subject=0, name="rest", runs=1)
print(timeseries.shape) # n_parcel x n_timepoint
#加载为每个被试的静息态时间序列(使用所有运行数据):
timeseries_rest = []
for subject in subjects:
ts_concat = load_timeseries(subject, "rest")
timeseries_rest.append(ts_concat)
运行简单的基于相关性的“功能连接”分析
为每个受试者生成一个相关矩阵(显示“功能连接性”或功能系数),并绘制组平均值:
fc = np.zeros((N_SUBJECTS, N_PARCELS, N_PARCELS))
for sub, ts in enumerate(timeseries_rest):
fc[sub] = np.corrcoef(ts)
group_fc = fc.mean(axis=0)
plt.imshow(group_fc, interpolation="none", cmap="bwr", vmin=-1, vmax=1)
plt.colorbar()
plt.show()
绘制特定“种子”parcel和数据集中每个parcel之间的FC值分布图,用半球分隔:
seed_roi = "R_FEF" # name of seed parcel
ind = region_info["name"].index(seed_roi)
hemi_fc = np.split(group_fc, 2)
# 绘制右半球和左半球目标区域的功能曲线
for i, hemi_fc in enumerate(hemi_fc):
plt.plot(hemi_fc[:, ind], label=f"{HEMIS[i]} hemisphere")
plt.title(f"FC for region {seed_roi}")
plt.xlabel("Target region")
plt.ylabel("Correlation (FC)")
plt.legend()
plt.show()