OSCR

Machine learning-based identification of abnormal functional connectivity in obesity across different metabolic states.

Code ↔ Paper

5 matches between paragraphs of the paper and lines of its authors' code, computed by the harvester (lexical-v1). Click a colored paragraph or line to see its counterpart.

The 5 matches
  1. [1] § Methods › Feature selection and classification ↔ CodeScript.ipynb, lines 403–515 · score 0.74 · max_depth, n_estimators, feature selection, optimal, iterations, folds
  2. [2] § Methods › Statistics and reproducibility ↔ CodeScript.ipynb, lines 796–825 · score 0.71 · Mann Whitney, Shapiro Wilk, accuracy
  3. [3] § Methods › Feature selection and classification ↔ CodeScript.ipynb, lines 403–515 · score 0.64 · feature selection, consecutive, threshold, iteratively, score, RF
  4. [4] § Methods › Feature selection and classification ↔ CodeScript.ipynb, lines 618–707 · score 0.58 · F1 score, AUC, recall, precision, metric, class
  5. [5] § Results › Machine learning model performance ↔ CodeScript.ipynb, lines 618–707 · score 0.51 · F1 score, AUC, recall, precision, metrics, class

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 · 1,336 lines · 50 KB · CC-BY-4.0 · 5 matches

  1. # %%
  2. import librosa
  3. import os as os
  4. import pandas as pd
  5. import re
  6. import numpy as np
  7. from sklearn.metrics import precision_score, recall_score, accuracy_score
  8. from matplotlib import cm, colors, colorbar
  9. from matplotlib import pyplot as plt
  10. from sklearn.neural_network import MLPClassifier
  11. from sklearn.linear_model import RidgeClassifier
  12. rdg = RidgeClassifier(alpha=0.5)
  13. #mlp=MLPClassifier(random_state=1,max_iter=300,activation='relu',solver='sgd',learning_rate='constant',learning_rate_init=0.0001)
  14. mlp=MLPClassifier(random_state=1,max_iter=300,activation='relu')
  15. from sklearn.linear_model import LogisticRegression
  16. lgr=LogisticRegression(random_state=1,max_iter=500)
  17. from sklearn.tree import DecisionTreeClassifier
  18. DT = DecisionTreeClassifier(random_state=0,max_depth=10)
  19. from sklearn.ensemble import AdaBoostClassifier
  20. adb = AdaBoostClassifier(n_estimators=100, random_state=0)
  21. from sklearn.ensemble import GradientBoostingClassifier
  22. gbc= GradientBoostingClassifier(n_estimators=100, random_state=1)
  23. from sklearn.neighbors import KNeighborsClassifier
  24. knn = KNeighborsClassifier(n_neighbors=3)
  25. from sklearn.linear_model import SGDClassifier
  26. SGD=SGDClassifier(loss= 'log',random_state=1,max_iter=100,early_stopping=True,learning_rate='optimal',validation_fraction=0.2)
  27. from sklearn.preprocessing import StandardScaler
  28. from sklearn.preprocessing import MinMaxScaler
  29. scaler = StandardScaler()
  30. mmscaler= MinMaxScaler()
  31. from sklearn.ensemble import RandomForestClassifier
  32. rf = RandomForestClassifier(n_estimators=75,max_depth=15, random_state=0)
  33. from sklearn.svm import SVC
  34. clf_svm=SVC(kernel='rbf')
  35. from sklearn.cluster import KMeans
  36. from sklearn.decomposition import PCA
  37. pca = PCA(n_components=2)
  38. from scipy.spatial import ConvexHull, convex_hull_plot_2d
  39. from sklearn.cluster import DBSCAN
  40. from sklearn.decomposition import PCA
  41. from scipy.stats.mstats import mquantiles
  42. from scipy.stats import skew
  43. from sklearn.cluster import KMeans
  44. from sklearn.model_selection import LeaveOneOut
  45. pca = PCA(n_components=2, svd_solver='full')
  46. import random
  47. from sklearn.cluster import DBSCAN
  48. from sklearn.model_selection import train_test_split
  49. from sklearn.model_selection import cross_val_score
  50. #import nilearn
  51. #from nilearn import plotting
  52. from matplotlib.pyplot import figure
  53. import seaborn as sns
  54. import statistics
  55. import warnings
  56. warnings.filterwarnings('ignore')
  57. from sklearn.metrics import (recall_score, confusion_matrix, balanced_accuracy_score,
  58. f1_score, precision_score, roc_auc_score,
  59. matthews_corrcoef, average_precision_score)
  60. # %% [markdown]
  61. # ### Read Functional Connectivity Data
  62. # %%
  63. def extract_per_time_Lean(time,directory):
  64. coh={}
  65. shorten_list={}
  66. for time,directory,in zip([time],[directory]):
  67. os.chdir(directory)
  68. coh[time]=os.listdir(directory)
  69. if '.ipynb_checkpoints' in coh[time]:
  70. coh[time].remove('.ipynb_checkpoints')
  71. shorten_list[time]=[]
  72. for i in range(0,len(coh[time])):
  73. if coh[time][i][0]=='L':
  74. shorten_list[time].append(coh[time][i].split(str(time)+'min')[0])
  75. ns=(set(shorten_list[time])
  76. )
  77. ns=list(ns)
  78. ns.sort()
  79. #random.shuffle(ns) ### Shuffle the list
  80. ns_l=[]
  81. ns_ob=[]
  82. for n in ns:
  83. if n[0]=='L':
  84. ns_l.append(n)
  85. else:
  86. ns_ob.append(n)
  87. names_l=[]
  88. for i in ns_l:
  89. name=i+'0min.EDFOUT-ROIlaggedCoh-covar.txt'
  90. names_l.append(name)
  91. #names_l=names_l[0:27]
  92. l_name_ls={}
  93. for t in [time]:
  94. sr=str(t)+'min'
  95. print(sr)
  96. l_name_ls[t]=[]
  97. for n in names_l:
  98. nn=n.replace('0min',sr)
  99. l_name_ls[t].append(nn)
  100. names_list={}
  101. for t in [time]:
  102. names_list[t]=l_name_ls[t]
  103. names_list[t]=names_list[t][0:30]
  104. def extract_connectivity(band,data):
  105. Y=[]
  106. coh_ar=np.zeros([len(data),88*88])
  107. for i in range(0,len(data)):
  108. m=np.loadtxt(data[i])[band*88:(band+1)*88,:] # extract only delta band
  109. m=np.tril(m, k=-1).flatten() ## Take upper/lower Triangle of the Symetrical Coherence Matrix
  110. coh_ar[i,:]=m
  111. #cor_ar=cor_ar[0:60,:]
  112. if (data[i][0])=='L':
  113. Y.append(0)
  114. else:
  115. Y.append(1)
  116. #Y=Y[0:60]
  117. return coh_ar,Y
  118. connectivity={}
  119. for band in [0,1,2,3,4]: # 0-delta, 1-theta, 2-alpha, 3-beta, 4-gamma
  120. #for band in [2]:
  121. #print(band)
  122. connectivity[band]=np.zeros([1,88*88])
  123. Y=[]
  124. for time,directory,in zip([time],[directory]):
  125. os.chdir(directory)
  126. data=names_list[time][0:60]
  127. con=extract_connectivity(band,data)[0]
  128. y=extract_connectivity(band,data)[1]
  129. connectivity[band]=np.vstack([connectivity[band],con])
  130. Y=Y+y
  131. connectivity[band]=connectivity[band][1:,:]
  132. print(connectivity[band].shape)
  133. print(' ')
  134. con_all_bl_lean_x=np.hstack([connectivity[0],connectivity[1],connectivity[2],connectivity[3],connectivity[4]])
  135. #con_alpha_bl_lean_x=connectivity[band]
  136. con_all_bl_lean_y=np.zeros([con_all_bl_lean_x.shape[0]])
  137. return con_all_bl_lean_x,con_all_bl_lean_y
  138. # %%
  139. def extract_per_time_Ob(time,directory):
  140. coh={}
  141. shorten_list={}
  142. for time,directory,in zip([time],[directory]):
  143. os.chdir(directory)
  144. coh[time]=os.listdir(directory)
  145. if '.ipynb_checkpoints' in coh[time]:
  146. coh[time].remove('.ipynb_checkpoints')
  147. shorten_list[time]=[]
  148. for i in range(0,len(coh[time])):
  149. shorten_list[time].append(coh[time][i].split(str(time)+'min')[0])
  150. # find those files that belong to the subjects that are not missing in any timestates
  151. ns=(set(shorten_list[time])
  152. )
  153. ns=list(ns)
  154. ns.sort()
  155. #random.shuffle(ns) ### Shuffle the list
  156. ns_l=[]
  157. ns_ob=[]
  158. for n in ns:
  159. if n[0]=='L':
  160. ns_l.append(n)
  161. else:
  162. ns_ob.append(n)
  163. names_ob=[]
  164. for r in ns_ob:
  165. name=r+'0min-ROIlaggedCoh-covar.txt'
  166. names_ob.append(name)
  167. ob_name_ls={}
  168. for t in [time]:
  169. sr=str(t)+'min'
  170. print(sr)
  171. ob_name_ls[t]=[]
  172. for n in names_ob:
  173. nn=n.replace('0min',sr)
  174. ob_name_ls[t].append(nn)
  175. names_list={}
  176. for t in [time]:
  177. names_list[t]=ob_name_ls[t]
  178. names_list[t]=names_list[t][0:30]
  179. def extract_connectivity(band,data):
  180. Y=[]
  181. coh_ar=np.zeros([len(data),88*88])
  182. for i in range(0,len(data)):
  183. m=np.loadtxt(data[i])[band*88:(band+1)*88,:] # extract only delta band
  184. m=np.tril(m, k=-1).flatten() ## Take upper/lower Triangle of the Symetrical Coherence Matrix
  185. coh_ar[i,:]=m
  186. #cor_ar=cor_ar[0:60,:]
  187. if (data[i][0])=='L':
  188. Y.append(0)
  189. else:
  190. Y.append(1)
  191. #Y=Y[0:60]
  192. return coh_ar,Y
  193. connectivity={}
  194. for band in [0,1,2,3,4]: # 0-delta, 1-theta, 2-alpha, 3-beta, 4-gamma
  195. #for band in [2]:
  196. #print(band)
  197. connectivity[band]=np.zeros([1,88*88])
  198. Y=[]
  199. for time,directory,in zip([time], [directory]):
  200. os.chdir(directory)
  201. data=names_list[time][0:60]
  202. con=extract_connectivity(band,data)[0]
  203. y=extract_connectivity(band,data)[1]
  204. connectivity[band]=np.vstack([connectivity[band],con])
  205. Y=Y+y
  206. connectivity[band]=connectivity[band][1:,:]
  207. #print(connectivity[band].shape)
  208. #print(' ')
  209. con_all_pwl_ob_x=np.hstack([connectivity[0],connectivity[1],connectivity[2],connectivity[3],connectivity[4]])
  210. con_all_pwl_ob_y=np.ones([con_all_pwl_ob_x.shape[0]])
  211. print(con_all_pwl_ob_x.shape,con_all_pwl_ob_y.shape)
  212. return con_all_pwl_ob_x,con_all_pwl_ob_y
  213. # %%
  214. Xdata={}
  215. Ydata={}
  216. for time in [0,15,30,45,60,90,120,180,240]:
  217. xarray=[]
  218. yarray=[]
  219. for directory in [f"/datasets/Demo_MOCKED_data/3MON/T{time}" ,
  220. f"/datasets/Demo_MOCKED_data/PostWL/T{time}"
  221. ]:
  222. #for directory in [f"/datasets/MOCKED_data/3MON/T{time}" ,
  223. #
  224. # f"/datasets/MOCKED_data/PostWL/T{time}"
  225. # ]:
  226. xarray.append(extract_per_time_Ob(time,directory)[0])
  227. yarray.append(extract_per_time_Ob(time,directory)[1])
  228. xarray=np.concatenate(xarray, axis=0)
  229. yarray=np.concatenate(yarray, axis=0)
  230. Xdata[time]=xarray
  231. Ydata[time]=yarray
  232. # %%
  233. for time in [0,15,30,45,60,90,120,180,240]:
  234. print(Xdata[time].shape, Ydata[time].shape)
  235. # %%
  236. def extract_per_time_Ob_BL(time,directory):
  237. coh={}
  238. shorten_list={}
  239. for time,directory,in zip([time],[directory]):
  240. os.chdir(directory)
  241. coh[time]=os.listdir(directory)
  242. if '.ipynb_checkpoints' in coh[time]:
  243. coh[time].remove('.ipynb_checkpoints')
  244. shorten_list[time]=[]
  245. for i in range(0,len(coh[time])):
  246. shorten_list[time].append(coh[time][i].split(str(time)+'min')[0])
  247. # find those files that belong to the subjects that are not missing in any timestates
  248. ns=(set(shorten_list[time])
  249. )
  250. ns=list(ns)
  251. ns.sort()
  252. #random.shuffle(ns) ### Shuffle the list
  253. ns_l=[]
  254. ns_ob=[]
  255. for n in ns:
  256. if n[0]=='L':
  257. ns_l.append(n)
  258. else:
  259. ns_ob.append(n)
  260. names_ob=[]
  261. for r in ns_ob:
  262. name=r+'0min.EDFOUT-ROIlaggedCoh-covar.txt'
  263. names_ob.append(name)
  264. ob_name_ls={}
  265. for t in [time]:
  266. sr=str(t)+'min'
  267. print(sr)
  268. ob_name_ls[t]=[]
  269. for n in names_ob:
  270. nn=n.replace('0min',sr)
  271. ob_name_ls[t].append(nn)
  272. names_list={}
  273. for t in [time]:
  274. names_list[t]=ob_name_ls[t]
  275. names_list[t]=names_list[t][0:30]
  276. def extract_connectivity(band,data):
  277. Y=[]
  278. coh_ar=np.zeros([len(data),88*88])
  279. for i in range(0,len(data)):
  280. m=np.loadtxt(data[i])[band*88:(band+1)*88,:] # extract only delta band
  281. m=np.tril(m, k=-1).flatten() ## Take upper/lower Triangle of the Symetrical Coherence Matrix
  282. coh_ar[i,:]=m
  283. #cor_ar=cor_ar[0:60,:]
  284. if (data[i][0])=='L':
  285. Y.append(0)
  286. else:
  287. Y.append(1)
  288. #Y=Y[0:60]
  289. return coh_ar,Y
  290. connectivity={}
  291. for band in [0,1,2,3,4]: # 0-delta, 1-theta, 2-alpha, 3-beta, 4-gamma
  292. #for band in [2]:
  293. #print(band)
  294. connectivity[band]=np.zeros([1,88*88])
  295. Y=[]
  296. for time,directory,in zip([time], [directory]):
  297. os.chdir(directory)
  298. data=names_list[time][0:60]
  299. con=extract_connectivity(band,data)[0]
  300. y=extract_connectivity(band,data)[1]
  301. connectivity[band]=np.vstack([connectivity[band],con])
  302. Y=Y+y
  303. connectivity[band]=connectivity[band][1:,:]
  304. #print(connectivity[band].shape)
  305. #print(' ')
  306. con_all_pwl_ob_x=np.hstack([connectivity[0],connectivity[1],connectivity[2],connectivity[3],connectivity[4]])
  307. con_all_pwl_ob_y=np.ones([con_all_pwl_ob_x.shape[0]])
  308. print(con_all_pwl_ob_x.shape,con_all_pwl_ob_y.shape)
  309. return con_all_pwl_ob_x,con_all_pwl_ob_y
  310. # %%
  311. Xdata_={}
  312. Ydata_={}
  313. for time in [0,15,30,45,60,90,120,180,240]:
  314. xarray=[]
  315. yarray=[]
  316. for directory in [f"/datasets/Demo_MOCKED_data/BL/T{time}"]:
  317. #for directory in [f"/datasets/MOCKED_data/BL/T{time}"]:
  318. xarray.append(extract_per_time_Ob_BL(time,directory)[0])
  319. yarray.append(extract_per_time_Ob_BL(time,directory)[1])
  320. xarray=np.concatenate(xarray, axis=0)
  321. yarray=np.concatenate(yarray, axis=0)
  322. Xdata_[time]=xarray
  323. Ydata_[time]=yarray
  324. # %%
  325. Xdata_ob={}
  326. Ydata_ob={}
  327. for time in [0,15,30,45,60,90,120,180,240]:
  328. Xdata_ob[time]=np.vstack([Xdata_[time],Xdata[time]])
  329. Ydata_ob[time]=np.hstack([Ydata_[time],Ydata[time]])
  330. # %%
  331. Xdata={}
  332. Ydata={}
  333. for time in [0,15,30,45,60,90,120,180,240]:
  334. xarray=[]
  335. yarray=[]
  336. for directory in [f"/datasets/Demo_MOCKED_data/BL/T{time}"]:
  337. xarray.append(extract_per_time_Lean(time,directory)[0])
  338. yarray.append(extract_per_time_Lean(time,directory)[1])
  339. xarray=np.concatenate(xarray, axis=0)
  340. yarray=np.concatenate(yarray, axis=0)
  341. Xdata[time]=xarray
  342. Ydata[time]=yarray
  343. # %%
  344. Xdata_Lean={}
  345. Ydata_Lean={}
  346. for time in [0,15,30,45,60,90,120,180,240]:
  347. Xdata_Lean[time]=Xdata[time]
  348. Ydata_Lean[time]=Ydata[time]
  349. # %%
  350. Xdata_Lean_list = list(Xdata_Lean.values())
  351. Xdata_ob_list = list(Xdata_ob.values())
  352. Xdata_Lean_concatenated = np.concatenate(Xdata_Lean_list, axis=0)
  353. Xdata_ob_concatenated = np.concatenate(Xdata_ob_list, axis=0)
  354. print(Xdata_Lean_concatenated.shape)
  355. print(Xdata_ob_concatenated.shape)
  356. xall=np.vstack([Xdata_ob_concatenated ,Xdata_Lean_concatenated ])
  357. yall=np.array([1]*Xdata_ob_concatenated.shape[0]+[0]*Xdata_Lean_concatenated.shape[0])
  358. # %%
  359. def select_top_n_feature(data,numb_feat,id_ls,y,rf_estimators,rf_depth):
  360. dX=id_ls
  361. Top1_feat_id=[]
  362. rf=RandomForestClassifier(n_estimators=rf_estimators,max_depth=rf_depth, random_state=0,class_weight='balanced')
  363. rf.fit(data[:,dX],y)
  364. Top1_feat_id=(-rf.feature_importances_).argsort()[:numb_feat].tolist()
  365. return (Top1_feat_id)
  366. def kfoldCV(xdata,ydata):
  367. cv = StratifiedKFold(n_splits=10, shuffle=True, random_state=0)
  368. classifier = XGBClassifier(n_estimators=xgb_est, learning_rate=xgb_lr, max_depth=xgb_depth,
  369. subsample=xgb_subsamp, colsample_bytree=xgb_colsam, reg_alpha=0.5,
  370. random_state=42, use_label_encoder=False, eval_metric='logloss')
  371. acc = cross_val_score(classifier, xdata, ydata, scoring='balanced_accuracy', cv=cv, n_jobs=-1)
  372. avg_acc=sum(acc/acc.shape[0])
  373. return (avg_acc )
  374. def feature_selection(traindataX, traindataY,
  375. xgb_est,xgb_lr,xgb_depth,xgb_subsamp,xgb_colsam,
  376. rf_estimators, rf_depth, meric_Threshold,numb_runs):
  377. existing_id_ls = []
  378. acc_dif = {}
  379. DF = {}
  380. rf_filtered_id_ls = {}
  381. Xdata_train = traindataX
  382. Ydata_train = traindataY
  383. all_fidls = np.arange(0, Xdata_train.shape[1])
  384. # Select the top features based on initial selection
  385. rf_filtered_id_ls = select_top_n_feature(Xdata_train, Xdata_train.shape[1], all_fidls, traindataY, rf_estimators, rf_depth)
  386. # Initialize the existing_id_ls with the best feature
  387. existing_id_ls = select_top_n_feature(Xdata_train, 1, np.arange(0, Xdata_train.shape[1]), Ydata_train, rf_estimators, rf_depth)
  388. # Get the rest of the features that are not in existing_id_ls
  389. rest_id_ls = [e for e in rf_filtered_id_ls if e not in existing_id_ls]
  390. mrf_index = 0
  391. consecutive_runs = 0
  392. highest_acc = -np.inf # To track the highest accuracy
  393. best_id_ls = existing_id_ls.copy() # To track the best feature set
  394. while mrf_index < len(rest_id_ls) and mrf_index < numb_runs:
  395. print('Run', mrf_index)
  396. # Select the next feature to add
  397. mrf = rest_id_ls[mrf_index]
  398. select_id = existing_id_ls + [mrf]
  399. # Evaluate the accuracy with the new feature added
  400. xdata = Xdata_train[:, select_id]
  401. ydata = np.array(Ydata_train)
  402. acc_newf = kfoldCV(xdata, ydata)
  403. #acc_newf = kfold_cv(xdata, ydata, valdataX[:, select_id], valdataY,xgb_est,xgb_lr,xgb_depth,xgb_subsamp,xgb_colsam)
  404. # Evaluate the accuracy with the current set of selected features
  405. xdata1 = Xdata_train[:, existing_id_ls]
  406. ydata1 = np.array(Ydata_train)
  407. acc_currentselect = kfoldCV(xdata1, ydata1)
  408. #acc_currentselect = kfold_cv(xdata1, ydata1, valdataX[:, existing_id_ls], valdataY,xgb_est,xgb_lr,xgb_depth,xgb_subsamp,xgb_colsam)
  409. print(acc_newf, select_id, acc_currentselect, existing_id_ls, 'p_gain:', acc_newf - acc_currentselect)
  410. # Track the highest accuracy and the corresponding feature set
  411. if acc_newf - acc_currentselect >meric_Threshold: # <-- Only update if the new accuracy is better than current
  412. existing_id_ls = select_id.copy() # Update the current feature set
  413. consecutive_runs = 0 # Reset the counter if acc_newf > acc_currentselect
  414. # Update the best set if this is the highest accuracy seen
  415. if acc_newf > highest_acc:
  416. highest_acc = acc_newf
  417. best_id_ls = select_id.copy() # Update the best feature set
  418. else:
  419. consecutive_runs += 1
  420. # Feature reselection process (if new feature does not improve performance)
  421. rf = RandomForestClassifier(n_estimators=rf_estimators, max_depth=rf_depth, class_weight='balanced', random_state=42)
  422. rf.fit(Xdata_train[:, select_id], Ydata_train)
  423. imp_score = rf.feature_importances_
  424. # Remove the least important feature
  425. toremove_id = select_id[np.argmin(imp_score)]
  426. existing_id_ls = select_id.copy() # Always use a copy to prevent mutation
  427. existing_id_ls.remove(toremove_id)
  428. # Stopping criteria
  429. if consecutive_runs == numb_runs:
  430. break
  431. if len(existing_id_ls) > 30:
  432. break
  433. mrf_index += 1
  434. print('consecutive_runs', consecutive_runs)
  435. print('existing_id_ls', existing_id_ls)
  436. # Return the feature set that gave the highest accuracy across all iterations
  437. return best_id_ls
  438. #def get_best_n_features(feature_list, traindataX, traindataY,xval,yval,rf_estimators, rf_depth):
  439. def get_best_n_features(feature_list, traindataX, traindataY,rf_estimators, rf_depth):
  440. selected_features = []
  441. accuracy_per_num_features = []
  442. skf = StratifiedKFold(n_splits=9, shuffle=True, random_state=42)
  443. for i, feature in enumerate(feature_list):
  444. #print(f"Adding feature {i+1}/{len(feature_list)}: Feature {feature}")
  445. selected_features.append(feature)
  446. accuracies=kfoldCV(traindataX[:, selected_features],np.array(traindataY))
  447. accuracy_per_num_features.append(accuracies)
  448. optimal_num_features = np.argmax(accuracy_per_num_features) + 1 # Adding 1 since index starts at 0
  449. print(f"\nOptimal number of features: {optimal_num_features} with accuracy: {accuracy_per_num_features[optimal_num_features-1]}")
  450. best_acc=accuracy_per_num_features[optimal_num_features-1]
  451. return optimal_num_features, best_acc,accuracy_per_num_features
  452. # %% [markdown]
  453. # ### Traning Set and Testing Set Data Split
  454. # %%
  455. from sklearn.model_selection import StratifiedKFold
  456. from imblearn.over_sampling import RandomOverSampler
  457. import numpy as np
  458. # Initialize the outer StratifiedKFold
  459. skf = StratifiedKFold(n_splits=10, shuffle=True, random_state=42)
  460. # Initialize dictionaries for storing training, validation, and test sets
  461. Xtv = {}
  462. Ytv = {}
  463. Xtest = {}
  464. Ytest = {}
  465. ros = RandomOverSampler(random_state=42)
  466. for time, i in zip([0, 15, 30, 45, 60, 90, 120, 180, 240], range(9)):
  467. X = np.vstack([Xdata_ob[time], Xdata_Lean[time]])
  468. y = np.hstack([Ydata_ob[time], Ydata_Lean[time]])
  469. Xtv[time] = {}
  470. Ytv[time] = {}
  471. Xtest[time] = {}
  472. Ytest[time] = {}
  473. # Initialize fold count
  474. fold = 0
  475. for train_index, test_index in skf.split(X, y):
  476. print('fold', fold)
  477. fold += 1
  478. # Create outer training and testing sets
  479. X_train, y_train = X[train_index], y[train_index]
  480. print('X_train, y_train',X_train.shape,y_train.shape,sum(y_train==0),sum(y_train==1))
  481. X_resampled, y_resampled = ros.fit_resample(X_train, y_train)
  482. print('X_resampled, y_resampled',X_resampled.shape,y_resampled.shape,sum(y_resampled==0),sum(y_resampled==1))
  483. X_test, y_test = X[test_index], y[test_index]
  484. # Store the inner training, validation, and outer test sets
  485. Xtv[time][fold] = X_resampled#X_tv
  486. Ytv[time][fold] = y_resampled#Y_tv
  487. Xtest[time][fold] = X_test
  488. Ytest[time][fold] = y_test
  489. print(' ')
  490. # %%
  491. #os.chdir('/home/jupy/SourceAnalysis/Journal2024_updatedMICMAC/data_Stratifysplit_on_TIME')
  492. Xtv_alltime={}
  493. Xtest_alltime={}
  494. #Xval_alltime={}
  495. Ytv_alltime={}
  496. Ytest_alltime={}
  497. #Yval_alltime={}
  498. for fold in range(1,11):
  499. print(fold)
  500. Xtv_alltime[fold]=np.vstack([ Xtv[0][fold], Xtv[15][fold], Xtv[30][fold], Xtv[45][fold], Xtv[60][fold],
  501. Xtv[90][fold], Xtv[120][fold],Xtv[180][fold], Xtv[240][fold] ])
  502. Xtest_alltime[fold]=np.vstack([ Xtest[0][fold], Xtest[15][fold], Xtest[30][fold], Xtest[45][fold], Xtest[60][fold],
  503. Xtest[90][fold], Xtest[120][fold],Xtest[180][fold], Xtest[240][fold] ])
  504. Ytv_alltime[fold]=np.hstack([ Ytv[0][fold], Ytv[15][fold],Ytv[30][fold], Ytv[45][fold], Ytv[60][fold],
  505. Ytv[90][fold], Ytv[120][fold],Ytv[180][fold], Ytv[240][fold] ])
  506. Ytest_alltime[fold]=np.hstack([ Ytest[0][fold], Ytest[15][fold], Ytest[30][fold], Ytest[45][fold], Ytest[60][fold],
  507. Ytest[90][fold], Ytest[120][fold], Ytest[180][fold], Ytest[240][fold] ])
  508. # %%
  509. Xtv_alltime[fold].shape
  510. # %%
  511. xgb_est=100
  512. xgb_lr=0.3
  513. xgb_depth=6
  514. xgb_subsamp=1
  515. xgb_colsam=1
  516. rf_estimators=100
  517. rf_depth=None
  518. meric_Threshold=0.00
  519. # %%
  520. from xgboost import XGBClassifier
  521. features_lst=[]
  522. test_acc_lst=[]
  523. best_features_lst=[]
  524. for f in range(1,11):
  525. features=feature_selection(Xtv_alltime[f], Ytv_alltime[f],
  526. xgb_est,xgb_lr,xgb_depth,xgb_subsamp,xgb_colsam,
  527. rf_estimators, rf_depth, meric_Threshold,numb_runs=100)
  528. features_lst.append(features)
  529. features=features[0:(get_best_n_features(features, Xtv_alltime[f], Ytv_alltime[f], rf_estimators, rf_depth)[0])]
  530. best_features_lst.append(features)
  531. print('best_features_lst',best_features_lst)
  532. best_features_acc_lst=(get_best_n_features(features, Xtv_alltime[f], Ytv_alltime[f], rf_estimators, rf_depth)[2])
  533. print('best_features_lst_ACC',best_features_acc_lst)
  534. print('######################## ACC ######################')
  535. # %%
  536. from sklearn.ensemble import RandomForestClassifier
  537. from sklearn.metrics import (recall_score, confusion_matrix, balanced_accuracy_score,
  538. f1_score, precision_score, roc_auc_score,
  539. matthews_corrcoef, average_precision_score)
  540. original_features =[5991, 3529, 30022, 38491, 38539, 36613]
  541. # Initialize dictionaries to store metrics for each fold
  542. recall_scores = {}
  543. normal_accuracies={}
  544. balanced_accuracies = {}
  545. f1_scores = {}
  546. precision_scores = {}
  547. roc_auc_scores = {}
  548. pr_auc_scores = {}
  549. confusion_matrices={}
  550. for fold in range(1, 11):
  551. # Train the model on the specified features in the training set
  552. rf = RandomForestClassifier(random_state=42, class_weight='balanced')
  553. rf.fit(np.vstack([ Xtv_alltime[fold][:, original_features] ]),
  554. np.hstack([ Ytv_alltime[fold]]) )
  555. # Predict on the test set
  556. y_pred = rf.predict(Xtest_alltime[fold][:, original_features])
  557. y_prob = rf.predict_proba(Xtest_alltime[fold][:, original_features])[:, 1] # Probability for ROC-AUC and PR-AUC
  558. recall = recall_score(Ytest_alltime[fold], y_pred, pos_label=1)
  559. recall_scores[fold] = recall
  560. cm = confusion_matrix(Ytest_alltime[fold], y_pred)
  561. tn, fp, fn, tp = cm.ravel()
  562. normal_acc = accuracy_score(Ytest_alltime[fold], y_pred)
  563. normal_accuracies[fold] = normal_acc
  564. balanced_acc = balanced_accuracy_score(Ytest_alltime[fold], y_pred)
  565. balanced_accuracies[fold] = balanced_acc
  566. f1 = f1_score(Ytest_alltime[fold], y_pred, pos_label=1)
  567. f1_scores[fold] = f1
  568. precision = precision_score(Ytest_alltime[fold], y_pred, pos_label=1)
  569. precision_scores[fold] = precision
  570. roc_auc = roc_auc_score(Ytest_alltime[fold], y_prob)
  571. roc_auc_scores[fold] = roc_auc
  572. pr_auc = average_precision_score(Ytest_alltime[fold], y_prob)
  573. pr_auc_scores[fold] = pr_auc
  574. cm = confusion_matrix(Ytest_alltime[fold], y_pred)
  575. confusion_matrices[fold] = cm
  576. # Display metrics for each fold
  577. for fold in range(1, 11):
  578. print(f"Fold {fold}:")
  579. print(f" Recall: {recall_scores[fold]:.4f}")
  580. print(f" Balanced Accuracy: {balanced_accuracies[fold]:.4f}")
  581. print(f" Normal Accuracy: {normal_accuracies[fold]:.4f}")
  582. print(f" F1 Score: {f1_scores[fold]:.4f}")
  583. print(f" Precision: {precision_scores[fold]:.4f}")
  584. print(f" ROC-AUC: {roc_auc_scores[fold]:.4f}")
  585. print(f" Precision-Recall AUC: {pr_auc_scores[fold]:.4f}")
  586. print(f" CM: {confusion_matrices[fold]}")
  587. # Calculate averages and standard deviations for each metric
  588. avg_recall = np.mean(list(recall_scores.values()))
  589. std_recall = np.std(list(recall_scores.values()))
  590. avg_normal_accuracy = np.mean(list(normal_accuracies.values()))
  591. std_normal_accuracy = np.std(list(normal_accuracies.values()))
  592. avg_balanced_accuracy = np.mean(list(balanced_accuracies.values()))
  593. std_balanced_accuracy = np.std(list(balanced_accuracies.values()))
  594. avg_f1 = np.mean(list(f1_scores.values()))
  595. std_f1 = np.std(list(f1_scores.values()))
  596. avg_precision = np.mean(list(precision_scores.values()))
  597. std_precision = np.std(list(precision_scores.values()))
  598. avg_roc_auc = np.mean(list(roc_auc_scores.values()))
  599. std_roc_auc = np.std(list(roc_auc_scores.values()))
  600. avg_pr_auc = np.mean(list(pr_auc_scores.values()))
  601. std_pr_auc = np.std(list(pr_auc_scores.values()))
  602. # Display the averages and standard deviations
  603. print("\nAverage Metrics Across All Folds (with Standard Deviations):")
  604. print(f" Average Recall: {avg_recall:.4f} ± {std_recall:.4f}")
  605. print(f" Average Normal Accuracy: {avg_normal_accuracy:.4f} ± {std_normal_accuracy:.4f}")
  606. print(f" Average Balanced Accuracy: {avg_balanced_accuracy:.4f} ± {std_balanced_accuracy:.4f}")
  607. print(f" Average F1 Score: {avg_f1:.4f} ± {std_f1:.4f}")
  608. print(f" Average Precision: {avg_precision:.4f} ± {std_precision:.4f}")
  609. print(f" Average ROC-AUC: {avg_roc_auc:.4f} ± {std_roc_auc:.4f}")
  610. print(f" Average Precision-Recall AUC: {avg_pr_auc:.4f} ± {std_pr_auc:.4f}")
  611. # %% [markdown]
  612. # # ------------------------------------------------------------
  613. # %%
  614. from sklearn.model_selection import StratifiedKFold
  615. def cross_val_with_features(X, y):
  616. skf = StratifiedKFold(n_splits=10, shuffle=True, random_state=42)
  617. accuracies = []
  618. for train_index, test_index in skf.split(X, y):
  619. X_train, X_test = X[train_index], X[test_index]
  620. y_train, y_test = y[train_index], y[test_index]
  621. rf.fit(X_train, y_train)
  622. y_pred =rf.predict(X_test)
  623. accuracies.append(accuracy_score(y_test, y_pred))
  624. return accuracies
  625. X_3mon_ob=np.vstack([ Xdata_ob[0][30:60,:], Xdata_ob[15][30:60,:], Xdata_ob[30][30:60,:], Xdata_ob[45][30:60,:],
  626. Xdata_ob[60][30:60,:],Xdata_ob[90][30:60,:], Xdata_ob[120][30:60,:],
  627. Xdata_ob[180][30:60,:], Xdata_ob[240][30:60,:] ])
  628. X_bl_ob=np.vstack([ Xdata_ob[0][0:30,:], Xdata_ob[15][0:30,:], Xdata_ob[30][0:30,:], Xdata_ob[45][0:30,:],
  629. Xdata_ob[60][0:30,:],Xdata_ob[90][0:30,:], Xdata_ob[120][0:30,:],
  630. Xdata_ob[180][0:30,:], Xdata_ob[240][0:30,:] ])
  631. X_pwl_ob=np.vstack([ Xdata_ob[0][60:,:], Xdata_ob[15][60:,:], Xdata_ob[30][60:,:], Xdata_ob[45][60:,:],
  632. Xdata_ob[60][60:,:],Xdata_ob[90][60:,:], Xdata_ob[120][60:,:],
  633. Xdata_ob[180][60:,:], Xdata_ob[240][60:,:] ])
  634. X_bl_lean=np.vstack([ Xdata_Lean[0][0:30,:], Xdata_Lean[15][0:30,:], Xdata_Lean[30][0:30,:], Xdata_Lean[45][0:30,:],
  635. Xdata_Lean[60][0:30,:],Xdata_Lean[90][0:30,:], Xdata_Lean[120][0:30,:],
  636. Xdata_Lean[180][0:30,:], Xdata_Lean[240][0:30,:] ])
  637. # %% [markdown]
  638. # ### Test minimum best model per Stage per Timepoint
  639. # %%
  640. best_feat=[ 7144, 6001, 38004, 6674, 37885, 7040, 38470, 37416, 7150,
  641. 38520, 7016, 37372, 1320, 7115, 7028, 7119, 36576]
  642. best_feat_permu_min=[5991, 3529, 30022, 38491, 38539, 36613]
  643. # %%
  644. def acc_per_stage_per_tps(best_feat,time_point):
  645. subj_y = np.hstack([np.ones(30), np.zeros(30)])
  646. Xtv_id = {}
  647. Xtest_id = {}
  648. index_lean = {}
  649. index_ob = {}
  650. for s in range(10):
  651. index_lean[s] = ([np.where(np.array(subj_y) == 1)][0][0])[s * (60 // 10 // 2):(s + 1) * (60 // 10 // 2)]
  652. index_ob[s] = ([np.where(np.array(subj_y) == 0)][0][0])[s * (60 // 10 // 2):(s + 1) * (60 // 10 // 2)]
  653. index_test = index_lean[s].tolist() + index_ob[s].tolist()
  654. Xtest_id[s] = index_test
  655. index_train = np.arange(60)[np.isin(np.arange(60), index_test, invert=True)]
  656. Xtv_id[s] = index_train
  657. allstage_score = []
  658. for stage, obese_data in zip(['BL', '3MON', 'PWL'],
  659. [Xdata_ob[time_point][:30, :], Xdata_ob[time_point][30:60, :], Xdata_ob[time_point][60:, :]]):
  660. Xdata = np.vstack([obese_data[:, best_feat], Xdata_Lean[time_point][:30, :][:, best_feat]])
  661. Ydata = np.hstack([np.ones(30), np.zeros(30)])
  662. avg_score = []
  663. for s in range(10):
  664. Xtv = Xdata[Xtv_id[s]]
  665. Ytv = Ydata[Xtv_id[s]]
  666. Xtest = Xdata[Xtest_id[s]]
  667. Ytest = Ydata[Xtest_id[s]]
  668. rf.fit(Xtv, Ytv)
  669. avg_score.append(accuracy_score(rf.predict(Xtest), Ytest))
  670. allstage_score.append(avg_score)
  671. return sum(allstage_score[0]) / 10, sum(allstage_score[1]) / 10, sum(allstage_score[2]) / 10
  672. # %%
  673. time_points = [0, 15, 30, 45, 60, 90, 120, 180, 240]
  674. pwl_acc_list = []
  675. mon3_acc_list = []
  676. bl_acc_list = []
  677. # Calculate the accuracy for each time point
  678. for time_point in time_points:
  679. bl_acc, mon3_acc, pwl_acc = acc_per_stage_per_tps(best_feat_permu_min,time_point)
  680. pwl_acc_list.append(pwl_acc)
  681. mon3_acc_list.append(mon3_acc)
  682. bl_acc_list.append(bl_acc)
  683. # %%
  684. from scipy.stats import ttest_ind, levene, mannwhitneyu, shapiro
  685. def compare_lists(list1, list2, name1, name2):
  686. # Perform Shapiro-Wilk test for normality on both lists
  687. shapiro_list1 = shapiro(list1)
  688. shapiro_list2 = shapiro(list2)
  689. print(f"Shapiro-Wilk test p-values: {name1} = {shapiro_list1.pvalue:.4f}, {name2} = {shapiro_list2.pvalue:.4f}")
  690. # Check if both distributions are normally distributed (p-value > 0.05)
  691. if shapiro_list1.pvalue > 0.05 and shapiro_list2.pvalue > 0.05:
  692. # Check for equality of variances using Levene's Test
  693. stat, p_value_levene = levene(list1, list2)
  694. equal_var = p_value_levene > 0.05
  695. # Perform an independent t-test
  696. t_stat, p_value = ttest_ind(list1, list2, equal_var=equal_var)
  697. test_name = "Independent t-test"
  698. else:
  699. # Use Mann-Whitney U test if either distribution is not normal
  700. t_stat, p_value = mannwhitneyu(list1, list2)
  701. test_name = "Mann-Whitney U test"
  702. print(f"{test_name} ({name1} vs {name2}): statistic={t_stat:.4f}, p-value={p_value:.4f}\n")
  703. # Compare the lists in pairs
  704. compare_lists(pwl_acc_list, mon3_acc_list, "pwl_acc_list", "mon3_acc_list")
  705. compare_lists(pwl_acc_list, bl_acc_list, "pwl_acc_list", "bl_acc_list")
  706. compare_lists(mon3_acc_list, bl_acc_list, "mon3_acc_list", "bl_acc_list")
  707. # %%
  708. time_points_str = [str(tp) for tp in time_points]
  709. plt.figure(figsize=(8, 4))
  710. plt.plot(time_points_str, bl_acc_list, label='BL', marker='o')
  711. plt.fill_between(time_points_str, bl_acc_list - np.std(bl_acc_list), bl_acc_list + np.std(bl_acc_list), alpha=0.15,color='blue')
  712. plt.plot(time_points_str, pwl_acc_list, label='PWL', marker='o')
  713. plt.fill_between(time_points_str, pwl_acc_list - np.std(pwl_acc_list), pwl_acc_list + np.std(pwl_acc_list), alpha=0.15,color='orange')
  714. plt.plot(time_points_str, mon3_acc_list, label='3MON', marker='o')
  715. plt.fill_between(time_points_str, mon3_acc_list - np.std(mon3_acc_list), mon3_acc_list + np.std(mon3_acc_list), alpha=0.15, color='green')
  716. plt.xlabel('Time Point')
  717. plt.ylabel('Accuracy')
  718. plt.title('Accuracy per Stage per Time Point')
  719. plt.legend()
  720. plt.grid(True)
  721. plt.ylim(0.2, 1)
  722. # %% [markdown]
  723. # #### Model Significance Test
  724. # %%
  725. def swap_labels(X, y, n, swap_ratio):
  726. np.random.seed(42) # For reproducibility
  727. X_swapped, y_swapped = X.copy(), y.copy()
  728. for _ in range(n):
  729. pain_indices = np.where(y_swapped == 1)[0]
  730. healthy_indices = np.where(y_swapped == 0)[0]
  731. num_to_swap = int(min(len(pain_indices), len(healthy_indices)) * swap_ratio)
  732. pain_to_healthy_indices = np.random.choice(pain_indices, size=num_to_swap, replace=False)
  733. healthy_to_pain_indices = np.random.choice(healthy_indices, size=num_to_swap, replace=False)
  734. y_swapped[pain_to_healthy_indices], y_swapped[healthy_to_pain_indices] = \
  735. y[healthy_to_pain_indices], y[pain_to_healthy_indices]
  736. return X_swapped, y_swapped
  737. # %%
  738. num_splits=1000
  739. swap_ratio=0.5
  740. def permutation_test(real_accuracies, shuffled_accuracies, n_permutations=1000):
  741. observed_diff = np.mean(real_accuracies) - np.mean(shuffled_accuracies)
  742. all_accuracies = np.concatenate([real_accuracies, shuffled_accuracies])
  743. extreme_count = 0
  744. for i in range(n_permutations):
  745. # Shuffle labels
  746. np.random.shuffle(all_accuracies)
  747. perm_real = all_accuracies[:len(real_accuracies)]
  748. perm_shuffled = all_accuracies[len(real_accuracies):]
  749. perm_diff = np.mean(perm_real) - np.mean(perm_shuffled)
  750. # Count how often permuted difference is as extreme as observed
  751. if abs(perm_diff) >= abs(observed_diff):
  752. extreme_count += 1
  753. p_value = (extreme_count + 1) / (n_permutations + 1)
  754. return p_value, observed_diff
  755. clf=rf
  756. for t in range(0, 9):
  757. shuffled_acc = []
  758. non_shuffled_acc = []
  759. # Adjust your xx and yy variable population based on t
  760. xx = np.vstack([X_bl_ob[t*30:(t+1)*30,best_feat_permu_min], X_bl_lean[t*30:(t+1)*30,best_feat_permu_min]])
  761. yy = np.hstack([np.zeros(30), np.ones(30)])
  762. # Calculate shuffled accuracy
  763. for i in range(num_splits):
  764. X_train, X_test, y_train, y_test = train_test_split(xx, yy, test_size=0.2, random_state=i, stratify=yy)
  765. X_swapped, y_swapped = swap_labels(X_train, y_train, 1, swap_ratio)
  766. clf.fit(X_train, y_swapped)
  767. score = accuracy_score(y_test, clf.predict(X_test))
  768. shuffled_acc.append(score)
  769. print('shuf acc', sum(shuffled_acc) / len(shuffled_acc), 'shuf std', statistics.stdev(shuffled_acc))
  770. # Calculate non-shuffled accuracy
  771. for i in range(num_splits):
  772. X_train, X_test, y_train, y_test = train_test_split(xx, yy, test_size=0.2, random_state=i, stratify=yy)
  773. clf.fit(X_train, y_train)
  774. score = accuracy_score(y_test, clf.predict(X_test))
  775. non_shuffled_acc.append(score)
  776. print('real acc', sum(non_shuffled_acc) / len(non_shuffled_acc), 'real std', statistics.stdev(non_shuffled_acc))
  777. p_value, diff = permutation_test(non_shuffled_acc, shuffled_acc, n_permutations=1000)
  778. print(f"Time {t}: p-value = {p_value:.4f}, mean difference = {diff:.3f}")
  779. # %%
  780. #os.chdir('/home/jupy/SourceAnalysis/Journal2024_updatedMICMAC/SourceData/PWL_shuffle')
  781. num_splits=1000
  782. swap_ratio=0.5
  783. def permutation_test(real_accuracies, shuffled_accuracies, n_permutations=1000):
  784. observed_diff = np.mean(real_accuracies) - np.mean(shuffled_accuracies)
  785. all_accuracies = np.concatenate([real_accuracies, shuffled_accuracies])
  786. extreme_count = 0
  787. for i in range(n_permutations):
  788. # Shuffle labels
  789. np.random.shuffle(all_accuracies)
  790. perm_real = all_accuracies[:len(real_accuracies)]
  791. perm_shuffled = all_accuracies[len(real_accuracies):]
  792. perm_diff = np.mean(perm_real) - np.mean(perm_shuffled)
  793. # Count how often permuted difference is as extreme as observed
  794. if abs(perm_diff) >= abs(observed_diff):
  795. extreme_count += 1
  796. p_value = (extreme_count + 1) / (n_permutations + 1)
  797. return p_value, observed_diff
  798. clf=rf
  799. for t in range(0, 9):
  800. shuffled_acc = []
  801. non_shuffled_acc = []
  802. # Adjust your xx and yy variable population based on t
  803. xx = np.vstack([X_pwl_ob[t*30:(t+1)*30,best_feat_permu_min], X_bl_lean[t*30:(t+1)*30,best_feat_permu_min]])
  804. yy = np.hstack([np.zeros(30), np.ones(30)])
  805. # Calculate shuffled accuracy
  806. for i in range(num_splits):
  807. X_train, X_test, y_train, y_test = train_test_split(xx, yy, test_size=0.2, random_state=i, stratify=yy)
  808. X_swapped, y_swapped = swap_labels(X_train, y_train, 1, swap_ratio)
  809. clf.fit(X_train, y_swapped)
  810. score = accuracy_score(y_test, clf.predict(X_test))
  811. shuffled_acc.append(score)
  812. print('shuf acc', sum(shuffled_acc) / len(shuffled_acc), 'shuf std', statistics.stdev(shuffled_acc))
  813. # Calculate non-shuffled accuracy
  814. for i in range(num_splits):
  815. X_train, X_test, y_train, y_test = train_test_split(xx, yy, test_size=0.2, random_state=i, stratify=yy)
  816. clf.fit(X_train, y_train)
  817. score = accuracy_score(y_test, clf.predict(X_test))
  818. non_shuffled_acc.append(score)
  819. print('real acc', sum(non_shuffled_acc) / len(non_shuffled_acc), 'real std', statistics.stdev(non_shuffled_acc))
  820. p_value, diff = permutation_test(non_shuffled_acc, shuffled_acc, n_permutations=1000)
  821. print(f"Time {t}: p-value = {p_value:.4f}, mean difference = {diff:.3f}")
  822. # %%
  823. num_splits=1000
  824. swap_ratio=0.5
  825. def permutation_test(real_accuracies, shuffled_accuracies, n_permutations=1000):
  826. observed_diff = np.mean(real_accuracies) - np.mean(shuffled_accuracies)
  827. all_accuracies = np.concatenate([real_accuracies, shuffled_accuracies])
  828. extreme_count = 0
  829. for i in range(n_permutations):
  830. # Shuffle labels
  831. np.random.shuffle(all_accuracies)
  832. perm_real = all_accuracies[:len(real_accuracies)]
  833. perm_shuffled = all_accuracies[len(real_accuracies):]
  834. perm_diff = np.mean(perm_real) - np.mean(perm_shuffled)
  835. # Count how often permuted difference is as extreme as observed
  836. if abs(perm_diff) >= abs(observed_diff):
  837. extreme_count += 1
  838. p_value = (extreme_count + 1) / (n_permutations + 1)
  839. return p_value, observed_diff
  840. clf=rf
  841. for t in range(0, 9):
  842. shuffled_acc = []
  843. non_shuffled_acc = []
  844. # Adjust your xx and yy variable population based on t
  845. xx = np.vstack([X_3mon_ob[t*30:(t+1)*30,best_feat_permu_min], X_bl_lean[t*30:(t+1)*30,best_feat_permu_min]])
  846. yy = np.hstack([np.zeros(30), np.ones(30)])
  847. # Calculate shuffled accuracy
  848. for i in range(num_splits):
  849. X_train, X_test, y_train, y_test = train_test_split(xx, yy, test_size=0.2, random_state=i, stratify=yy)
  850. X_swapped, y_swapped = swap_labels(X_train, y_train, 1, swap_ratio)
  851. clf.fit(X_train, y_swapped)
  852. score = accuracy_score(y_test, clf.predict(X_test))
  853. shuffled_acc.append(score)
  854. print('shuf acc', sum(shuffled_acc) / len(shuffled_acc), 'shuf std', statistics.stdev(shuffled_acc))
  855. # Calculate non-shuffled accuracy
  856. for i in range(num_splits):
  857. X_train, X_test, y_train, y_test = train_test_split(xx, yy, test_size=0.2, random_state=i, stratify=yy)
  858. clf.fit(X_train, y_train)
  859. score = accuracy_score(y_test, clf.predict(X_test))
  860. non_shuffled_acc.append(score)
  861. print('real acc', sum(non_shuffled_acc) / len(non_shuffled_acc), 'real std', statistics.stdev(non_shuffled_acc))
  862. p_value, diff = permutation_test(non_shuffled_acc, shuffled_acc, n_permutations=1000)
  863. print(f"Time {t}: p-value = {p_value:.4f}, mean difference = {diff:.3f}")
  864. # %% [markdown]
  865. # # Feature Interpretation
  866. # %%
  867. Original_features= [5991, 3529, 30022, 38491, 38539, 36613]
  868. # %%
  869. def extract_feat_info(feat_idx_ls):
  870. os.chdir('/home/jupy/SourceAnalysis')
  871. coordinates=np.loadtxt('88_areas-ROIcentroids.txt')[:,0:3]
  872. sensor= np.arange(0,88)#.astype(str)
  873. nodes1=np.zeros([2])
  874. nodes2=np.zeros([2])
  875. data=np.array(pd.read_csv('88ROIallBA-ROI-ROI.csv',header=None))
  876. bands=['delta','theta','alpha','beta','gamma']
  877. featid_info=[]
  878. structure_info=[]
  879. band_info=[]
  880. for feat_idx in feat_idx_ls:
  881. if feat_idx//7744==0:
  882. e_color='BuGn'
  883. if feat_idx//7744==1:
  884. e_color='inferno'
  885. if feat_idx//7744==2:
  886. e_color='Oranges'
  887. if feat_idx//7744==3:
  888. e_color='Purples'
  889. if feat_idx//7744==4:
  890. e_color='Oranges'
  891. #print(feat_idx)
  892. i=feat_idx-feat_idx//7744*7744
  893. chanel1=int((i)//88)
  894. name_chan1=sensor[chanel1]
  895. name_chan1_correctInd=name_chan1+1
  896. chanel2=int((i)%88)
  897. name_chan2=sensor[chanel2]
  898. name_chan2_correctInd=name_chan2+1
  899. #lobe
  900. lobe1=data[np.where(data[:,-1]==name_chan1_correctInd)[0][0],3]
  901. lobe2=data[np.where(data[:,-1]==name_chan2_correctInd)[0][0],3]
  902. #structure
  903. structure1=data[np.where(data[:,-1]==name_chan1_correctInd)[0][0],4]
  904. structure2=data[np.where(data[:,-1]==name_chan2_correctInd)[0][0],4]
  905. #Brodmann area
  906. brod1=data[np.where(data[:,-1]==name_chan1_correctInd)[0][0],5]
  907. brod2=data[np.where(data[:,-1]==name_chan2_correctInd)[0][0],5]
  908. #ROI number
  909. roinumb1=data[np.where(data[:,-1]==name_chan1_correctInd)[0][0],6]
  910. roinumb2=data[np.where(data[:,-1]==name_chan2_correctInd)[0][0],6]
  911. nodes1=np.vstack([nodes1,np.array([name_chan1,name_chan2])])
  912. nodes2=np.vstack([nodes2,np.array([name_chan2,name_chan1])])
  913. print('feature_id: ',feat_idx,';',bands[feat_idx//7744],';',lobe1,'-',lobe2,';',structure1,'-',structure2,';',
  914. brod1,'-',brod2,';',roinumb1,'-',roinumb2)
  915. #print(' ')
  916. structure_info.append(f'{brod1} - {brod2}')
  917. featid_info.append(feat_idx)
  918. band_info.append(bands[feat_idx//7744])
  919. return featid_info,structure_info,band_info
  920. # %%
  921. Original_features
  922. featid,featStruc,feat_band=extract_feat_info(Original_features)
  923. featStruc= ['40L - 4R','25L - 5R', '44R - 8L','32L - 22R','32L - 47R','38L - 3R',]
  924. # %%
  925. #### Feature Significance Test
  926. # %%
  927. df_simulated = pd.DataFrame({ 'Feature_ID':col_featid,'Feature_Structure':col_struc,'Feature_Value': col_featvalue,'Group': col_group})
  928. # %%
  929. from scipy.stats import mannwhitneyu
  930. reject_array=[]
  931. pvalue_array=[]
  932. sigstar_array=[]
  933. for tp in [0,15,30,45, 60,90,120,180,240]:
  934. featStruc
  935. col_struc=[]
  936. for i in featStruc:
  937. col_struc.append([f'{i}']*90)
  938. col_struc=col_struc+col_struc
  939. col_struc=np.array(col_struc).reshape(-1)
  940. col_featvalue_ob=[]
  941. col_featvalue_lean=[]
  942. for feat in Original_features:
  943. aa=Xdata_ob[tp][:, feat]
  944. bb= Xdata_Lean[tp][:, feat]
  945. col_featvalue_ob.append(aa)
  946. col_featvalue_lean.append(bb)
  947. col_featvalue_ob=np.array(col_featvalue_ob).reshape(-1)
  948. col_featvalue_lean=np.array(col_featvalue_lean).reshape(-1)
  949. ros = RandomOverSampler(sampling_strategy=0.33)
  950. col_featvalue_lean_rosX, col_featvalue_lean_rosY = ros.fit_resample(col_featvalue_lean, y)
  951. print(col_featvalue_ob.shape)
  952. print(col_featvalue_lean.shape)
  953. col_featvalue=np.hstack([col_featvalue_ob,col_featvalue_lean])
  954. col_featid=[]
  955. for feat in Original_features:
  956. col_featid.append( np.array([feat]*90).astype(str) )
  957. col_featid=col_featid+col_featid
  958. col_featid=np.array(col_featid).reshape(-1)
  959. col_featid
  960. print(col_featid.shape)
  961. col_group=['Obese']*int(col_featvalue.shape[0]/2)+['Lean']*int(col_featvalue.shape[0]/2)
  962. col_group=np.array(col_group)
  963. print(col_group.shape)
  964. df_simulated = pd.DataFrame({ 'Feature_ID':col_featid,'Feature_Structure':col_struc,'Feature_Value': col_featvalue,'Group': col_group})
  965. plt.rcParams.update({'font.size': 9})
  966. import matplotlib.pyplot as plt
  967. import seaborn as sns
  968. from statannot import add_stat_annotation
  969. from scipy.stats import ttest_ind
  970. import os
  971. from statsmodels.stats.multitest import multipletests
  972. # Define box pairs for annotation
  973. unique_features = df_simulated["Feature_Structure"].unique()
  974. box_pairs = [((feature, "Obese"), (feature, "Lean")) for feature in unique_features]
  975. box_pairs = [((feature, "Lean"), (feature, "Obese")) for feature in unique_features]
  976. # Perform t-tests
  977. p_values = []
  978. for pair in box_pairs:
  979. group1 = df_simulated[(df_simulated['Feature_Structure'] == pair[0][0]) & (df_simulated['Group'] == pair[0][1])]['Feature_Value']
  980. group2 = df_simulated[(df_simulated['Feature_Structure'] == pair[1][0]) & (df_simulated['Group'] == pair[1][1])]['Feature_Value']
  981. #t_stat, p_val = ttest_ind(group1, group2)
  982. t_stat, p_val = mannwhitneyu(group1, group2, alternative='two-sided')
  983. p_values.append(p_val)
  984. reject, pvals_corrected, _, _ = multipletests(p_values, alpha=0.05, method='fdr_bh')
  985. # Output the results
  986. print("Reject null hypothesis for these comparisons:", reject)
  987. print("Corrected p-values:", [f'{pval:.4f}' for pval in pvals_corrected])
  988. def get_significance_level(p):
  989. if p < 0.0001:
  990. return "***"
  991. elif p < 0.01:
  992. return "**"
  993. elif p < 0.05:
  994. return "*"
  995. else:
  996. return "ns"
  997. # Get significance level annotations for each feature
  998. significance_levels = [get_significance_level(p) for p in pvals_corrected]
  999. significance_levels
  1000. reject_array.append(reject)
  1001. pvalue_array.append(pvals_corrected)
  1002. sigstar_array.append(significance_levels)
  1003. pvalue_array=np.array(pvalue_array)
  1004. # %%
  1005. ### Feature Distribution
  1006. # %%
  1007. # Define the feature and time indices
  1008. time_index = ["T0", "T15", "T30", "T45", "T60", "T90", "T120", "T180", "T240"]
  1009. feature_index = ['40L - 4R', '25L - 5R', '44R - 8L', '32L - 22R', '32L - 47R', '38L - 3R']
  1010. # Set custom colors for specific feature labels
  1011. custom_colors = {
  1012. '40L - 4R': '#D4A000',
  1013. '25L - 5R': '#D4A000',
  1014. '44R - 8L': 'green',
  1015. '32L - 22R': 'red',
  1016. '32L - 47R': 'red',
  1017. '38L - 3R': 'red'
  1018. }
  1019. # Create the heatmap with features on the x-axis and timepoints on the y-axis
  1020. plt.rcParams.update({'font.size': 12})
  1021. plt.figure(figsize=(12, 8))
  1022. heatmap = plt.imshow(pvalue_array, cmap='YlOrBr_r', aspect='auto', vmin=0, vmax=0.05) # Increase color resolution for low p-values
  1023. # Add a color bar to indicate the scale
  1024. cbar = plt.colorbar(heatmap)
  1025. cbar.set_label('Corrected p-values', fontsize=12) # Increase the color bar label font size
  1026. cbar.ax.tick_params(labelsize=11) # Increase the font size of the color bar ticks
  1027. # Set the tick labels with custom colors
  1028. xticks = plt.xticks(np.arange(len(feature_index)), feature_index, rotation=45, ha='right', fontsize=12)
  1029. yticks = plt.yticks(np.arange(len(time_index)), time_index, fontsize=12)
  1030. for label in plt.gca().get_xticklabels():
  1031. label.set_color(custom_colors.get(label.get_text(), 'black'))
  1032. # Annotate the heatmap with p-values or "ns" if p > 0.05, with white font and increased font size
  1033. for i in range(pvalue_array.shape[0]):
  1034. for j in range(pvalue_array.shape[1]):
  1035. value = pvalue_array[i, j]
  1036. if value > 0.05:
  1037. plt.text(j, i, 'ns', ha='center', va='center', color='black', fontsize=12)
  1038. else:
  1039. plt.text(j, i, f'{value:.4f}', ha='center', va='center', color='white', fontsize=12)
  1040. # %%
  1041. featStruc
  1042. col_struc=[]
  1043. for i in featStruc:
  1044. col_struc.append([f'{i}']*270)
  1045. col_struc=col_struc+col_struc
  1046. col_struc=np.array(col_struc).reshape(-1)
  1047. col_featvalue_ob=[]
  1048. col_featvalue_lean=[]
  1049. for feat in Original_features:
  1050. aa=X_bl_ob[:, feat]
  1051. bb=X_bl_lean[:, feat]
  1052. col_featvalue_ob.append(aa)
  1053. col_featvalue_lean.append(bb)
  1054. col_featvalue_ob=np.array(col_featvalue_ob).reshape(-1)
  1055. col_featvalue_lean=np.array(col_featvalue_lean).reshape(-1)
  1056. print(col_featvalue_ob.shape)
  1057. print(col_featvalue_lean.shape)
  1058. col_featvalue=np.hstack([col_featvalue_ob,col_featvalue_lean])
  1059. col_featid=[]
  1060. for feat in Original_features:
  1061. # col_featid.append( np.array([feat]*90).astype(str) )
  1062. col_featid.append( np.array([feat]*270).astype(str) )
  1063. col_featid=col_featid+col_featid
  1064. col_featid=np.array(col_featid).reshape(-1)
  1065. col_featid
  1066. print(col_featid.shape)
  1067. col_group=['Obese']*int(col_featvalue.shape[0]/2)+['Lean']*int(col_featvalue.shape[0]/2)
  1068. col_group=np.array(col_group)
  1069. print(col_group.shape)
  1070. df_simulated = pd.DataFrame({ 'Feature_ID':col_featid,'Feature_Structure':col_struc,'Feature_Value': col_featvalue,'Group': col_group})
  1071. plt.rcParams.update({'font.size': 9})
  1072. import matplotlib.pyplot as plt
  1073. import seaborn as sns
  1074. from statannot import add_stat_annotation
  1075. from scipy.stats import ttest_ind
  1076. import os
  1077. # Set up the plot
  1078. plt.figure(figsize=(10,7))
  1079. custom_colors = {
  1080. '40L - 4R': '#D4A000',
  1081. '25L - 5R': '#D4A000',
  1082. '44R - 8L': 'green',
  1083. '32L - 22R': 'red',
  1084. '32L - 47R': 'red',
  1085. '38L - 3R': 'red'
  1086. }
  1087. ax = sns.boxplot(x='Feature_Structure', y='Feature_Value', hue='Group', data=df_simulated)
  1088. unique_features = df_simulated["Feature_Structure"].unique()
  1089. box_pairs = [((feature, "Obese"), (feature, "Lean")) for feature in unique_features]
  1090. box_pairs = [((feature, "Lean"), (feature, "Obese")) for feature in unique_features]
  1091. p_values = []
  1092. for pair in box_pairs:
  1093. group1 = df_simulated[(df_simulated['Feature_Structure'] == pair[0][0]) & (df_simulated['Group'] == pair[0][1])]['Feature_Value']
  1094. group2 = df_simulated[(df_simulated['Feature_Structure'] == pair[1][0]) & (df_simulated['Group'] == pair[1][1])]['Feature_Value']
  1095. t_stat, p_val = mannwhitneyu(group1, group2, alternative='two-sided')
  1096. p_values.append(p_val)
  1097. reject, pvals_corrected, _, _ = multipletests(p_values, alpha=0.05, method='fdr_bh')
  1098. significance_annotations = ['***' if p < 0.0001 else
  1099. '**' if p < 0.001 else
  1100. '*' if p < 0.01 else
  1101. 'ns' for p in pvals_corrected]
  1102. add_stat_annotation(ax, data=df_simulated, x='Feature_Structure', y='Feature_Value', hue='Group',
  1103. box_pairs=box_pairs, perform_stat_test=False, pvalues=p_values, test=None, text_format='star', loc='outside',
  1104. line_height=0.001, text_annot_custom=significance_annotations, fontsize=12)
  1105. ax.spines['top'].set_visible(False)
  1106. ax.spines['right'].set_visible(False)
  1107. ax.spines['left'].set_visible(False)
  1108. ax.spines['bottom'].set_visible(False)
  1109. ax.set_xlabel(None)
  1110. plt.ylabel('Feature Value', fontsize=12)
  1111. ax.legend(loc='upper left', bbox_to_anchor=(1, 1), fontsize=12)
  1112. plt.xticks(rotation=45, ha='right', fontsize=12)
  1113. for label in plt.gca().get_xticklabels():
  1114. label.set_color(custom_colors.get(label.get_text(), 'black'))
  1115. plt.yticks(fontsize=12)
  1116. plt.tight_layout()

CodeScript.ipynb, under CC-BY-4.0 · at the source

Overview

Authors: Yuan Yue1, Patrick Manning2, Dirk De Ridder3, Matthew Hall3, Divya Bharatkumar Adhia3, Samantha Ross2, Daniel Alencar da Costa1, Jeremiah D. Deng1
  1. School of Computing, University of Otago,Dunedin, New Zealand
  2. Department of Medicine, University of Otago,Dunedin, New Zealand
  3. Department of Surgical Science, University of Otago,Dunedin, New Zealand
Institutions: University of Otago (New Zealand)
Journal: Communications medicine, volume 6, issue 1, article 241
Dates: received 7 October 2024; accepted 27 February 2026; published online 10 March 2026
Type: Research article · Language: English
License: CC BY-NC-ND
Identifiers: DOI 10.1038/s43856-026-01518-5 · PMID 41807824 · PMCID PMC13106778 · OpenAlex W7134936701
Open access: gold, a free copy (OpenAlex)
Status: code verified
Categories: human (organism), other condition (population), clinical / translational (subfield)
Methods: Spectral & time-frequency, Connectivity, Statistics, Smoothing, state filtering, decompositions, Machine learning, Preprocessing, fMRI & imaging, Physiology & signal measures
Keywords: Neurology, Predictive markers, Endocrinology
Topic: Transcranial Magnetic Stimulation Studies (Neurology, Neuroscience), according to OpenAlex
Citations: cited by 1 paper (Europe PMC); 93 references in the paper

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 5 matches between paragraphs and lines of code.

yuan410/obesitymeta

License: Apache-2.0
State: the link answers, verified on 30 September 2026
Evidence: files inventoried
Commit: a2b735338c6bbccc8bf4a0cfdd28796904f36c02, 10 October 2025
Languages: Jupyter (1)
Size: 1,445 files, 1 script
Software Heritage: not archived
Found in: “Code availability”
Holds: README, license file, environment (Dockerfile, requirements.txt), 1 notebook
Not found: CITATION.cff, tests, continuous integration, documentation
Tools: imbalanced-learn (1 file), Matplotlib (1 file), NumPy (1 file), pandas (1 file), scikit-learn (1 file), SciPy (1 file), seaborn (1 file), statannotations (1 file), statsmodels (1 file), XGBoost (1 file)
Availability: 1 check, the latest on 30 September 2026: the link answers
  • 30 September 2026: the link answers
3 files

figshare 30351418

License: CC-BY-4.0
State: the link answers, verified on 30 September 2026
Evidence: files inventoried
Languages: Jupyter (1)
Size: 1 file, 1 script
Software Heritage: not checked
Found in: “Code availability”
Holds: 1 notebook
Not found: README, license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: imbalanced-learn (1 file), Matplotlib (1 file), NumPy (1 file), pandas (1 file), scikit-learn (1 file), SciPy (1 file), seaborn (1 file), statannotations (1 file), statsmodels (1 file), XGBoost (1 file)
Availability: 1 check, the latest on 30 September 2026: the link answers (HTTP 200)
  • 30 September 2026: the link answers (HTTP 200)
1 file
At the source:

Code availability statement

The paper has a code availability statement. Its license (CC BY-NC-ND) does not allow reproducing it here; in short, from what the harvester recognized in it:

Read it in the paper: doi.org/10.1038/s43856-026-01518-5.

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;
  • 2 scripts, each with its path and the digest of its content;
  • 5 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

Datasets cited

Data availability statement

The paper has a 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 a dataset: figshare 30351280
  • it says that the data are available on request

Read it in the paper: doi.org/10.1038/s43856-026-01518-5.

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, 30 September 2026: the first record

Recorded: type, language, journal, volume, issue, pages, dates, 8 authors, 3 keywords, 86 references.

Cite

This paper

Yue, Y., Manning, P., De Ridder, D., Hall, M., Adhia, D. B., Ross, S., Alencar da Costa, D., & Deng, J. D. (2026). Machine learning-based identification of abnormal functional connectivity in obesity across different metabolic states. Communications medicine, 6(1), 241. https://doi.org/10.1038/s43856-026-01518-5

BibTeX

@article{yue2026machine,
author = {Yue, Yuan and Manning, Patrick and De Ridder, Dirk and Hall, Matthew and Adhia, Divya Bharatkumar and Ross, Samantha and Alencar da Costa, Daniel and Deng, Jeremiah D.},
title = {{Machine learning-based identification of abnormal functional connectivity in obesity across different metabolic states}},
journal = {Communications medicine},
year = {2026},
month = mar,
volume = {6},
number = {1},
pages = {241},
publisher = {Nature Publishing Group},
issn = {2730-664X},
doi = {10.1038/s43856-026-01518-5},
url = {https://doi.org/10.1038/s43856-026-01518-5},
pmid = {41807824},
pmcid = {PMC13106778}
}

RIS

TY - JOUR
AU - Yue, Yuan
AU - Manning, Patrick
AU - De Ridder, Dirk
AU - Hall, Matthew
AU - Adhia, Divya Bharatkumar
AU - Ross, Samantha
AU - Alencar da Costa, Daniel
AU - Deng, Jeremiah D.
TI - Machine learning-based identification of abnormal functional connectivity in obesity across different metabolic states
T2 - Communications medicine
J2 - Commun Med (Lond)
PY - 2026
DA - 2026/03/10
VL - 6
IS - 1
SP - 241
SN - 2730-664X
PB - Nature Publishing Group
DO - 10.1038/s43856-026-01518-5
UR - https://doi.org/10.1038/s43856-026-01518-5
LA - en
ER -

CSL-JSON

{
"id": "10.1038/s43856-026-01518-5",
"type": "article-journal",
"title": "Machine learning-based identification of abnormal functional connectivity in obesity across different metabolic states",
"container-title": "Communications medicine",
"author": [
{
"family": "Yue",
"given": "Yuan"
},
{
"family": "Manning",
"given": "Patrick"
},
{
"family": "De Ridder",
"given": "Dirk"
},
{
"family": "Hall",
"given": "Matthew"
},
{
"family": "Adhia",
"given": "Divya Bharatkumar"
},
{
"family": "Ross",
"given": "Samantha"
},
{
"family": "Alencar da Costa",
"given": "Daniel"
},
{
"family": "Deng",
"given": "Jeremiah D."
}
],
"container-title-short": "Commun Med (Lond)",
"volume": "6",
"issue": "1",
"page": "241",
"DOI": "10.1038/s43856-026-01518-5",
"PMID": "41807824",
"PMCID": "PMC13106778",
"ISSN": "2730-664X",
"publisher": "Nature Publishing Group",
"URL": "https://doi.org/10.1038/s43856-026-01518-5",
"language": "en",
"issued": {
"date-parts": [
[
2026,
3,
10
]
]
}
}

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.3389/fnins.2026.1803154 [code]
Multimodal machine learning reveals neurobiological signatures of binge-type eating disorders.
Journal: Frontiers in neuroscience
In common: statannotations, XGBoost, statsmodels, 6 other tools, other condition, 2 references
[2] doi:10.1016/j.isci.2026.115329 [code]
Brain metastases converge on shared geometric architecture and transcriptomic landscape yet remain distinct from gliomas.
Journal: iScience
In common: imbalanced-learn, statannotations, XGBoost, 7 other tools, clinical / translational, other condition
[3] doi:10.3390/s26175327 [code]
Subject Identity Confounds qEEG Emotion Recognition on DEAP and DREAMER.
Journal: Sensors (Basel, Switzerland)
In common: imbalanced-learn, XGBoost, statsmodels, 6 other tools, 1 reference
[4] doi:10.1038/s41598-026-64405-y [code]
Evaluating clinical and neuroimaging predictors for cognitive-behavioral therapy outcome in obsessive-compulsive disorder.
Journal: Scientific reports
In common: imbalanced-learn, XGBoost, statsmodels, 6 other tools, clinical / translational, other condition
[5] doi:10.1016/j.nicl.2026.104012 [code]
Structural-functional multilayer brain network properties and outcome of combined repetitive transcranial magnetic stimulation and psychotherapy for obsessive-compulsive disorder.
Journal: NeuroImage. Clinical
In common: imbalanced-learn, XGBoost, statsmodels, 6 other tools, other condition
[6] doi:10.1038/s42003-026-10957-8 [code]
Brain defence by the extracellular matrix protein Cochlin.
Journal: Communications biology
In common: imbalanced-learn, XGBoost, statsmodels, 6 other tools
[7] doi:10.1186/s13059-026-04125-8 [code]
MLMarker: a machine learning framework for tissue inference and biomarker discovery.
Journal: Genome biology
In common: imbalanced-learn, XGBoost, statsmodels, 6 other tools
[8] doi:10.1038/s41598-026-56688-y [code]
On the value of radiomics in addition to clinical measures in emotional conflict fMRI for predicting sertraline response in major depressive disorder.
Journal: Scientific reports
In common: imbalanced-learn, XGBoost, statsmodels, 6 other tools
[9] doi:10.1016/j.isci.2026.116825 [code]
Social hierarchy shapes behavioral and transcriptional responses to chronic stress and ketamine in male mice.
Journal: iScience
In common: imbalanced-learn, XGBoost, statsmodels, 6 other tools
[10] doi:10.7554/elife.108109 [code]
Multimodal MRI marker of cognition explains the association between cognition and mental health in the UK Biobank.
Journal: eLife
In common: seaborn, scikit-learn, pandas, 3 other tools, author Jeremiah D Deng

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.

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.