A predictive corticospinal model for pain perception.
The 9 matches · 2 of them tie a paragraph to a whole file, not to given lines: weak matches, whose lines are not tinted
- [1] § STAR★Methods › Method details › Model development ↔ 01_model_training.ipynb, lines 66–187 · score 0.86 · Lasso alpha, square error, LASSO PCR, model training, RMSE, R2
- [2] § STAR★Methods › Method details › Resting-state fMRI and clinical tracking ↔ utils/AlFF_calc.sh, the whole file · a weak match · score 0.81 · power spectrum, frequency bands, fALFF, 0.13 Hz, amplitude, sum
- [3] § STAR★Methods › Method details › Hidden Markov modeling of dynamic states › HMM specification and training ↔ src/hmmlearn/hmm.py, lines 422–531 · score 0.75 · diagonal covariance matrix, GaussianHMM, log likelihood, seed, transition, hmmlearn
- [4] § Development of the corticospinal pain intensity pattern › Comparisons between CsPIP and other models ↔ 01_model_training.ipynb, lines 66–187 · score 0.71 · LASSO PCR, Random Forest, external validation, kernel, SVR, regression
- [5] § STAR★Methods › Method details › Experimental design ↔ 02_model_specificity.ipynb, lines 68–202 · score 0.68 · low itch, High itch, high pain, low pain, compresses, modality
- [6] § STAR★Methods › Method details › Model development ↔ 01_model_training.ipynb, lines 294–412 · score 0.68 · Random Forest, epsilon, RBF, depth, RF, kernel
- [7] § Development of the corticospinal pain intensity pattern › External validation ↔ 02_model_specificity.ipynb, lines 68–202 · score 0.65 · low itch, high itch, high pain, low pain, modalities, intensities
- [8] § Development of the corticospinal pain intensity pattern › Spectral power of spontaneous activity within CsPIP serves as a state-dependent marker of pain relief ↔ utils/AlFF_calc.sh, the whole file · a weak match · score 0.64 · fALFF, low frequency fluctuations, 0.13 Hz, amplitude, temporally, power
- [9] § Development of the corticospinal pain intensity pattern › External validation ↔ 01_model_training.ipynb, lines 425–504 · score 0.63 · pain sensitivity, external validation, high pain, low pain, predict, model
Paper
Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC
The paper is loaded when this pane is shown.
The authors' code
Jupyter notebook · 707 lines · 28 KB · MIT · 4 matches
- # %%
- import os
- import numpy as np
- from scipy.stats import pearsonr
- from sklearn.model_selection import GroupKFold, cross_val_predict
- from sklearn.decomposition import PCA
- from sklearn.linear_model import Lasso
- from sklearn.preprocessing import StandardScaler
- from sklearn.metrics import mean_squared_error, r2_score
- from sklearn.pipeline import Pipeline
- # %% [markdown]
- # # CsPIP training
- # %%
- # loading data
- datadir = '0data'
- train_y = np.load(os.path.join(datadir,'d1_train_y.npy'))
- test_y = np.load(os.path.join(datadir,'d1_test_y.npy'))
- train_pred = np.load(os.path.join(datadir,'d1_train_pred.npy'))
- test_pred = np.load(os.path.join(datadir,'d1_test_pred.npy'))
- train_set = np.load(os.path.join(datadir,'d1_train_set.npy'))
- test_set = np.load(os.path.join(datadir,'d1_test_set.npy'))
- train_groups = np.load(os.path.join(datadir,'d1_train_group.npy'))
- qh_lp_copes = np.load(os.path.join(datadir,'d2_qh_lp_set.npy'))
- qh_hp_copes = np.load(os.path.join(datadir,'d2_qh_hp_set.npy'))
- # qh_lp_pred = np.load(os.path.join(datadir,'d2_qh_lp_pred.npy'))
- # qh_hp_pred = np.load(os.path.join(datadir,'d2_qh_hp_pred.npy'))
- qh_lp_y = np.load(os.path.join(datadir,'d2_qh_lp_y.npy'))
- qh_hp_y = np.load(os.path.join(datadir,'d2_qh_hp_y.npy'))
- # %%
- lassopcr = Pipeline(steps=[
- ('scaler', StandardScaler()),
- ('pca', PCA()),
- ('lasso', Lasso())])
- # Set up the cross_valdation
- cv = GroupKFold(n_splits=10)
- # 并行得到逐样本的交叉验证预测
- y_pred = cross_val_predict(
- lassopcr, # 你的 Pipeline
- X=train_set,
- y=train_y,
- groups=train_groups,
- cv=cv,
- n_jobs=-1, # -1 = 用完所有 CPU 核
- method="predict" # 调用 predict
- )
- # 计算总体指标
- r = pearsonr(train_y, y_pred)[0]
- rmse = np.sqrt(mean_squared_error(train_y, y_pred))
- r2 = r2_score(train_y, y_pred)
- print(r, rmse, r2)
- lassopcr.fit(train_set, train_y)
- print(pearsonr(test_y, lassopcr.predict(test_set)))
- print('-'*20)
- print(pearsonr(qh_lp_y,lassopcr.predict(qh_lp_copes)))
- print(pearsonr(qh_hp_y,lassopcr.predict(qh_hp_copes)))
- # %% [markdown]
- # # nolinear
- # %%
- import numpy as np
- import os
- import pandas as pd
- from sklearn.preprocessing import StandardScaler
- from sklearn.decomposition import PCA
- from sklearn.linear_model import Lasso
- from sklearn.ensemble import RandomForestRegressor
- from sklearn.svm import SVR
- from sklearn.pipeline import Pipeline
- from sklearn.model_selection import GridSearchCV, GroupKFold
- from sklearn.metrics import mean_squared_error, r2_score
- from scipy.stats import pearsonr
- # # --- 1. Loading Data (保持你原有的代码) ---
- # --- 2. 定义评估函数 (Helper Function) ---
- def evaluate_model(model, X, y, dataset_name="Set"):
- preds = model.predict(X)
- r = pearsonr(y, preds)[0]
- # 如果只是为了看结果,可以只打印 r,也可以加上 RMSE
- print(f" [{dataset_name}] Pearson r: {r:.3f}")
- return r, preds
- # --- 3. 设置交叉验证策略 ---
- # 这一点非常重要:确保 GridSearch 内部也遵守 Group 约束
- cv = GroupKFold(n_splits=10)
- # --- 4. 定义模型和参数网格 ---
- # 我们把不同的模型放在一个字典里,方便循环处理
- model_configs = {
- # 'LassoPCR': {
- # 'pipeline': Pipeline([
- # ('scaler', StandardScaler()),
- # ('pca', PCA()),
- # ('regressor', Lasso(max_iter=10000)) # 增加 iter 防止收敛警告
- # ]),
- # 'param_grid': {
- # # 优化 PCA 维度 (可选,视特征数量而定)
- # 'pca__n_components': [0.8, 0.9, 0.95],
- # # 优化 Lasso 的 Alpha (审稿人要求的重点)
- # 'regressor__alpha': np.logspace(-4, 1, 20)
- # }
- # },
- 'SVR (RBF)': {
- 'pipeline': Pipeline([
- ('scaler', StandardScaler()),
- ('pca', PCA(n_components=0.95)), # SVR 在高维下较慢,通常建议先降维
- ('regressor', SVR(kernel='rbf'))
- ]),
- 'param_grid': {
- 'regressor__C': [0.1, 1, 10, 100],
- 'regressor__epsilon': [0.01, 0.1, 0.5]
- }
- },
- 'Random Forest': {
- 'pipeline': Pipeline([
- ('scaler', StandardScaler()), # RF 不需要归一化,但加上也不影响
- # RF 通常不需要 PCA,因为它可以处理高维特征
- ('regressor', RandomForestRegressor(random_state=42, n_jobs=-1))
- ]),
- 'param_grid': {
- 'regressor__n_estimators': [100, 200],
- 'regressor__max_depth': [None, 10, 20],
- 'regressor__min_samples_split': [2, 5]
- }
- }
- }
- # --- 5. 主循环:训练与评估 ---
- results = {}
- print(f"{'='*20} Start Model Training {'='*20}")
- preds = {}
- for name, config in model_configs.items():
- print(f"\n>>> Training Model: {name}...")
- # 配置 GridSearchCV
- grid = GridSearchCV(
- estimator=config['pipeline'],
- param_grid=config['param_grid'],
- cv=cv,
- scoring='neg_mean_squared_error', # 或者 'r2'
- n_jobs=-1,
- verbose=1
- )
- # 训练 (注意需要传入 groups 参数)
- grid.fit(train_set, train_y, groups=train_groups)
- # 获取最佳模型
- best_model = grid.best_estimator_
- print(f" Best Params: {grid.best_params_}")
- # --- 内部交叉验证性能 (Best CV Score) ---
- # 这是模型在训练集交叉验证中的平均表现
- print(f" Best CV Score (Neg MSE): {grid.best_score_:.3f}")
- # --- 外部测试集评估 ---
- print(" --- Performance on Hold-out Sets ---")
- # 1. Test Set
- r_test, preds['Test Set'] = evaluate_model(best_model, test_set, test_y, "Test Set")
- # 2. External Validation (QH LP)
- r_lp, preds['QH LP'] = evaluate_model(best_model, qh_lp_copes, qh_lp_y, "QH LP")
- # 3. External Validation (QH HP)
- r_hp, preds['QH HP'] = evaluate_model(best_model, qh_hp_copes, qh_hp_y, "QH HP")
- # 存储结果
- results[name] = {
- 'best_params': grid.best_params_,
- 'r_test': r_test,
- 'r_qh_lp': r_lp,
- 'r_qh_hp': r_hp
- }
- np.savez(f"sup_data/{name.replace(' ', '_')}_predictions.npz", **preds)
- print(f"\n{'='*20} Summary {'='*20}")
- for name, res in results.items():
- print(f"{name}: Test r={res['r_test']:.3f}, QH_LP r={res['r_qh_lp']:.3f}, QH_HP r={res['r_qh_hp']:.3f}")
- # %%
- def plot_regression_with_annotations(x, y, title, xlabel, ylabel, color='#7985B3',save_path=None):
- """
- Plots a regression plot with custom annotations.
- Parameters:
- - x: array-like, the observed values
- - y: array-like, the predicted values
- - title: str, the title of the plot
- - xlabel: str, the label for the x-axis
- - ylabel: str, the label for the y-axis
- - color: str, the color for the points and regression line
- """
- import matplotlib.pyplot as plt
- import seaborn as sns
- from sklearn.metrics import mean_absolute_error
- from scipy.stats import pearsonr
- from matplotlib.ticker import MaxNLocator
- plt.figure(figsize=(7, 6))
- ax = sns.regplot(x=x, y=y, scatter_kws={'alpha':0.4,'color':color}, line_kws={'color':color})
- # Customizing the plot with titles and labels
- ax.set_title(title,fontsize=20,fontweight='bold')
- ax.set_xlabel(xlabel,fontsize=16,fontweight='bold')
- ax.set_ylabel(ylabel,fontsize=16,fontweight='bold')
- # Removing top and right spines
- ax.spines['top'].set_visible(False)
- ax.spines['right'].set_visible(False)
- # Calculate correlation coefficient and p-value
- r, p = pearsonr(x, y)
- # Annotate the plot with the correlation coefficient and p-value
- ax.text(0.05, 0.95, f'r = {r:.2f}', transform=ax.transAxes, fontsize=16, fontweight='bold')
- ax.text(0.05, 0.90, f'p = {p:.3f}', transform=ax.transAxes, fontsize=16, fontweight='bold')
- # Calculate and display mean absolute error
- mae = mean_absolute_error(x, y)
- m, b = np.polyfit(x, y, 1)
- # Customize the number of ticks on x and y axes
- ax.xaxis.set_major_locator(MaxNLocator(3))
- ax.yaxis.set_major_locator(MaxNLocator(3))
- if save_path:
- plt.savefig(save_path, dpi=300, bbox_inches='tight')
- # Show the plot
- plt.show()
- # %%
- svr_pred = np.load('sup_data/SVR_(RBF)_predictions.npz', allow_pickle=True)
- rf_pred = np.load('sup_data/Random_Forest_predictions.npz', allow_pickle=True)
- # %%
- plot_regression_with_annotations(svr_pred['Test Set'],test_y,
- title='SVR Model Predictions (Hold-out Set)',
- ylabel='Actual Values',
- xlabel='Predicted Values',
- color='#7985B3',
- save_path='/mnt/lxm2/2025/03_Tens/manuscript_FINAL/figs/SVR_Holdout_Predictions.tif'
- )
- plot_regression_with_annotations(y = qh_lp_y,x = svr_pred['QH LP'],
- title='SVR Model Predictions (Study 2 Low Pain)',
- ylabel='Actual Values',
- xlabel='Predicted Values',
- color='#7985B3',
- save_path='/mnt/lxm2/2025/03_Tens/manuscript_FINAL/figs/SVR_QH_LP_Predictions.tif'
- )
- plot_regression_with_annotations(y = qh_hp_y,x = svr_pred['QH HP'],
- title='SVR Model Predictions (Study 2 High Pain)',
- ylabel='Actual Values',
- xlabel='Predicted Values',
- color='#7985B3',
- save_path='/mnt/lxm2/2025/03_Tens/manuscript_FINAL/figs/SVR_QH_HP_Predictions.tif'
- )
- # %%
- plot_regression_with_annotations(y = test_y,x = rf_pred['Test Set'],
- title='Random Forest Model Predictions (Hold-out Set)',
- ylabel='Actual Values',
- xlabel='Predicted Values',
- color='#FF6F61',
- save_path='/mnt/lxm2/2025/03_Tens/manuscript_FINAL/figs/RF_Holdout_Predictions.tif'
- )
- plot_regression_with_annotations(y = qh_lp_y,x = rf_pred['QH LP'],
- title='Random Forest Model Predictions (Study 2 Low Pain)',
- ylabel='Actual Values',
- xlabel='Predicted Values',
- color='#FF6F61',
- save_path='/mnt/lxm2/2025/03_Tens/manuscript_FINAL/figs/RF_QH_LP_Predictions.tif'
- )
- plot_regression_with_annotations(y = qh_hp_y,x = rf_pred['QH HP'],
- title='Random Forest Model Predictions (Study 2 High Pain)',
- ylabel='Actual Values',
- xlabel='Predicted Values',
- color='#FF6F61',
- save_path='/mnt/lxm2/2025/03_Tens/manuscript_FINAL/figs/RF_QH_HP_Predictions.tif'
- )
- # %%
- # %%
- import numpy as np
- import os
- import pandas as pd
- from sklearn.preprocessing import StandardScaler
- from sklearn.decomposition import PCA
- from sklearn.linear_model import Lasso
- from sklearn.ensemble import RandomForestRegressor
- from sklearn.svm import SVR
- from sklearn.pipeline import Pipeline
- from sklearn.model_selection import GridSearchCV, GroupKFold
- from sklearn.metrics import mean_squared_error, r2_score
- from scipy.stats import pearsonr
- # # --- 1. Loading Data (保持你原有的代码) ---
- # --- 2. 定义评估函数 (Helper Function) ---
- def evaluate_model(model, X, y, dataset_name="Set"):
- preds = model.predict(X)
- r = pearsonr(y, preds)[0]
- # 如果只是为了看结果,可以只打印 r,也可以加上 RMSE
- print(f" [{dataset_name}] Pearson r: {r:.3f}")
- return r, preds
- # --- 3. 设置交叉验证策略 ---
- # 这一点非常重要:确保 GridSearch 内部也遵守 Group 约束
- cv = GroupKFold(n_splits=10)
- # --- 4. 定义模型和参数网格 ---
- # 我们把不同的模型放在一个字典里,方便循环处理
- model_configs = {
- 'LassoPCR': {
- 'pipeline': Pipeline([
- ('scaler', StandardScaler()),
- ('pca', PCA()),
- ('regressor', Lasso(max_iter=10000)) # 增加 iter 防止收敛警告
- ]),
- 'param_grid': {
- # 优化 PCA 维度 (可选,视特征数量而定)
- 'pca__n_components': [0.8, 0.9, 0.95],
- # 优化 Lasso 的 Alpha (审稿人要求的重点)
- 'regressor__alpha': np.logspace(-4, 1, 20)
- }
- },
- # 'SVR (RBF)': {
- # 'pipeline': Pipeline([
- # ('scaler', StandardScaler()),
- # ('pca', PCA(n_components=0.95)), # SVR 在高维下较慢,通常建议先降维
- # ('regressor', SVR(kernel='rbf'))
- # ]),
- # 'param_grid': {
- # 'regressor__C': [0.1, 1, 10, 100],
- # 'regressor__epsilon': [0.01, 0.1, 0.5]
- # }
- # },
- # 'Random Forest': {
- # 'pipeline': Pipeline([
- # ('scaler', StandardScaler()), # RF 不需要归一化,但加上也不影响
- # # RF 通常不需要 PCA,因为它可以处理高维特征
- # ('regressor', RandomForestRegressor(random_state=42, n_jobs=-1))
- # ]),
- # 'param_grid': {
- # 'regressor__n_estimators': [100, 200],
- # 'regressor__max_depth': [None, 10, 20],
- # 'regressor__min_samples_split': [2, 5]
- # }
- # }
- }
- # --- 5. 主循环:训练与评估 ---
- results = {}
- print(f"{'='*20} Start Model Training {'='*20}")
- for name, config in model_configs.items():
- print(f"\n>>> Training Model: {name}...")
- # 配置 GridSearchCV
- grid = GridSearchCV(
- estimator=config['pipeline'],
- param_grid=config['param_grid'],
- cv=cv,
- scoring='neg_mean_squared_error', # 或者 'r2'
- n_jobs=-1,
- verbose=1
- )
- # 训练 (注意需要传入 groups 参数)
- grid.fit(train_set, train_y, groups=train_groups)
- # 获取最佳模型
- best_model = grid.best_estimator_
- print(f" Best Params: {grid.best_params_}")
- # --- 内部交叉验证性能 (Best CV Score) ---
- # 这是模型在训练集交叉验证中的平均表现
- print(f" Best CV Score (Neg MSE): {grid.best_score_:.3f}")
- # --- 外部测试集评估 ---
- print(" --- Performance on Hold-out Sets ---")
- # 1. Test Set
- r_test, preds_test = evaluate_model(best_model, test_set, test_y, "Test Set")
- # 2. External Validation (QH LP)
- r_lp, preds_lp = evaluate_model(best_model, qh_lp_copes, qh_lp_y, "QH LP")
- # 3. External Validation (QH HP)
- r_hp, preds_hp = evaluate_model(best_model, qh_hp_copes, qh_hp_y, "QH HP")
- # 存储结果
- results[name] = {
- 'best_params': grid.best_params_,
- 'r_test': r_test,
- 'r_qh_lp': r_lp,
- 'r_qh_hp': r_hp
- }
- print(f"\n{'='*20} Summary {'='*20}")
- for name, res in results.items():
- print(f"{name}: Test r={res['r_test']:.3f}, QH_LP r={res['r_qh_lp']:.3f}, QH_HP r={res['r_qh_hp']:.3f}")
- # %%
- # 1. Test Set
- r_test, preds_test = evaluate_model(best_model, test_set, test_y, "Test Set")
- # 2. External Validation (QH LP)
- r_lp, preds_lp = evaluate_model(best_model, qh_lp_copes, qh_lp_y, "QH LP")
- # 3. External Validation (QH HP)
- r_hp, preds_hp = evaluate_model(best_model, qh_hp_copes, qh_hp_y, "QH HP")
- # %%
- # 1. Test Set
- r_test, preds_test = evaluate_model(best_model, test_set, test_y, "Test Set")
- # 2. External Validation (QH LP)
- r_lp, preds_lp = evaluate_model(best_model, qh_lp_copes, qh_lp_y, "QH LP")
- # 3. External Validation (QH HP)
- r_hp, preds_hp = evaluate_model(best_model, qh_hp_copes, qh_hp_y, "QH HP")
- import matplotlib.pyplot as plt
- import seaborn as sns
- from matplotlib.ticker import MaxNLocator
- from scipy.stats import pearsonr
- from matplotlib.colors import LinearSegmentedColormap
- def plot_d2d3(t1,t2,x1,y1,x2,y2,save=False):
- # 读取txt文件,通常是3列数据 (R, G, B)
- roma_data = np.loadtxt('/mnt/lxm/tools/romaO/romaO.txt')
- # 创建 Matplotlib 可用的 colormap 对象
- roma_cmap = LinearSegmentedColormap.from_list('romaO', roma_data)
- # 设置字体族为衬线体 (serif)
- plt.rcParams['font.family'] = 'serif'
- # 指定衬线体具体为 Times New Roman
- plt.rcParams['font.serif'] = ['Times New Roman']
- # 确保数学公式也尽量接近 Times 风格 (可选)
- plt.rcParams['mathtext.fontset'] = 'stix'
- # 设置字号 (可选,根据需要调整)
- plt.rcParams['font.size'] = 12
- # 设置 Seaborn 风格,但保留我们的字体设置
- sns.set_theme(style="ticks", rc={"font.family": "serif", "font.serif": ["Times New Roman"]})
- # 设置字体族为 Times New Roman
- plt.rcParams['font.family'] = 'serif'
- plt.rcParams['font.serif'] = ['Times New Roman']
- sns.set_context("notebook", rc={"font.family": "Times New Roman"})
- # 设置 Seaborn 风格,但保留我们的字体设置
- sns.set_theme(style="ticks", rc={"font.family": "serif", "font.serif": ["Times New Roman"]})
- color1=roma_cmap(0.15)
- color2=roma_cmap(0.95)
- # color3=roma_cmap(0.5)
- color3='black'
- # 创建图表
- plt.figure(figsize=(7, 6))
- ax = plt.gca() # 获取当前坐标轴
- # 为每个数据集绘制回归散点图
- sns.regplot(x=t1, y=t2, scatter_kws={'alpha':0.6, 'color':color3}, line_kws={'color':color3}, ax=ax, label='Hold-out Set')
- # sns.regplot(x=x1, y=y1, scatter_kws={'alpha':0.6, 'color':color1}, line_kws={'color':color1}, ax=ax, label='Low Pain')
- # sns.regplot(x=x2, y=y2, scatter_kws={'alpha':0.6, 'color':color2}, line_kws={'color':color2}, ax=ax, label='High Pain')
- # 自定义图表标题和轴标签
- ax.set_xlabel('Observed pain sensitivity',fontsize=16, fontweight='bold')
- ax.set_ylabel('Predicted pain sensitivity',fontsize=16, fontweight='bold')
- ax.spines['top'].set_visible(False)
- ax.spines['right'].set_visible(False)
- # 计算每个数据集的相关系数
- r1,p1=pearsonr(x1,y1)
- r2,p2=pearsonr(x2,y2)
- rt,p_t=pearsonr(t1,t2)
- # 添加相关系数的注释
- ax.text(0.05, 0.95, f'Hold-out Set: r = {rt:.2f}, p = {p_t:.3f}', transform=ax.transAxes, color=color3)
- # ax.text(0.05, 0.90, f'Study 2 - low pain: r = {r1:.2f}, p = {p1:.3f}', transform=ax.transAxes, color=color1)
- # ax.text(0.05, 0.85, f'Study 2 - high pain: r = {r2:.2f}, p = {p2:.3f}', transform=ax.transAxes, color=color2)
- ax.xaxis.set_major_locator(MaxNLocator(3)) # 在x轴上最多显示5个刻度
- ax.yaxis.set_major_locator(MaxNLocator(3)) # 在y轴上最多显示4个刻度
- # plt.ylim(0,13)
- # 显示图例
- plt.legend(loc='lower right',frameon=True, fontsize=13) # 或 ax.legend(loc='lower right')
- # 显示图表
- # if save:
- # # save
- # fileDir = '/mnt/lxm2/2025/03_Tens/manuscript_FINAL/figs/'
- # fileName = 'd2_corr.tif'
- # plt.gcf().savefig(fileDir+fileName, dpi=300, bbox_inches='tight', pad_inches=0.04,
- # pil_kwargs={'compression':'tiff_lzw'})
- plt.show()
- plot_d2d3(preds_test,test_y,preds_lp,qh_lp_y,preds_hp,qh_hp_y,save=True)
- # %% [markdown]
- # # bootstrap
- # %%
- nbootstraps = 10000
- nstop = 200 # frequency to stop/save bootstraps
- njobs = -1
- brain_v = len_brain
- spial_v = len_spinal
- from joblib import Parallel, delayed
- from scipy.stats import norm
- from tqdm import tqdm
- from os.path import join as opj
- outpath = '/mnt/lxm2/2025/03_Tens/lassopcr_res_0503_2a/boots_new'
- name = 'lassopcr'
- os.makedirs(opj(outpath, 'permsamples'), exist_ok=True)
- os.makedirs(opj(outpath, 'bootsamples'), exist_ok=True)
- def bootstrap_weights(X, Y,rs):
- # Randomly select observations
- rng = np.random.RandomState(rs)
- boot_ids = rng.choice(np.arange(len(X)),
- size=len(X),
- replace=True)
- try:
- # Fit the classifier on this sample and get the weights
- lassopcr.fit(X[boot_ids], Y[boot_ids])
- # Return the weights and stats
- return np.dot(lassopcr['pca'].components_.T, lassopcr['lasso'].coef_)
- except:
- print("SVD failed on a bootstrap sample. Skipping...")
- return rs # 返回 None 而不是零向量
- # Run in parrallel and stop/save regurarly to run in multiple
- for i in tqdm(range(nbootstraps//nstop)):
- # Check if file alrady exist in case bootstrap done x times
- outbootfile = ['bootsamples_' + str(nstop) + 'samples_'
- + str(i+1) + '_of_'
- + str(nbootstraps//nstop) + '.npy']
- print("Running permloop " + str(i + 1) + ' out of ' + str(nbootstraps//nstop))
- if not os.path.exists(opj(outpath, 'bootsamples', outbootfile[0])):
- bootstrapped = Parallel(n_jobs=40,
- verbose=0)(delayed(bootstrap_weights)(X=train_set, Y=train_y,rs=i*200+ii)
- for ii in range(nstop))
- try:
- bootstrapped = np.stack(bootstrapped)
- except:
- for ind, vv in enumerate(bootstrapped):
- if isinstance(vv, int): # Check if vv is of type int
- # Replace vv with the result of bootstrap_weights
- bootstrapped[ind] = bootstrap_weights(all_copes, all_y, vv)
- bootstrapped = np.stack(bootstrapped)
- np.save(opj(outpath, 'bootsamples', outbootfile[0]), bootstrapped)
- # %%
- mask_img = nb.load('/mnt/lxm2/2025/03_Tens/3group_level/all_lr+.gfeat/all_lr_mask_thr31_bin.nii.gz')
- spinal_mask = nb.load('/mnt/lxm2/2025/03_Tens/LASSOPCR/group_mask_gm.nii.gz')
- # Load all boostraps
- bootstrapped = np.vstack(np.stack([np.load(opj(outpath, 'bootsamples', f))
- for f in os.listdir(opj(outpath, 'bootsamples'))
- if 'bootsamples' in f], axis=0))
- assert bootstrapped.shape[0] == nbootstraps
- # Get bootstraped statistics and threshold (as in nltools)
- # Zscore
- boot_z = bootstrapped.mean(axis=0)/bootstrapped.std(axis=0)
- # boot_z[bootstrapped.mean(axis=0) == 0] = 0
- unmask(boot_z[:brain_v], mask_img).to_filename(opj(outpath, 'brain_'+name + '_bootz.nii'))
- unmask(boot_z[brain_v:], spinal_mask).to_filename(opj(outpath, 'spinal_'+name + '_bootz.nii'))
- # P vals
- boot_pval = 2 * (1 - norm.cdf(np.abs(boot_z)))
- unmask(boot_pval[:brain_v], mask_img).to_filename(opj(outpath, 'brain_'+name + '_boot_pvals.nii'))
- unmask(boot_pval[brain_v:], spinal_mask).to_filename(opj(outpath, 'spinal_'+name + '_boot_pvals.nii'))
- def fdr(p, q=0.05):
- s = np.sort(p)
- nvox = p.shape[0]
- null = np.array(range(1, nvox + 1), dtype="float") * q / nvox
- below = np.where(s <= null)[0]
- return s[max(below)] if len(below) else -1 # p_fdr
- # FDR orrected z
- boot_z_fdr = np.where(boot_pval < fdr(boot_pval, q=0.05), boot_z, 0)
- boot_z_unc001 = np.where(boot_pval < 0.001, boot_z, 0)
- boot_z_unc005 = np.where(boot_pval < 0.005, boot_z, 0)
- boot_z_unc01 = np.where(boot_pval < 0.01, boot_z, 0)
- unmask(boot_z_fdr[:brain_v], mask_img).to_filename(opj(outpath,
- 'brain'+ name + '_bootz_fdr05.nii'))
- unmask(boot_z_unc001[:brain_v], mask_img).to_filename(opj(outpath,
- 'brain'+ name + '_bootz_unc001.nii'))
- unmask(boot_z_unc005[:brain_v], mask_img).to_filename(opj(outpath,
- 'brain'+ name + '_bootz_unc005.nii'))
- unmask(boot_z_unc01[:brain_v], mask_img).to_filename(opj(outpath,
- 'brain'+ name + '_bootz_unc01.nii'))
- unmask(boot_z_fdr[brain_v:], spinal_mask).to_filename(opj(outpath,
- 'spianl'+ name + '_bootz_fdr05.nii'))
- unmask(boot_z_unc001[brain_v:], spinal_mask).to_filename(opj(outpath,
- 'spianl'+ name + '_bootz_unc001.nii'))
- unmask(boot_z_unc005[brain_v:], spinal_mask).to_filename(opj(outpath,
- 'spianl'+ name + '_bootz_unc005.nii'))
- unmask(boot_z_unc01[brain_v:], spinal_mask).to_filename(opj(outpath,
- 'spianl'+ name + '_bootz_unc01.nii'))
- # %%
- boot_z_fdr_brain = np.where(boot_pval[:brain_v] < fdr(boot_pval[:brain_v], q=0.05), boot_z[:brain_v], 0)
- unmask(boot_z_fdr_brain, mask_img).to_filename(opj(outpath, 'only_brain_'+name + '_bootz_fdr05.nii'))
- boot_z_fdr_spinal = np.where(boot_pval[brain_v:] < fdr(boot_pval[brain_v:], q=0.05), boot_z[brain_v:], 0)
- unmask(boot_z_fdr_spinal, spinal_mask).to_filename(opj(outpath, 'only_spinal_'+name + '_bootz_fdr05.nii'))
- # %% [markdown]
- # # Orignial Pipeline
- # %%
- # all_sub = open('/home/lxm/2_lxm/2025/03_Tens/scripts/all.list').read().splitlines()
- # r_list = [x for x in all_sub if '_r' in x]
- # l_list = [x for x in all_sub if '_l' in x]
- # y_all_r = np.array([np.loadtxt(f'/mnt/lxm2/2025/03_Tens/0data/time_pr/{sub}_pre_pr.txt').mean() for sub in r_list])
- # y_all_l = np.array([np.loadtxt(f'/mnt/lxm2/2025/03_Tens/0data/time_pr/{sub}_pre_pr.txt').mean() for sub in l_list])
- # import numpy as np
- # import nibabel as nb
- # from nilearn.image import binarize_img,threshold_img
- # from joblib import Parallel, delayed
- # brain_mask_img = nb.load('/mnt/lxm2/2025/03_Tens/3group_level/all_lr+.gfeat/all_lr_mask_thr31_bin.nii.gz')
- # spinal_mask_img = nb.load('/home/lxm/2_lxm/2025/03_Tens/LASSOPCR/group_mask_gm.nii.gz')
- # brain_mask = brain_mask_img.get_fdata().astype(bool).ravel() # (n_vox_brain,)
- # spinal_mask = spinal_mask_img.get_fdata().astype(bool).ravel() # (n_vox_spinal,)
- # # 把两张掩膜长度记录下来,后面拼接用
- # len_brain, len_spinal = brain_mask.sum(), spinal_mask.sum()
- # def load_subject(sub_id, prefix):
- # """
- # 读一个受试者的脑 + 脊髓 COPE,返回 (len_brain + len_spinal,) 的 1-D 特征向量
- # """
- # # 路径
- # brain_p = f'{prefix}/brain/{sub_id}.feat/reg_standard/stats/cope1.nii.gz'
- # spinal_p = f'{prefix}/spinal/{sub_id}.feat/stats/cope1_template.nii.gz'
- # brain_data = nb.load(brain_p).get_fdata().ravel()[brain_mask] # (len_brain,)
- # spinal_data = nb.load(spinal_p).get_fdata().ravel()[spinal_mask] # (len_spinal,)
- # return np.concatenate((brain_data, spinal_data), axis=0)
- # # ── 2. 并行读取 ─────────────────────────────────────────────
- # prefix = '/mnt/lxm2/2025/03_Tens/2fst_level'
- # # 左右两组
- # all_data = Parallel(n_jobs=-1, backend='loky', verbose=5)(
- # delayed(load_subject)(sub, prefix) for sub in l_list
- # )
- # test_data = Parallel(n_jobs=-1, backend='loky', verbose=5)(
- # delayed(load_subject)(sub, prefix) for sub in r_list
- # )
- # all_data = np.vstack(all_data) # shape = (n_L, len_brain + len_spinal)
- # test_data = np.vstack(test_data) # shape = (n_R, len_brain + len_spinal)
- # # ── 3. 组装后续矩阵 / 标签 / 分组 ───────────────────────────
- # # all_copes = np.vstack((all_data, test_data))
- # all_copes = np.vstack((all_data, test_data))
- # all_y = np.hstack((y_all_l, y_all_r))
- # groups = np.tile(np.arange(len(y_all_l)), 2)
- # from sklearn.model_selection import GroupShuffleSplit
- # group_split = GroupShuffleSplit(n_splits=2, test_size=0.33, random_state=42)
- # # 拆分数据集,确保同一组数据不会同时出现在训练集和测试集中
- # for train_index, test_index in group_split.split(all_copes, groups=groups):
- # train_set = all_copes[train_index]
- # train_y = all_y[train_index]
- # test_set = all_copes[test_index]
- # test_y = all_y[test_index]
- # train_groups = groups[train_index]
- # test_groups = groups[test_index]
- # train_id = [r_list[x] for x in train_groups]
- # test_id = [r_list[x] for x in test_groups]
- # outdir = '/home/lxm/2_lxm/2025/03_Tens/manuscript_FINAL/0data'
- # if not os.path.exists(outdir):
- # os.makedirs(outdir)
- # np.save(os.path.join(outdir,'d1_train_set.npy'),train_set)
- # np.save(os.path.join(outdir,'d1_test_set.npy'),test_set)
- # np.save(os.path.join(outdir,'d1_train_y.npy'),train_y)
- # np.save(os.path.join(outdir,'d1_train_pred.npy'),y_pred)
- # np.save(os.path.join(outdir,'d1_test_y.npy'),test_y)
- # np.save(os.path.join(outdir,'d1_test_pred.npy'),lassopcr.predict(test_set))
- # np.save(os.path.join(outdir,'d2_qh_lp_pred.npy'),lassopcr.predict(qh_lp_copes))
- # np.save(os.path.join(outdir,'d2_qh_hp_pred.npy'),lassopcr.predict(qh_hp_copes))
- # np.save(os.path.join(outdir,'d2_qh_hp_y.npy'),real_hp)
- # np.save(os.path.join(outdir,'d2_qh_lp_y.npy'),real_lp)
- # np.save(os.path.join(outdir,'d1_train_group.npy'),train_groups)
- # np.save(os.path.join(outdir,'d1_test_group.npy'),test_groups)
- # np.save(os.path.join(outdir,'d2_qh_lp_pred.npy'), qh_lp_copes)
- # np.save(os.path.join(outdir,'d2_qh_hp_pred.npy'), qh_hp_copes)
01_model_training.ipynb at commit 660ab60, under MIT · at the source
Overview
- State Key Laboratory of Cognitive Science and Mental Health, Institute of Psychology, Chinese Academy of Sciences, Beijing 100101, China
- Department of Psychology, University of Chinese Academy of Sciences, Beijing 100049, China
- International Acupuncture and Moxibustion Innovation Institute, School of Acupuncture-Moxibustion and Tuina, Beijing University of Chinese Medicine, Beijing 100029, China
- Department of Psychological and Brain Sciences, Dartmouth College, Hanover, NH 03755, USA
- Wellcome Centre for Integrative Neuroimaging, FMRIB, Nuffield Department of Clinical Neurosciences, University of Oxford, Oxford OX3 9DU, UK
- Center for Brain Imaging, School of Life Science and Technology, Xidian University, Xi’an 710126, China
Abstract
The abstract is not reproduced here: the paper's license (CC BY-NC-ND) does not allow it. Read it in the paper, at the publisher or on Europe PMC.
Repositories
Its files are read in the Code ↔ Paper reader above, with 9 matches between paragraphs and lines of code.
buer19970329/corticospinal-pain-intensity-pattern
660ab60aa75bfc2c7f21a7bbc1aaa2f7e9a784b6, 29 May 2026Availability: 1 check, the latest on 27 September 2026: the link answers
- 27 September 2026: the link answers
5 files
- 01_model_training.ipynb, Jupyter, 707 lines, 4 matches
- 02_model_specificity.ipy
nb , Jupyter, 664 lines, 2 matches - 03_model_tens.ipynb, Jupyter, 539 lines
- utils/
AlFF_calc.sh , Shell, 87 lines, 2 matches - README.md, Text, 76 lines
hmmlearn/hmmlearn
e01a10e99df1042e4c1e6b7c822fd292dd37502f, 31 October 2024Availability: 1 check, the latest on 27 September 2026: the link answers
- 27 September 2026: the link answers
35 files
- doc/
source/ , Python, 52 linesconf.py - examples/
plot_casino.py , Python, 145 lines - examples/
plot_gaussian_model_sele , Python, 78 linesction.py - examples/
plot_hmm_sampling_and_de , Python, 117 linescoding.py - examples/
plot_multinomial_hmm.py , Python, 129 lines - examples/
plot_poisson_hmm.py , Python, 111 lines - examples/
plot_variational_inferen , Python, 185 linesce.py - ext/
_hmmc.cpp , C++, 334 lines - scripts/
benchmark.py , Python, 298 lines - setup.py, Python, 9 lines
- src/
hmmlearn/ , Python, 15 lines__init__.py - src/
hmmlearn/ , Python, 410 lines_emissions.py - src/
hmmlearn/ , Python, 117 lines_kl_divergence.py - src/
hmmlearn/ , Python, 84 lines_utils.py - src/
hmmlearn/ , Python, 1,271 linesbase.py - src/
hmmlearn/ , Python, 1,075 lines, 1 matchhmm.py - src/
hmmlearn/ , Python, 98 linesstats.py - src/
hmmlearn/ , Python, 96 linestests/ __init__.py - src/
hmmlearn/ , Python, 12 linestests/ conftest.py - src/
hmmlearn/ , Python, 245 linestests/ test_base.py - src/
hmmlearn/ , Python, 167 linestests/ test_categorical_hmm.py - src/
hmmlearn/ , Python, 366 linestests/ test_gaussian_hmm.py - src/
hmmlearn/ , Python, 111 linestests/ test_gmm_hmm.py - src/
hmmlearn/ , Python, 286 linestests/ test_gmm_hmm_multisequen ce.py - src/
hmmlearn/ , Python, 265 linestests/ test_gmm_hmm_new.py - src/
hmmlearn/ , Python, 55 linestests/ test_kl_divergence.py - src/
hmmlearn/ , Python, 181 linestests/ test_multinomial_hmm.py - src/
hmmlearn/ , Python, 101 linestests/ test_poisson_hmm.py - src/
hmmlearn/ , Python, 45 linestests/ test_utils.py - src/
hmmlearn/ , Python, 255 linestests/ test_variational_categor ical.py - src/
hmmlearn/ , Python, 507 linestests/ test_variational_gaussia n.py - src/
hmmlearn/ , Python, 71 linesutils.py - src/
hmmlearn/ , Python, 844 linesvhmm.py - LICENSE.txt, License, 27 lines
- README.rst, Text, 61 lines
The paper's code and data availability statement is in the Data section.
Tracing map
Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.
What the map holds:
- 2 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
- 37 scripts, each with its path and the digest of its content;
- 9 matches between paragraphs of the paper and lines of the code (method lexical-v1);
- neither the text of the paper nor the code itself.
Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.
Data
No dataset and no data link were found in the paper.
Code and data availability statement
The paper has a code and data availability statement. Its license (CC BY-NC-ND) does not allow reproducing it here; in short, from what the harvester recognized in it:
- it points to the authors' code: buer19970329/
corticospinal-pain-inten sity-pattern - it says that the data are available on request
- it says that the code is available on request
Read it in the paper: doi.org/10.1016/j.xcrm.2026.102793.
Versions
The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.
Version 1, 27 September 2026: the first record
Recorded: type, language, journal, volume, issue, pages, dates, 10 authors, 5 keywords, 9 MeSH terms, 5 funders, 50 references.
Cite
This paper
Lin, X.-M., Zhang, X.-S., Zhou, H., Han, X.-Y., Wei, Z.-X., Wager, T. D., Tracey, I., Liu, J.-X., Liu, C.-Z., & Kong, Y.-Z. (2026). A predictive corticospinal model for pain perception. Cell reports. Medicine, 7(7), 102793. https://
BibTeX
@article{lin2026predicti
author = {Lin, Xiao-Min and Zhang, Xiao-Shuo and Zhou, Hang and Han, Xiu-Yi and Wei, Zhao-Xing and Wager, Tor D and Tracey, Irene and Liu, Ji-Xin and Liu, Cun-Zhi and Kong, Ya-Zhuo},
title = {{A predictive corticospinal model for pain perception}},
journal = {Cell reports. Medicine},
year = {2026},
month = jun,
volume = {7},
number = {7},
pages = {102793},
publisher = {Elsevier},
issn = {2666-3791},
doi = {10.1016/
url = {https://
pmid = {42309066},
pmcid = {PMC13400141}
}
RIS
TY - JOUR
AU - Lin, Xiao-Min
AU - Zhang, Xiao-Shuo
AU - Zhou, Hang
AU - Han, Xiu-Yi
AU - Wei, Zhao-Xing
AU - Wager, Tor D
AU - Tracey, Irene
AU - Liu, Ji-Xin
AU - Liu, Cun-Zhi
AU - Kong, Ya-Zhuo
TI - A predictive corticospinal model for pain perception
T2 - Cell reports. Medicine
J2 - Cell Rep Med
PY - 2026
DA - 2026/
VL - 7
IS - 7
SP - 102793
SN - 2666-3791
PB - Elsevier
DO - 10.1016/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.1016/
"type": "article-journal",
"title": "A predictive corticospinal model for pain perception",
"container-title": "Cell reports. Medicine",
"author": [
{
"family": "Lin",
"given": "Xiao-Min"
},
{
"family": "Zhang",
"given": "Xiao-Shuo"
},
{
"family": "Zhou",
"given": "Hang"
},
{
"family": "Han",
"given": "Xiu-Yi"
},
{
"family": "Wei",
"given": "Zhao-Xing"
},
{
"family": "Wager",
"given": "Tor D"
},
{
"family": "Tracey",
"given": "Irene"
},
{
"family": "Liu",
"given": "Ji-Xin"
},
{
"family": "Liu",
"given": "Cun-Zhi"
},
{
"family": "Kong",
"given": "Ya-Zhuo"
}
],
"container-title-short":
"volume": "7",
"issue": "7",
"page": "102793",
"DOI": "10.1016/
"PMID": "42309066",
"PMCID": "PMC13400141",
"ISSN": "2666-3791",
"publisher": "Elsevier",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
6,
18
]
]
}
}
The tracing map gets a citation of its own once an author has validated it and it has a DOI.
Similar papers
The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.
- [1] doi:10.1038/s41467-026-74743-0 [code]
- Meta-analytic evidence for distinct neural correlates of conditioned versus verbally induced placebo analgesia.Journal: Nature communicationsIn common: Pingouin, FSL, Nilearn, 8 other tools, pain, 2 references
- [2] doi:10.1038/s41467-026-71568-9 [code]
- Convergent and selective representations of pain, appetitive processes, aversive processes, and cognitive control in the insula.Journal: Nature communicationsIn common: FSL, Nilearn, NiBabel, 6 other tools, pain, 4 references
- [3] doi:10.1038/s41467-026-71963-2 [code]
- Spinal cord structural and functional architecture and its shared organization with the brain across the adult lifespan.Journal: Nature communicationsIn common: Pingouin, FSL, Nilearn, 8 other tools, 2 references
- [4] doi:10.1038/s41597-026-07377-y [code]
- An open-access multi-site fMRI dataset for investigating conscious visual perception.Journal: Scientific dataIn common: Pingouin, FSL, Nilearn, 8 other tools, fMRI
- [5] doi:10.1038/s41467-026-75662-w [code]
- Distinct Roles of Deep and Superficial Cortical Layers in Tone Prediction, Comparison, and Adaptation in Human Auditory Cortices.Journal: Nature communicationsIn common: Pingouin, FSL, Nilearn, 8 other tools
- [6] doi:10.1038/s41597-026-07350-9 [code]
- An open multi-center MEG-EEG dataset for studying conscious visual perception.Journal: Scientific dataIn common: Pingouin, FSL, Nilearn, 8 other tools
- [7] doi:10.1093/nc/niag029 [code]
- A data-driven approach to identifying and evaluating connectivity-based neural correlates of conscious visual perception.Journal: Neuroscience of consciousnessIn common: Pingouin, FSL, Nilearn, 8 other tools
- [8] doi:10.1038/s41467-026-75661-x [code]
- A neural signature of sleep deprivation in the human brain.Journal: Nature communicationsIn common: Nilearn, NiBabel, statsmodels, 6 other tools, 2 references
- [9] doi:10.1371/journal.pbio.3003856 [code]
- Aging and metabolism contribute separately to brain-body health.Journal: PLoS biologyIn common: FSL, Nilearn, NiBabel, 7 other tools, 1 reference
- [10] doi:10.1162/imag.a.1245 [code]
- Towards precision EEG connectomics: Evaluating the benefits of dense sampling.Journal: Imaging neuroscience (Cambridge, Mass.)In common: Pingouin, FSL, Nilearn, 7 other tools
Contribute
The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.
Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.
Claim this paper
Correct its record
Say what each link of this record is, remove the ones that are not the paper's, add the ones that are missing. The correction becomes a new version of the record, in its Versions section.
Validate its tracing map
You validate the map as this page shows it: 2 repositories of the authors' code, each at its verified commit and with its license, 37 scripts, and 9 matches between paragraphs and code (see the Code and Map sections). It then receives a DOI on Zenodo, with you (your ORCID iD) and OSCR as its creators; the code itself is not deposited.
The map's fingerprint: sha256:e5b9689d9272a2ba…
Add the badge to its README
The badge links the code to this page. Copy one of these into the README of the paper's code: only you decide where it goes, and nothing is changed for you.
Markdown
[, paste the snippet at the top, then “Commit changes…” and, to review it first, “Create a new branch and start a pull request”. You open the pull request; OSCR asks for no permission.
Request its removal
To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).
Discussion, reproductions, activity
Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.
Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.
Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.
