Exploring the Impact of T2-Weighted MRI Fat Saturation on Radiomics Stability for Brain Radionecrosis Prediction After Skull-Base Proton Therapy: A Pilot Study.
The 10 matches
- [1] § 2. Materials and Methods › 2.2. Brain Tissue Segmentation ↔ src/data_curation/tissue_segmentation_methods.ipynb, lines 145–197 · score 0.68 · tissue segmentation, brain extraction, atropos, ANTsPyNet, synthstrip, mri
- [2] § 2. Materials and Methods › 2.6. Radiomics Modeling ↔ src/brn_prediction/analysis.py, lines 174–259 · score 0.67 · near zero, CCC thresholds, variance, subsets, filtering, predictive
- [3] § 3. Results › 3.2. Radiomics Modeling ↔ src/brn_prediction/analysis.py, lines 263–322 · score 0.64 · homogeneous subgroups, high correlations, CCC thresholded, subsets, signature, sequence
- [4] § 3. Results › 3.2. Radiomics Modeling ↔ src/brn_prediction/analysis.py, lines 174–259 · score 0.62 · CCC thresholds, excellent features, subgroups, subsets, Delong, CI
- [5] § 2. Materials and Methods › 2.3. Image-Level Processing ↔ src/data_curation/tissue_segmentation_methods.ipynb, lines 145–197 · score 0.62 · brain mask, bias correction, ANTs, segmented, intensity
- [6] § 2. Materials and Methods › 2.3. Image-Level Processing ↔ src/stability_analysis/feature_extraction3D.ipynb, lines 314–357 · score 0.62 · binary mask, bias correction, radiomics features, gm, wm, thresholding
- [7] § 2. Materials and Methods › 2.6. Radiomics Modeling ↔ src/brn_prediction/analysis.py, lines 146–170 · score 0.59 · repeated stratified, CV, fold, training, cross, prediction
- [8] § 2. Materials and Methods › 2.6. Radiomics Modeling ↔ src/brn_prediction/analysis.py, lines 324–363 · score 0.52 · weighted matching, Spearman, DeLong, CI, AUC, signatures
- [9] § 2. Materials and Methods › 2.4. Radiomics Feature Extraction and Harmonization ↔ src/stability_analysis/stability_analysis.ipynb, lines 123–168 · score 0.52 · neuroCombat, Combat harmonization, batches, sequences
- [10] § 2. Materials and Methods › 2.2. Brain Tissue Segmentation ↔ src/brn_prediction/feature_gen.py, lines 2–25 · score 0.51 · FSL, FAST, csf, wm, segmentation, brain
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
Python · 384 lines · 17 KB · GPL-3.0 · 5 matches
- #%%
- from sklearn.model_selection import RepeatedStratifiedKFold
- from sklearn.linear_model import LogisticRegression
- from sklearn.ensemble import RandomForestClassifier
- from sklearn.base import clone
- from sklearn.model_selection import cross_val_score, cross_val_predict
- from sklearn.metrics import roc_auc_score
- from sklearn.model_selection import RepeatedStratifiedKFold, LeaveOneOut
- from sklearn.feature_selection import SequentialFeatureSelector
- from boruta import BorutaPy
- from scipy.stats import mannwhitneyu
- from sklearn.preprocessing import StandardScaler
- from sklearn.pipeline import make_pipeline
- from sklearn.decomposition import PCA
- # import neuroCombat as neuroCombat
- from neurocombat_sklearn import CombatModel
- import matplotlib.pyplot as plt
- from scipy.optimize import linear_sum_assignment
- import seaborn as sns
- import os
- import pandas as pd
- import numpy as np
- from MLstatkit import Delong_test
- #%%
- FUP_RADIOMICS_FILE = r"/home/sithints/research/projects/t2w_stability/outputs/stability/radiomicsFeatures3D copy.csv"
- FUP_STABILITY_FILE = r"/home/sithints/research/projects/t2w_stability/outputs/stability/stability_df copy.csv"
- BRN_RADIOMICS_FILE = r"/home/sithints/research/projects/t2w_stability/outputs/brn_prediction/radiomicsFeatures3D copy.csv"
- BRN_DB_FILE = r"/home/sithints/research/projects/t2w_stability/outputs/brn_prediction/db copy.xlsx"
- OUTDIR = r"/home/sithints/research/projects/t2w_stability/outputs/brn_prediction/analysis_5CV"
- os.makedirs(OUTDIR, exist_ok=True)
- FEAT_FAMILIES = ["firstorder", "glcm", "glrlm", "glszm", "ngtdm", "gldm"]
- BIAS = "none"
- ZNORM_ROI = "none"
- TISSUE = "gwm"
- TYPE = "combat"
- CCC_THRESHOLDS = {"baseline":-np.inf, ">=good":0.70, "excellent":0.85}
- TARGET_LABEL = "CTCAE_GRADE_NECROSIS>=1"
- BATCH_COL = "sequence"
- N_SPLITS = 5
- RANDOM_STATE = 42
- def filter_near_zero(df, threshold = 1e-6, verbose=False): #1e-6 and 1e-3 works
- feats = df.columns.to_list()
- feats_var = df.var()
- mask_feats = feats_var[feats_var<=threshold].index.to_list()
- selected_feats = [feat for feat in feats if feat not in mask_feats]
- if verbose:
- print(f"Deleted {len(mask_feats)}/{len(feats)} near zero features, remaining {len(selected_feats)} features")
- return selected_feats
- def filter_high_corr(df, threshold=0.85, verbose=False):
- corr_matrix = df.corr(method='spearman').abs()
- mean_corr = corr_matrix.mean()
- ordered_feats = mean_corr.sort_values(ascending=True).index.to_list()
- corr_matrix = df[ordered_feats].corr(method='spearman').abs()
- up_tri = corr_matrix.where(np.triu(np.ones(corr_matrix.shape), k=1).astype(bool))
- mask_feats = [column for column in up_tri.columns if any(up_tri[column]>=threshold)]
- selected_feats = [feat for feat in ordered_feats if feat not in mask_feats]
- if verbose:
- print(f"Deleted {len(mask_feats)}/{len(ordered_feats)} highly corr features, remaining {len(selected_feats)} features")
- return selected_feats
- def select_topk_utest(X, y, k=5):
- scores = []
- for i in range(X.shape[1]):
- pvalue = mannwhitneyu(X[y==0, i], X[y==1, i], alternative = 'two-sided').pvalue
- scores.append(pvalue)
- selected_idxs = np.argsort(scores)[:k]
- return selected_idxs
- def select_topk_boruta(X, y, k=5):
- rf = RandomForestClassifier(n_jobs=-1, max_depth=5, class_weight="balanced")
- boruta = BorutaPy(estimator=rf, n_estimators='auto', verbose=0, random_state=42)
- boruta.fit(X, y)
- importance_history = boruta.importance_history_
- importance_history = np.nan_to_num(importance_history, 0.0)
- importance = np.mean(importance_history, axis=0)
- selected_idxs = np.argsort(importance)[::-1][:k]
- return selected_idxs
- def mean_weighted_matching_correlation(df_A, df_B, method = 'pearson'):
- """
- Computes the Mean Weighted Matching Correlation (MWMC) between two signatures (feature sets + predictions).
- It solves the linear assignment problem on the cost matrix C = 1 - |corr(A_i, B_j)|
- and returns the mean absolute correlation of the optimal matching.
- """
- # Calculate the pairwise absolute correlation matrix
- combined = pd.concat([df_A, df_B], axis=1)
- corr = combined.corr(method=method).abs()
- # Extract the cross-correlation submatrix (A vs B)
- cols_A = df_A.columns
- cols_B = df_B.columns
- cross_corr = corr.loc[cols_A, cols_B].values
- # Cost matrix is 1 - absolute correlation
- cost_matrix = 1.0 - cross_corr
- # Find the optimal bipartite matching
- row_ind, col_ind = linear_sum_assignment(cost_matrix)
- # Return the mean matched correlation (1 - cost)
- return cross_corr[row_ind, col_ind].mean()
- def visualize_corr_matrix(corr_matrix, title, figsize=(10,8)):
- plt.figure(figsize=figsize)
- sns.heatmap(
- corr_matrix,
- annot=True,
- fmt=".2f",
- cmap="coolwarm",
- vmin=0,
- vmax=1,
- square=True,
- cbar_kws={"shrink": .8}
- )
- plt.title(title, fontsize=12, pad=15)
- plt.xticks(rotation=45, ha='right', fontsize=9)
- plt.yticks(fontsize=9)
- plt.tight_layout()
- os.makedirs(OUTDIR, exist_ok=True)
- plt.savefig(os.path.join(OUTDIR, f"{title}.tiff"), dpi=600, bbox_inches='tight')
- plt.show()
- def cross_val(model, fs_method, num_folds = 5, n_repeats=5, random_state = 42):
- def call_fn(X_df, y_df):
- cv = RepeatedStratifiedKFold(n_splits=num_folds, n_repeats=n_repeats, random_state=random_state) # LeaveOneOut()
- y_preds, y_trues = [], []
- X, y = X_df.values, y_df.values
- for train_idx, test_idx in cv.split(X, y):
- X_train, X_test = X[train_idx], X[test_idx]
- y_train, y_test = y[train_idx], y[test_idx]
- train_selected_idxs = fs_method(X_train, y_train, k=k)
- X_train_selected = X_train[:, train_selected_idxs]
- X_test_selected = X_test[:, train_selected_idxs]
- y_pred = clone(model).fit(X_train_selected, y_train).predict_proba(X_test_selected)[:, 1]
- y_preds.append(y_pred)
- y_trues.append(y_test)
- y_true = np.concatenate(y_trues)
- y_pred = np.concatenate(y_preds)
- return y_true, y_pred
- return call_fn
- combined_signatures = {}
- # %%
- # Heterogeneous (Mixed-FS) Subgroups Analysis
- if __name__=="__main__":
- fs_method = select_topk_utest
- fup_radiomics_df = pd.read_csv(FUP_RADIOMICS_FILE, index_col=0)
- fup_radiomics_df = fup_radiomics_df[(fup_radiomics_df.tissue==TISSUE)&(fup_radiomics_df.bias_correction==BIAS)&(fup_radiomics_df.norm_roi==ZNORM_ROI)].copy().reset_index(drop=True)
- features = [feat for feat in fup_radiomics_df.columns for family in FEAT_FAMILIES if family in feat.lower()]
- # Combat parameters are learned from follow-up data used for stability study
- combat = CombatModel()
- variances = fup_radiomics_df[features].copy().var()
- zero_var_feats = variances[variances == 0].index
- nzvar_features = [feat for feat in features if feat not in zero_var_feats]
- combat.fit(data = fup_radiomics_df[nzvar_features].values, sites = fup_radiomics_df[[BATCH_COL]].apply(lambda x: x.astype('category').cat.codes).values)
- radiomics_df = pd.read_csv(BRN_RADIOMICS_FILE)[["pid", "sequence", "exclude"]+features]
- db = pd.read_excel(BRN_DB_FILE)[["ID", "CTCAE GRADE NECROSIS2"]]
- db = db.rename(columns={"ID":"pid"})
- radiomics_df = radiomics_df.merge(db, on="pid").reset_index(drop=True)
- radiomics_df["CTCAE_GRADE_NECROSIS"] = radiomics_df["CTCAE GRADE NECROSIS2"].fillna(0)
- radiomics_df[TARGET_LABEL] = (radiomics_df["CTCAE_GRADE_NECROSIS"]>=1).astype(int)
- radiomics_df = radiomics_df.dropna(subset=features, inplace=False)
- radiomics_df = radiomics_df[radiomics_df.exclude==0].reset_index(drop=True)
- stability_df = pd.read_csv(FUP_STABILITY_FILE)
- stability_df = stability_df[(stability_df.bias_correction==BIAS)&(stability_df.normalization==ZNORM_ROI)&(stability_df.tissue==TISSUE)&(stability_df.type==TYPE)]
- ## Performance Analysis on the heterogenous data
- estimator = make_pipeline(StandardScaler(), LogisticRegression(C=np.inf, random_state = 42)) #no penalty
- k = 4
- outputs = {}
- print(f"\nTarget label: {TARGET_LABEL} (prevalance= {len(radiomics_df[radiomics_df[TARGET_LABEL]==1])} / {len(radiomics_df)} = {radiomics_df[TARGET_LABEL].mean():.3f})")
- for ccc_stability, ccc_threshold in CCC_THRESHOLDS.items():
- print(f"\tCCC threshold: {ccc_stability}")
- combat_data_df = radiomics_df.copy().reset_index(drop=True)
- # transforming mixed-FS baseline features using Combat parameters learned from the stability study
- combat_data_df[nzvar_features] = combat.transform(data = combat_data_df[nzvar_features].values, sites = combat_data_df[[BATCH_COL]].apply(lambda x: x.astype('category').cat.codes).values)
- columns = stability_df[stability_df.ccc>=ccc_threshold].feature.to_list()
- stable_features = [feat for feat in columns if feat in features]
- print(f"\t\t# stable features = {len(stable_features)}")
- filtered_features = filter_near_zero(combat_data_df[stable_features])
- filtered_features = filter_high_corr(combat_data_df[filtered_features])
- print(f"\t\t# filtered features = {len(filtered_features)}")
- X_df = combat_data_df[filtered_features].copy().reset_index(drop=True)
- y_df = combat_data_df[TARGET_LABEL].copy().reset_index(drop=True)
- selected_idxs = fs_method(X_df.values, y_df.values, k=k)
- selected_features = X_df.iloc[:, selected_idxs].columns.to_list()
- combined_signatures[("fs + non-fs", ccc_stability)] = selected_features
- y_trues, y_preds = cross_val(estimator, fs_method, N_SPLITS, RANDOM_STATE)(X_df, y_df)
- _, _, ci, _, auc, _, info = Delong_test(y_trues, y_preds, y_preds, return_ci=True, return_auc=True, verbose = 0)
- utest_p = mannwhitneyu(y_preds[y_trues==0], y_preds[y_trues==1], alternative = 'two-sided').pvalue
- print(f"\t\t\t {estimator[-1].__class__.__name__}: AUC={auc:.3f} [{ci[0]:.3f}-{ci[1]:.3f}], p = {utest_p:.3f}")
- outputs[ccc_stability] = {"y_trues":y_trues, "y_preds":y_preds}
- # Delong's test between baseline vs. excellent features; good vs. excellent features
- y_trues = outputs[">=good"]["y_trues"]
- y_preds_baseline = outputs["baseline"]["y_preds"]
- y_preds_good = outputs[">=good"]["y_preds"]
- y_preds_excellent = outputs["excellent"]["y_preds"]
- _, p_value = Delong_test(y_trues, y_preds_baseline, y_preds_excellent, return_ci=False, return_auc=False, verbose = 0)
- print(f"Delong's test between baseline and excellent features: p_value={p_value:.3f}")
- _, p_value = Delong_test(y_trues, y_preds_good, y_preds_excellent, return_ci=False, return_auc=False, verbose = 0)
- print(f"Delong's test between >=good and excellent features: p_value={p_value:.3f}")
- #%%
- # Homogeneous subgroups (FS-only vs. non-FS only) analysis
- if __name__=="__main__":
- fs_method = select_topk_utest
- fup_radiomics_df = pd.read_csv(FUP_RADIOMICS_FILE, index_col=0)
- fup_radiomics_df = fup_radiomics_df[(fup_radiomics_df.tissue==TISSUE)&(fup_radiomics_df.bias_correction==BIAS)&(fup_radiomics_df.norm_roi==ZNORM_ROI)].reset_index(drop=True)
- features = [feat for feat in fup_radiomics_df.columns for family in FEAT_FAMILIES if family in feat.lower()]
- radiomics_df = pd.read_csv(BRN_RADIOMICS_FILE)[["pid", "sequence", "exclude"]+features]
- db = pd.read_excel(BRN_DB_FILE)[["ID", "CTCAE GRADE NECROSIS2"]]
- db = db.rename(columns={"ID":"pid"})
- radiomics_df = radiomics_df.merge(db, on="pid").reset_index(drop=True)
- radiomics_df["CTCAE_GRADE_NECROSIS"] = radiomics_df["CTCAE GRADE NECROSIS2"].fillna(0)
- radiomics_df[TARGET_LABEL] = (radiomics_df["CTCAE_GRADE_NECROSIS"]>=1).astype(int)
- radiomics_df = radiomics_df.dropna(subset=features, inplace=False)
- grp_radiomics_df = radiomics_df.groupby(by=["pid"]).agg(list).reset_index()
- pids_with_both_sequences = grp_radiomics_df[grp_radiomics_df.sequence.apply(lambda x: len(x)==2)].pid.to_list()
- radiomics_df = radiomics_df[radiomics_df.pid.isin(pids_with_both_sequences)].reset_index(drop=True)
- stability_df = pd.read_csv(FUP_STABILITY_FILE)
- stability_df = stability_df[(stability_df.bias_correction==BIAS)&(stability_df.normalization==ZNORM_ROI)&(stability_df.tissue==TISSUE)&(stability_df.type==TYPE)]
- estimator = make_pipeline(StandardScaler(), LogisticRegression(C=np.inf, random_state = 42)) #no penalty
- k = 2
- outputs = {}
- for sequence in ["t2w_fs", "t2w_nfs"]:
- print(f"\n**Homogeneous Subgroups: Sequence = {sequence}**")
- data_df = radiomics_df[(radiomics_df["sequence"]==sequence)].copy().reset_index(drop=True)
- print(f"\nTarget label: {TARGET_LABEL} (prevalance= {len(data_df[data_df[TARGET_LABEL]==1])} / {len(data_df)} = {data_df[TARGET_LABEL].mean():.3f})")
- for ccc_stability, ccc_threshold in CCC_THRESHOLDS.items():
- print(f"\tCCC threshold: {ccc_stability}")
- columns = stability_df[stability_df.ccc>=ccc_threshold].feature.to_list()
- stable_features = [feat for feat in columns if feat in features]
- print(f"\t\t# stable features = {len(stable_features)}")
- filtered_features = filter_near_zero(data_df[stable_features])
- filtered_features = filter_high_corr(data_df[filtered_features])
- print(f"\t\t# filtered features = {len(filtered_features)}")
- X_df = data_df[filtered_features].copy().reset_index(drop=True)
- y_df = data_df[TARGET_LABEL].copy().reset_index(drop=True)
- selected_idxs = fs_method(X_df.values, y_df.values, k=k)
- selected_features = X_df.iloc[:, selected_idxs].columns.to_list()
- combined_signatures[(sequence, ccc_stability)] = selected_features
- y_trues, y_preds = cross_val(estimator, fs_method, N_SPLITS, RANDOM_STATE)(X_df, y_df)
- _, _, ci, _, auc, _, info = Delong_test(y_trues, y_preds, y_preds, return_ci=True, return_auc=True, verbose = 0)
- utest_p = mannwhitneyu(y_preds[y_trues==0], y_preds[y_trues==1], alternative = 'two-sided').pvalue
- print(f"\t\t\t {estimator[-1].__class__.__name__}: AUC={auc:.3f} [{ci[0]:.3f}-{ci[1]:.3f}], p = {utest_p:.3f}")
- outputs[(sequence, ccc_stability)] = {"y_trues":y_trues, "y_preds":y_preds}
- y_trues = outputs[(sequence, ">=good")]["y_trues"]
- y_preds_baseline = outputs[(sequence, "baseline")]["y_preds"]
- y_preds_good = outputs[(sequence, ">=good")]["y_preds"]
- y_preds_excellent = outputs[(sequence, "excellent")]["y_preds"]
- _, p_value = Delong_test(y_trues, y_preds_baseline, y_preds_excellent, return_ci=False, return_auc=False, verbose = 0)
- print(f"\t\tDelong's test between baseline and excellent features: p_value={p_value:.3f}")
- _, p_value = Delong_test(y_trues, y_preds_good, y_preds_excellent, return_ci=False, return_auc=False, verbose = 0)
- print(f"\t\tDelong's test between >=good and excellent features: p_value={p_value:.3f}")
- y_trues = outputs[("t2w_fs", "excellent")]["y_trues"]
- y_preds_fs = outputs[("t2w_fs", "excellent")]["y_preds"]
- y_preds_nfs = outputs[("t2w_nfs", "excellent")]["y_preds"]
- _, p_value = Delong_test(y_trues, y_preds_fs, y_preds_nfs, return_ci=False, return_auc=False, verbose = 0)
- print(f"Delong's test between excellent fs and nfs features: p_value={p_value:.3f}")
- config_names = list(combined_signatures.keys())
- n_configs = len(config_names)
- pearson_mwmc_matrix = pd.DataFrame(np.zeros((n_configs, n_configs)), index=config_names, columns=config_names)
- spearman_mwmc_matrix = pd.DataFrame(np.zeros((n_configs, n_configs)), index=config_names, columns=config_names)
- for i in range(n_configs):
- for j in range(n_configs):
- name_A = config_names[i]
- name_B = config_names[j]
- pearson_mwmc_matrix.iloc[i, j] = mean_weighted_matching_correlation(radiomics_df[combined_signatures[name_A]], radiomics_df[combined_signatures[name_B]], method='pearson')
- spearman_mwmc_matrix.iloc[i, j] = mean_weighted_matching_correlation(radiomics_df[combined_signatures[name_A]], radiomics_df[combined_signatures[name_B]], method='spearman')
- for method, matrix in {"pearson":pearson_mwmc_matrix, "spearman":spearman_mwmc_matrix}.items():
- visualize_corr_matrix(matrix, method.capitalize() + " Correlation Matrix")
- # %%
- print(combined_signatures)
- '''
- {('t2w_fs', 'baseline'): ['wavelet-HLH_glcm_InverseVariance',
- 'lbp-3D-k_firstorder_10Percentile'],
- ('t2w_fs', '>=good'): ['lbp-3D-k_firstorder_10Percentile',
- 'wavelet-LHL_ngtdm_Strength'],
- ('t2w_fs', 'excellent'): ['lbp-3D-k_firstorder_10Percentile',
- 'wavelet-LHL_ngtdm_Strength'],
- ('t2w_nfs', 'baseline'): ['wavelet-LLL_glszm_LargeAreaHighGrayLevelEmphasis',
- 'lbp-3D-k_firstorder_10Percentile'],
- ('t2w_nfs', '>=good'): ['original_glszm_LargeAreaHighGrayLevelEmphasis',
- 'lbp-3D-k_firstorder_10Percentile'],
- ('t2w_nfs', 'excellent'): ['wavelet-LLH_gldm_GrayLevelNonUniformity',
- 'original_glszm_ZoneVariance']}
- '''
analysis.py at commit db60fad, under GPL-3.0 · at the source
Overview
- Clinical and Scientific Department, CNAO National Center for Oncological Hadrontherapy, 27100 Pavia, Italy
- Radiology Unit, Clinical and Scientific Department, CNAO National Center for Oncological Hadrontherapy, 27100 Pavia, Italy
- Radiation Oncology Unit, Clinical and Scientific Department, CNAO National Center for Oncological Hadrontherapy, 27100 Pavia, Italy
- Department of Internal Medicine and Therapeutics, University of Pavia, 27100 Pavia, Italy
- Department of Clinical, Surgical, Diagnostic, and Pediatric Sciences, University of Pavia, 27100 Pavia, Italy
- Department of Electronics, Information and Bioengineering (DEIB), Politecnico di Milano, 20133 Milan, Italy
- Medical Physics Unit, Clinical and Scientific Department, CNAO National Center for Oncological Hadrontherapy, 27100 Pavia, Italy
- Bioengineering Unit, Clinical and Scientific Department, CNAO National Center for Oncological Hadrontherapy, 27100 Pavia, Italy
- Radiology Institute, Fondazione IRCCS Policlinico San Matteo, 27100 Pavia, Italy
Abstract
Background/
Reproduced under the paper's license (CC BY), from the paper cited above.
Repository
Its files are read in the Code ↔ Paper reader above, with 10 matches between paragraphs and lines of code.
sithin-cnao/t2w_stability
db60fadafcc63a6005565731eebea9dc32b1c299, 21 August 2026Availability: 1 check, the latest on 27 September 2026: the link answers
- 27 September 2026: the link answers
17 files
- src/
brn_prediction/ , Python, 384 lines, 5 matchesanalysis.py - src/
brn_prediction/ , Python, 140 linesdata_prep.py - src/
brn_prediction/ , Python, 67 lines, 1 matchfeature_gen.py - src/
brn_prediction/ , Python, 70 linesmask_gen.py - src/
brn_prediction/ , Python, 124 linesutils.py - src/
data_curation/ , Python, 1,527 linesgui.py - src/
data_curation/ , Jupyter, 193 linesmask_curation.ipynb - src/
data_curation/ , Python, 141 linesregistration_gui.py - src/
data_curation/ , Jupyter, 298 lines, 2 matchestissue_segmentation_meth ods.ipynb - src/
stability_analysis/ , Python, 201 linesconfig_analysis.py - src/
stability_analysis/ , Jupyter, 381 lines, 1 matchfeature_extraction3D.ipy nb - src/
stability_analysis/ , Python, 1,527 linesgui.py - src/
stability_analysis/ , Python, 141 linesregistration_gui.py - src/
stability_analysis/ , Jupyter, 175 lines, 1 matchstability_analysis.ipynb - src/
stability_analysis/ , Python, 121 linesutils.py - LICENSE, License, 674 lines
- README.md, Text, 54 lines
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:
- 1 repository of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
- 15 scripts, each with its path and the digest of its content;
- 10 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.
Data Availability Statement
The raw data supporting the conclusions of this article will be made available by the authors upon reasonable request.
Reproduced under the paper's license (CC BY), from the paper cited above.
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, 12 authors, 6 keywords, 1 funder, 54 references.
Cite
This paper
Thulasi Seetha, S., Fontana, G., Imparato, S., Lillo, S., Ciccone, L. P., Achilli, M. F., Paganelli, C., Molinelli, S., Iannalfi, A., Baroni, G., Preda, L., & Orlandi, E. (2026). Exploring the Impact of T2-Weighted MRI Fat Saturation on Radiomics Stability for Brain Radionecrosis Prediction After Skull-Base Proton Therapy: A Pilot Study. Cancers, 18(16), 2636. https://
BibTeX
@article{thulasiseetha20
author = {Thulasi Seetha, Sithin and Fontana, Giulia and Imparato, Sara and Lillo, Sara and Ciccone, Lucia Pia and Achilli, Marina Francesca and Paganelli, Chiara and Molinelli, Silvia and Iannalfi, Alberto and Baroni, Guido and Preda, Lorenzo and Orlandi, Ester},
title = {{Exploring the Impact of T2-Weighted MRI Fat Saturation on Radiomics Stability for Brain Radionecrosis Prediction After Skull-Base Proton Therapy: A Pilot Study}},
journal = {Cancers},
year = {2026},
month = aug,
volume = {18},
number = {16},
pages = {2636},
publisher = {Multidisciplinary Digital Publishing Institute (MDPI)},
issn = {2072-6694},
doi = {10.3390/
url = {https://
pmid = {42649948},
pmcid = {PMC13511151}
}
RIS
TY - JOUR
AU - Thulasi Seetha, Sithin
AU - Fontana, Giulia
AU - Imparato, Sara
AU - Lillo, Sara
AU - Ciccone, Lucia Pia
AU - Achilli, Marina Francesca
AU - Paganelli, Chiara
AU - Molinelli, Silvia
AU - Iannalfi, Alberto
AU - Baroni, Guido
AU - Preda, Lorenzo
AU - Orlandi, Ester
TI - Exploring the Impact of T2-Weighted MRI Fat Saturation on Radiomics Stability for Brain Radionecrosis Prediction After Skull-Base Proton Therapy: A Pilot Study
T2 - Cancers
J2 - Cancers (Basel)
PY - 2026
DA - 2026/
VL - 18
IS - 16
SP - 2636
SN - 2072-6694
PB - Multidisciplinary Digital Publishing Institute (MDPI)
DO - 10.3390/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.3390/
"type": "article-journal",
"title": "Exploring the Impact of T2-Weighted MRI Fat Saturation on Radiomics Stability for Brain Radionecrosis Prediction After Skull-Base Proton Therapy: A Pilot Study",
"container-title": "Cancers",
"author": [
{
"family": "Thulasi Seetha",
"given": "Sithin"
},
{
"family": "Fontana",
"given": "Giulia"
},
{
"family": "Imparato",
"given": "Sara"
},
{
"family": "Lillo",
"given": "Sara"
},
{
"family": "Ciccone",
"given": "Lucia Pia"
},
{
"family": "Achilli",
"given": "Marina Francesca"
},
{
"family": "Paganelli",
"given": "Chiara"
},
{
"family": "Molinelli",
"given": "Silvia"
},
{
"family": "Iannalfi",
"given": "Alberto"
},
{
"family": "Baroni",
"given": "Guido"
},
{
"family": "Preda",
"given": "Lorenzo"
},
{
"family": "Orlandi",
"given": "Ester"
}
],
"container-title-short":
"volume": "18",
"issue": "16",
"page": "2636",
"DOI": "10.3390/
"PMID": "42649948",
"PMCID": "PMC13511151",
"ISSN": "2072-6694",
"publisher": "Multidisciplinary Digital Publishing Institute (MDPI)",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
8,
15
]
]
}
}
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/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 reportsIn common: PyRadiomics, pydicom, FSL, 7 other tools, 1 reference
- [2] doi:10.1371/journal.pcbi.1014555 [code]
- Body surface potential driven personalisation of electrophysiological digital twins in hypertrophic cardiomyopathy.Journal: PLoS computational biologyIn common: PyRadiomics, pydicom, SimpleITK, 7 other tools, structural MRI / diffusion
- [3] doi:10.1002/alz.71649 [code]
- Postmortem brain MRI reveals differential associations of subcortical and limbic volumes with cortical thinning and neurodegenerative pathologies.Journal: Alzheimer's & dementia : the journal of the Alzheimer's AssociationIn common: SimpleITK, ANTs, FreeSurfer, 8 other tools, structural MRI / diffusion
- [4] doi:10.1371/journal.pone.0337726 [code]
- Classification of chronic pain and spinal cord stimulation response using machine learning in magnetoencephalography dataJournal: n/aIn common: PyRadiomics, neuroCombat, pydicom, 6 other tools
- [5] doi:10.1038/s41586-026-10631-3 [code]
- A prognostic human brain network for diffuse midline glioma.Journal: NatureIn common: pydicom, ANTs, FreeSurfer, 7 other tools, clinical / translational, 1 reference
- [6] doi:10.1038/s41598-026-55397-w [code]
- Fast surface reconstruction of human brain MRI: benchmarking deep-learning based morphometry tools.Journal: Scientific reportsIn common: PyRadiomics, SimpleITK, ANTs, 5 other tools, structural MRI / diffusion, 1 reference
- [7] doi:10.1162/netn.a.547 [code]
- An evaluation of the efficacy of single-echo and multi-echo fMRI denoising strategies.Journal: Network neuroscience (Cambridge, Mass.)In common: ANTs, FreeSurfer, FSL, 7 other tools, 1 reference
- [8] doi:10.1371/journal.pbio.3003856 [code]
- Aging and metabolism contribute separately to brain-body health.Journal: PLoS biologyIn common: ANTs, FreeSurfer, FSL, 7 other tools, structural MRI / diffusion, clinical / translational
- [9] doi:10.1038/s41467-026-71555-0 [code]
- A deep representation learning model to predict response to vagus nerve stimulation.Journal: Nature communicationsIn common: ANTs, FreeSurfer, FSL, 6 other tools, structural MRI / diffusion, clinical / translational, 1 reference
- [10] doi:10.64898/2026.08.18.26360725 [code]
- Temporal pole blurring in hippocampal sclerosis reflects seizure-disrupted myelinationJournal: medRxiv (preprint)In common: neuroCombat, FreeSurfer, statsmodels, 6 other tools, structural MRI / diffusion, 1 reference
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: 1 repository of the authors' code, each at its verified commit and with its license, 15 scripts, and 10 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:4f548e6cc4c9e5d5…
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.
