Personalized machine learning-guided radiation dose escalation in newly diagnosed glioblastoma: prospective pilot study.
The 5 matches
- [1] § Methods › Statistical analysis ↔ statistical_analysis/qc_and_os_analysis.qmd, lines 427–500 · score 0.87 · Cox proportional hazards, propensity score, PPRT intervention, MatchIt, nearest, wildtype
- [2] § Results › Overall survival outcomes ↔ statistical_analysis/qc_and_os_analysis.qmd, lines 427–500 · score 0.87 · proportional hazards assumption, Cox proportional hazards, Schoenfeld residuals, underwent PPRT intervention, 0.17–0.69, PH
- [3] § Results › Progression-free survival ↔ statistical_analysis/pfs_analysis.qmd, lines 202–269 · score 0.87 · Kaplan Meier, Cox proportional hazards, slower progression, log rank, robust standard errors, 0.13–0.61
- [4] § Methods › Propensity matched historical control group ↔ statistical_analysis/qc_and_os_analysis.qmd, lines 238–295 · score 0.70 · greedy nearest neighbor, MGMTp methylation status, propensity score, age, sex, variables
- [5] § Methods › Study design ↔ statistical_analysis/pfs_analysis.qmd, lines 53–118 · score 0.54 · progression free survival, disease progression, PFS, surgery, events, Status
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
Quarto · 502 lines · 21 KB · no license · 3 matches
- ---
- title: "PPRT Survival Analysis"
- description: "To evaluate if there is a significant difference in **overall** survival between the PPRT intervention and control group"
- date: last-modified
- date-format: "[Last Updated:] MMM DD, YYYY"
- format:
- html:
- self-contained: true
- title-block-banner: true
- title-block-banner-color: "#FFFFFF"
- toc: true
- toc-location: left
- number-sections: true
- code-fold: true
- code-tools:
- source: true #hide the source option
- toggle: true
- code-copy: true #option to copy code
- code-overflow: scroll
- df-print: kable
- code-block-bg: true
- code-block-border-left: "#31BAE9"
- editor: source #open in source editor by default
- theme: flatly
- echo: false
- execute:
- warning: false
- message: false
- ---
- # ------------------------------------------------------------------
- # NOTE: Patient identifiers have been removed for privacy.
- # Any identifiers appearing in the original analysis have been
- # replaced with "XXXX" in this shared version of the script.
- # This does not affect analytic results.
- # ------------------------------------------------------------------
- ```{r load_packages}
- #| label: load-packages
- #| include: false
- # Remove environment to avoid potential errors or conflicts
- rm(list = ls())
- library(tidyverse) #data wrangling, viz
- library(readxl) #reading excel sheets
- library(gtsummary) #for creating table 1
- library(DT) # for datatables
- library(survival) #for survival analysis
- library(survminer) #for visualizing kaplan-meier plots
- library(tab) #for generating tables for statistical reports
- library(lubridate) #date manipulation
- library(MatchIt) #for PSM matching
- library(lmtest)
- library(sandwich)
- library(writexl)
- library(geepack) #for GEE
- ```
- ```{r intervention}
- #updated survival data as of 03/20/25
- intervention <- read_excel("/Volumes/TOSHIBA/work_mac/Documents/collab_yr2/Hamed_SNO_0524/july24/ACC_Trial_11_20_2024_To_Amy.xlsx", sheet = 2) %>%
- janitor::clean_names() %>%
- mutate(survival_all = if_else(alive == "n", survival, survival_till_3_20_2025)) %>%
- mutate(survival_all = survival) %>%
- mutate(year = factor(year(dos))) %>%
- filter(is.na(remove) | remove != "Optune device") %>% #remove optune devices (tumor treating fields)
- select(cbicaid_preop, age, sex, alive, survival_all, mgmt, year) %>%
- rename(survival = survival_all) %>%
- mutate(group = "intervention") %>%
- #mutate(baseline_id = "000")
- mutate(baseline_id = cbicaid_preop) %>%
- select(age:baseline_id)
- ```
- ```{r selected_controls}
- ## control subjects that were QCed previously who meet the criterion
- sel_controls <- read_excel("/Volumes/TOSHIBA/work_mac/Documents/collab_yr2/Hamed_SNO_0524/july24/20240812_ACC_clinical.xlsx", sheet = 2) %>%
- janitor::clean_names() %>%
- filter(is.na(remove)) %>% #Remove the patients that did not meet the inclusion criteria
- pull(baseline_id) %>%
- unique()
- sept_alive <- read_excel("/Volumes/TOSHIBA/work_mac/Documents/collab_yr2/Hamed_SNO_0524/july24/potential_controls_9_9_2024_To Amy.xlsx", sheet = 2) %>%
- janitor::clean_names() %>%
- filter(is.na(remove)) %>% #N=23 patients did not meet the inclusion criteria
- pull(baseline_id) %>%
- unique()
- selected_controls <- c(sel_controls, sept_alive)
- #remove 8 patients from the list of selected controls that does not meet inclusion criteria based on quality cont
- remove_from_ctrl <- c("XXXX", "XXXX",
- "XXXX", "XXXX",
- "XXXX", "XXXX",
- "XXXX", "XXXX")
- selected_controls <- selected_controls[!selected_controls %in% remove_from_ctrl]
- #remove interim objects to avoid workplace confusion
- rm(sel_controls, sept_alive)
- ```
- ## Identify all the control subjects that should be removed (i.e., does not meet criterion)
- ```{r remove}
- ## Iteration 1; the n=5 patients that we needed to remove
- ctr_rm <- c("XXXX",
- "XXXX",
- "XXXX",
- "XXXX",
- "XXXX")
- ## Iteration 2; n=15 subjects that did not meet the inclusion criteria
- need_to_remove <- read_excel("/Volumes/TOSHIBA/work_mac/Documents/collab_yr2/Hamed_SNO_0524/Control_Group_17_June2024_REMOVE.xlsx", sheet = "sheet2") %>%
- janitor::clean_names() %>%
- filter(remove == "Yes") %>% #N=15 patients did not meet the inclusion criteria
- pull(baseline_id)
- ## Iteration 3; additional n=8 subjects that we need to remove
- need_to_remove_july <- read_excel("/Volumes/TOSHIBA/work_mac/Documents/collab_yr2/Hamed_SNO_0524/july24/07022024_ACC_clinical_REMOVE.xlsx", sheet = "sheet2") %>%
- janitor::clean_names() %>%
- filter(remove == "Yes") %>%
- pull(baseline_id)
- ## Iteration 4;
- need_to_remove_august <- read_excel("/Volumes/TOSHIBA/work_mac/Documents/collab_yr2/Hamed_SNO_0524/july24/20240812_ACC_clinical.xlsx", sheet = 2) %>%
- janitor::clean_names() %>%
- filter(remove == "yes") %>%
- pull(baseline_id)
- ## Iteration 5
- need_to_remove_september <- read_excel("/Volumes/TOSHIBA/work_mac/Documents/collab_yr2/Hamed_SNO_0524/july24/potential_controls_9_9_2024_To Amy.xlsx", sheet = 2) %>%
- janitor::clean_names() %>%
- filter(remove == "yes") %>% #N=23 patients did not meet the inclusion criteria
- pull(baseline_id)
- # `remove` contains a list of ids that should not be used as potential controls since criteria not meet
- remove <- c(ctr_rm, need_to_remove, need_to_remove_july,
- need_to_remove_august, need_to_remove_september,
- remove_from_ctrl) %>% unique()
- rm(ctr_rm, need_to_remove, need_to_remove_july, need_to_remove_august, need_to_remove_september)
- ```
- ## Qualified controls after QC
- ```{r cntrls_combined}
- ## This is the old list of "qualified controls" that meet the inclusion criteria
- # idh is wildtype; eor is GTR, survival > 90 days, methylated or unmethylated group
- qualified_cntr_old <- read_excel("/Volumes/TOSHIBA/work_mac/Documents/collaborator_projects/Hamed_ACC/UPenn.xlsx") %>%
- janitor::clean_names() %>%
- mutate(across(baseline_id:alive, ~str_sub(., 2, -2))) %>%
- mutate(across(rec:kps, ~str_sub(., 2, -2))) %>%
- filter(idh == "Wildtype" & eor == "GTR") %>%
- filter(survival >= 90) %>% #exclude patients who passed away before completing radiation therapy
- mutate(group = "control") %>% #create a control variable
- mutate(year = factor(str_sub(baseline_id, 6,9))) %>%
- filter(mgmt %in% c("Methylated", "Unmethylated")) %>%
- mutate(age = as.numeric(age)) %>%
- select(age, sex, alive, survival, mgmt, year, group, baseline_id)
- #### CURRENT CONTROL###
- # note: "Positive" ="Methylated"; "Not Detected" = "Unmethylated"
- # Control group
- # exclude patients who passed away before completing radiation therapy (approximately 90 days)
- # list of qualified control patients that are DECEASED
- control_new_deceased <- read_excel("/Volumes/TOSHIBA/work_mac/Documents/collab_yr2/Hamed_SNO_0524/potential_control_patients.xlsx", sheet = 1) %>%
- janitor::clean_names() %>%
- filter(deceased == "yes") %>% #only look at deceased patients for now
- filter(idh == "Wildtype" & eor == 3) %>% #EOR of 3 is GTR
- mutate(mgmt = if_else(mgmt %in% c("positive", "Positive"),
- "Methylated", "Unmethylated")) %>%
- filter(survival >= 90) %>%
- mutate(group = "control") %>% #create indicator variable
- mutate(year = factor(str_sub(baseline_id, 6,9))) %>%
- mutate(alive = if_else(deceased == "yes", "n", "y")) %>%
- select(age, sex, alive, survival, mgmt, year, group, baseline_id)
- # list of control patients that were still ALIVE
- control_new_alive <- read_excel("/Volumes/TOSHIBA/work_mac/Documents/collab_yr2/Hamed_SNO_0524/potential_control_patients.xlsx",
- sheet = 1) %>%
- janitor::clean_names() %>%
- filter(is.na(deceased)) %>% #look at alive patients
- filter(idh == "Wildtype" & eor == 3) %>% #EOR of 3 is GTR
- mutate(mgmt = if_else(mgmt %in% c("positive", "Positive"),
- "Methylated", "Unmethylated")) %>%
- #filter(mgmt == "Methylated") %>% ## ONLY look at the methylated patients
- mutate(group = "control") %>% #create indicator variable
- mutate(year = factor(str_sub(baseline_id, 6,9))) %>%
- # mutate(alive = if_else(deceased == "yes", "n", "y")) %>%
- mutate(alive = "y") %>%
- select(age, sex, alive, survival, mgmt, year, group, baseline_id)
- ####### combine all the controls from above and remove the unqualified lesions #########
- cntrls_combined <- rbind(qualified_cntr_old, control_new_deceased, control_new_alive) %>%
- filter(!baseline_id %in% remove)
- rm(qualified_cntr_old, control_new_deceased, control_new_alive)
- ```
- ## Combine intervention and control data (comp_data)
- ```{r comp_data, eval=T}
- set.seed(123)
- # NOTE: qualifed controls contains remaining controls that meet the diagnostic criteria, after subtracting the list of previously QC'ed controls
- cntrls_qualified <- cntrls_combined %>%
- filter(!baseline_id %in% selected_controls) %>%
- slice_sample(prop = 0)
- # The final control subjects list inlcude qualified controls from previous iterations and new patients
- control <- rbind(cntrls_combined %>% filter(baseline_id %in% selected_controls),
- cntrls_qualified) %>%
- mutate(survival = case_when(
- is.na(survival) & baseline_id == "XXXX" ~ 1070,
- is.na(survival) & baseline_id == "XXXX" ~ 650,
- is.na(survival) & baseline_id == "XXXX" ~ 530,
- is.na(survival) & baseline_id == "XXXX" ~ 647,
- TRUE ~ survival
- ))
- #NOTE: look at `potential_controls_9_9_2024_To Amy.xlsx` sheet3 to see how to obtain the survival #'s above. Briefly, we calculated the # of days between baseline date and the date of last follow-up (the survival status is unknown for these patients).
- #remove from workspace to avoid confusion
- rm(cntrls_combined, cntrls_qualified)
- ```
- ```{r}
- ######### COMBINE INTERVENTION AND CONTROL DATA to create final data frame #######
- comp_data <- rbind(intervention, control) %>%
- mutate(status = if_else(alive == "y", 0, 1)) #0=alive; 1=dead
- ```
- ::: callout-tip
- ## Note
- Currently we have n=17 patients in the intervention group and we want to match each subject to 4 controls; thus, we should have 17x4=68 control subjects.
- :::
- ---
- ## Check if data is balanced after matching (Table 1)
- The propensity score were estimated using logistic regression based on age, sex, and MGMTp methylation status. All subjects in the intervention group were matched to 4 control subjects who did not have PPRT using one-to-four nearest neighbour matching.
- In matchit(), setting method = "nearest" performs greedy nearest neighbor matching. A distance is computed between each treated unit and each control unit, and, one by one, each treated unit is assigned a control unit as a match. The matching is "greedy" in the sense that there is no action taken to optimize an overall criterion; each match is selected without considering the other matches that may occur subsequently.
- ```{r PSM}
- # matchit create treatment and control groups balanced on included covariates
- match_obj <- matchit(factor(group) ~ age + sex + mgmt,
- data = comp_data,
- method = "nearest",
- distance ="glm",
- ratio = 4, #how many control units should be matched to each treated unit in k:1 matching
- replace = F) #control units can only be matched to ONE treated unit each
- #check if data is balanced between control and intervention group
- check_balance <- summary(match_obj)
- check_balance[["sum.matched"]] %>% data.frame() %>% knitr::kable()
- matched_data <- get_matches(match_obj) %>%
- arrange(subclass) %>%
- mutate(sex = ifelse(sex == "M", 1, 0),
- mgmt = ifelse(mgmt == "Methylated", 1, 0))
- #save the matched data
- #mat_data <- match.data(match_obj)
- #saveRDS(mat_data, "./matched_data_w_id.rds")
- # create table 1
- get_matches(match_obj) %>%
- select(age, sex, mgmt, group) %>% #select the variables of interest
- tbl_summary(by = group,
- statistic = list(all_continuous() ~ "{mean}({sd})",
- all_categorical() ~ "{n}({p}%)")) %>%
- modify_header(label ~ "**Variable**") %>%
- modify_spanning_header(c("stat_1", "stat_2") ~ "**Intervention**") %>%
- bold_labels() #%>%
- #add_p(pvalue_fun = function(x) style_pvalue(x, digits = 2))
- ######## EXPORT SOURCE DATA FOR TABLE 1 ########
- # tab1_data <- get_matches(match_obj) %>%
- # select(subclass, group, age, sex, mgmt)
- #
- # write_xlsx(tab1_data, "~/Downloads/Tab1_data.xlsx")
- ################################################
- #check distribution of age
- ks_result <- ks.test(matched_data$age[matched_data$group == "control"],
- matched_data$age[matched_data$group == "intervention"])
- ks_result
- ```
- ### Assess the matching by fitting GEE models
- Use GEE models to account for potential clustering within matched set (assume a exchangeable within-set correlation structure). Report parameter significance using Wald test.
- ```{r}
- # 1) Is there a difference in age between control and treatment group?
- #age is a normally-distributed response
- mod <- geeglm(age ~ group,
- family = gaussian, #normally distributed response
- data = matched_data,
- id = subclass,
- corstr = "exch") #within-subject observations are equally correlated
- summary(mod)
- #difference in mean age between intervention and control groups --> large p-value -> there is NO significant difference in age between the groups
- # 2) Is there a significant difference in the proportion of males and females between the control and treatment groups?
- mod_sex <- geeglm(sex ~ group,
- family = binomial, #because the response is binary
- data = matched_data,
- id = subclass,
- corstr = "exch") #within-subject observations are equally correlated
- summary(mod_sex)
- #3) whether the probability of mgmt = 1 differs between the control and treatment groups, accounting for within-subclass correlations?
- mod_mgmt <- geeglm(mgmt ~ group,
- family = binomial, #because the response is binary
- data = matched_data,
- id = subclass,
- corstr = "exch") #within-subject observations are equally correlated
- # no strong evidence that mgmt differs between groups
- summary(mod_mgmt)
- ```
- ::: callout-important
- In total, we have `r nrow(intervention)` patients in the intervention group and `r nrow(intervention)*4` patients in the control group after PSM, for a total of `r nrow(intervention)*5` patients. From the results shown above, we can see that there is good balance between the controls and intervention group in terms of age, sex, and MGMTp methylation status (p>.05). All patients had gross total resection (GTR) and IDH-widtype glioblastoma.
- :::
- ## Log-rank tests
- ```{r, eval=T}
- fit <- survfit(Surv(survival, status) ~ group, #0=alive, 1=dead
- data = matched_data)
- # ordinary log-rank tests
- survdiff(Surv(survival, status) ~ group, #0=alive, 1=dead
- data = matched_data)
- #med survival
- median_surv <- data.frame(surv_median(fit)) %>%
- select(strata, median) %>%
- rename(median_day = median) %>%
- mutate(median_mon = round(median_day/30,2))
- median_surv
- # Show the median survival time
- survfit(Surv(survival, status) ~ group, data = matched_data) %>%
- tbl_survfit(
- probs = 0.5, #survival quantile to return
- label_header = "**Median survival (95% CI)**",
- )
- # kaplan-meier plot
- ggsurvplot(fit,
- data = matched_data,
- xscale = "d_m", #convert days to months
- break.time.by=365.25*0.75, #break the x-scale
- xlim = c(0, max(matched_data$survival) + 5), #limit the x-axis
- surv.median.line = "hv",
- #censor.shape = 124,
- cumcens= F,
- cumevents = F,
- palette = c("#f16c23", "#2b6a99"),
- xlab = "Time (months)",
- ylab = "Survival probability",
- legend.title = "Group",
- legend.labs = c("Control", "PPRT"),
- #pval = T, #p-value
- #pval.method = T,
- conf.int = T,
- risk.table = T,
- tables.height = 0.2,
- tables.theme = theme_cleantable(),
- ggtheme = theme_classic())
- ######## EXPORT DATA USED FOR K-M PLOT #############
- # saved_data <- matched_data %>%
- # select(baseline_id, group, survival, status, subclass) %>%
- # arrange(baseline_id)
- # write_xlsx(saved_data, "~/Downloads/Figure2_SourceData_OS.xlsx")
- ####################################################
- ```
- ::: callout-important
- The median overall survival was `r median_surv$median_mon[2]` months for patients in the intervention PPRT group and `r median_surv$median_mon[1]` months for patients in the control standard of care group.
- The log-rank test found a significant difference in survival between patients in the control and treatment group, indicating distinct survival experiences between patients with and without PPRT (p<0.05).
- :::
- ## Cox proportional hazards model with robust variance estimator
- ```{r, eval=T}
- #change reference group
- matched_data2 <- get_matches(match_obj) %>%
- mutate(group = factor(group, levels = c("control", "intervention")),
- mgmt = factor(mgmt, levels = c("Unmethylated", "Methylated")))
- # A) standard cox regression
- # cox_model_std <- coxph(Surv(survival, status) ~ group,
- # data = matched_data2)
- #
- # tabcoxph(cox_model_std, formatp.list = list(decimals = 4, lowerbound = 0.0001, leading0 = F))
- # B) cox model with robust variance estimator
- cox_model_robust <- coxph(Surv(survival, status) ~ group,
- cluster = subclass, #account for clustering within matched sets
- data = matched_data2)
- # option 2 output
- tabcoxph(cox_model_robust, formatp.list = list(decimals = 4, lowerbound = 0.0001, leading0 = F))
- # Test the Proportional Hazards Assumption of a Cox Regression
- cox.zph(cox_model_robust)
- ```
- ::: callout-important
- Based on the Cox proportional hazards regression (with robust standard errors) output above, death rate from glioblastoma for patients in the PPRT intervention group is **0.34** times the risk of patients in the standard control group. In other words, the analysis showed a significant improvement in survival times among patients who underwent PPRT intervention compared to those that did not (HR=0.34; 95% CI: 0.17-0.69; p=.003).
- To test the proportional hazard (PH) assumption, we can use a global Schoenfeld test, a form of goodness-of-fit test. If the PH assumption is true, then the Schoenfeld residuals should be independent of time. As shown above, the test is NOT statistically significant (GLOBAL p>.05). Therefore, the proportional hazard assumption holds.
- :::
- ## Intent-to-treat (ITT) analysis
- Let's use data from the 20 intervention subjects who were enrolled in PPRT, including the 3 subjects treated with tumor treating fields (TTFields) therapy.
- ```{r}
- intervention <- read_excel("/Volumes/TOSHIBA/work_mac/Documents/collab_yr2/Hamed_SNO_0524/july24/ACC_Trial_11_20_2024_To_Amy.xlsx",
- sheet = 2) %>%
- janitor::clean_names() %>%
- mutate(survival_all = if_else(alive == "n", survival, survival_till_3_20_2025)) %>%
- mutate(survival_all = survival) %>%
- mutate(year = factor(year(dos))) %>%
- #filter(is.na(remove) | remove != "Optune device") %>% #remove optune devices (tumor treating fields)
- select(age, sex, alive, survival_all, mgmt, year) %>%
- rename(survival = survival_all) %>%
- mutate(group = "intervention") %>%
- mutate(baseline_id = "000")
- comp_data <- rbind(intervention, control) %>%
- mutate(status = if_else(alive == "y", 0, 1))
- # perform propensity score matching (PSM) with the original control patients
- match_obj <- matchit(factor(group) ~ age + sex + mgmt, #eor = GTR and IDH = wildtype
- data = comp_data,
- method = "nearest",
- distance ="glm",
- ratio = 4, #how many control units should be matched to each treated unit in k:1 matching
- replace = F) #control units can only be matched to ONE treated unit each
- #Table 1 for the new matches
- # get_matches(match_obj) %>%
- # select(age, sex, mgmt, group) %>% #select the variables of interest
- # tbl_summary(by = group,
- # statistic = list(all_continuous() ~ "{mean}({sd})",
- # all_categorical() ~ "{n}({p}%)")) %>%
- # modify_header(label ~ "**Variable**") %>%
- # #modify_spanning_header(c("stat_1", "stat_2") ~ "**Intervention**") %>%
- # bold_labels() %>%
- # add_p(pvalue_fun = function(x) style_pvalue(x, digits = 2))
- matched_data <- get_matches(match_obj) %>%
- arrange(subclass) %>%
- mutate(sex = ifelse(sex == "M", 1, 0),
- mgmt = ifelse(mgmt == "Methylated", 1, 0))
- #median survival
- survfit(Surv(survival, status) ~ group, data = matched_data,
- #conf.type = "log" #indicate the confidence interval type
- ) %>%
- tbl_survfit(
- probs = 0.5, #survival quantile to return
- label_header = "**Median survival (95% CI)**",
- )
- # Cox PH hazard model w/robust estimators
- matched_data2 <- get_matches(match_obj) %>%
- mutate(group = factor(group, levels = c("control", "intervention")),
- mgmt = factor(mgmt, levels = c("Unmethylated", "Methylated")))
- cox_model_robust <- coxph(Surv(survival, status) ~ group,
- cluster = subclass, #account for clustering within matched sets
- data = matched_data2)
- # option 2 output
- tabcoxph(cox_model_robust, formatp.list = list(decimals = 4, lowerbound = 0.0001, leading0 = F))
- # Test the Proportional Hazards Assumption of a Cox Regression
- cox.zph(cox_model_robust)
- ```
- When we include all of the intervention subjects, the effect of the PPRT intervention is still significant (HR=0.4; 95% CI: 0.21-0.78; p=.007).
qc_and_os_analysis.qmd at commit 20b68d5, no license · at the source
Overview
and 11 other authors
Stephen J Bagley13,17, Arati Desai13,17, Donald M O’Rourke8,13, Russell T Shinohara2,3,5,6, MacLean P Nasrallah2,3,13,18, Boon-Keng Kevin Teo7, Goldie Kurtz7, Gaurav Shukla3,19, Michelle Alonso-Basanta7, Robert A Lustig7, Christos Davatzikos2,3,419 affiliations
- Department of Bioengineering, School of Engineering, Santa Clara University, Santa Clara, CA USA
- Center for Data Science and AI for Integrated Diagnostics (AI2D), University of Pennsylvania, Philadelphia, PA USA
- Center for Biomedical Image Computing and Analytics (CBICA), University of Pennsylvania, Philadelphia, PA USA
- Department of Radiology, Perelman School of Medicine at the University of Pennsylvania, Philadelphia, PA USA
- Penn Statistics in Imaging and Visualization Center, Perelman School of Medicine at the University of Pennsylvania, Philadelphia, PA USA
- Center for Clinical Epidemiology and Biostatistics, Perelman School of Medicine at the University of Pennsylvania, Philadelphia, PA USA
- Department of Radiation Oncology, Perelman School of Medicine at the University of Pennsylvania, Philadelphia, PA USA
- Department of Neurosurgery, Perelman School of Medicine at the University of Pennsylvania, Philadelphia, PA USA
- Center for Data-Driven Discovery in Biomedicine (D3b), Children’s Hospital of Philadelphia, Philadelphia, PA USA
- Department of Neurology, Emory University School of Medicine, Atlanta, GA USA
- Goizueta Alzheimer’s Disease Research Center, Emory University School of Medicine, Atlanta, GA USA
- Department of Biomedical Informatics, Emory University School of Medicine, Atlanta, GA USA
- GBM Translational Center of Excellence, Abramson Cancer Center, Perelman School of Medicine at the University of Pennsylvania, Philadelphia, PA USA
- Department of Pathology and Laboratory Medicine, Indiana University School of Medicine, Indianapolis, IN USA
- Department of Radiology and Imaging Sciences, Indiana University School of Medicine, Indianapolis, IN USA
- Diffusion and Connectomics in Precision Healthcare Research (DiCIPHR), Perelman School of Medicine at the University of Pennsylvania, Philadelphia, PA USA
- Department of Medicine, Perelman School of Medicine at the University of Pennsylvania, Philadelphia, PA USA
- Department of Pathology & Laboratory Medicine, Perelman School of Medicine at the University of Pennsylvania, Philadelphia, PA USA
- Department of Radiation Oncology, Christiana Care Health System, Newark, DE USA
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.
CBICA/AI-guided-radiation-dose-escalation
20b68d56e0cb20e29cbdb3ca191b8418b9ce052e, 5 March 2026Availability: 1 check, the latest on 28 September 2026: the link answers
- 28 September 2026: the link answers
11 files
- infiltration_maps/
run_acctrial_recurrmap.s , Shell, 34 linesh - preprocessing/
perfusion_alignment.py , Python, 305 lines - preprocessing/
preprocess_old_wrapper.s , Shell, 860 linesh - preprocessing/
run_3dresample.sh , Shell, 394 lines - preprocessing/
wrapper_convertDCM.sh , Shell, 237 lines - preprocessing/
wrapper_sort_and_rename_ , Shell, 225 linesdicoms.sh - segmentation/
run_single_segmdm.sh , Shell, 370 lines - statistical_analysis/
pfs_analysis.qmd , Quarto, 278 lines, 2 matches - statistical_analysis/
qc_and_os_analysis.qmd , Quarto, 502 lines, 3 matches - statistical_analysis/
simulation_modified_logr , R, 134 linesank.R - README.md, Text, 59 lines
Zenodo 18920301
Availability: 1 check, the latest on 28 September 2026: the link answers (HTTP 200)
- 28 September 2026: the link answers (HTTP 200)
11 files
- infiltration_maps/
run_acctrial_recurrmap.s , Shell, 34 linesh - preprocessing/
perfusion_alignment.py , Python, 305 lines - preprocessing/
preprocess_old_wrapper.s , Shell, 860 linesh - preprocessing/
run_3dresample.sh , Shell, 394 lines - preprocessing/
wrapper_convertDCM.sh , Shell, 237 lines - preprocessing/
wrapper_sort_and_rename_ , Shell, 225 linesdicoms.sh - segmentation/
run_single_segmdm.sh , Shell, 370 lines - statistical_analysis/
pfs_analysis.qmd , Quarto, 278 lines - statistical_analysis/
qc_and_os_analysis.qmd , Quarto, 502 lines - statistical_analysis/
simulation_modified_logr , R, 134 linesank.R - README.md, Text, 59 lines
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:
- it points to the authors' code: CBICA/
AI-guided-radiation-dose , Zenodo 18920301-escalation
Read it in the paper: doi.org/10.1038/s41467-026-72545-y.
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;
- 20 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
No dataset and no data link were found in the paper.
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:
- no repository, dataset or request procedure was recognized in it
Read it in the paper: doi.org/10.1038/s41467-026-72545-y.
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, 28 September 2026: the first record
Recorded: type, language, journal, volume, issue, pages, dates, 31 authors, 4 keywords, 18 MeSH terms, 1 funder, 38 references.
Cite
This paper
Akbari, H., Mohan, S., Liu, F., Jiang, C., Fathi Kazerooni, A., Berger, M., Rathore, S., Bilello, M., Sako, C., Garcia, J., Brem, S., Bakas, S., Mamourian, E., Pepin, A., James, P., Dorsey, J., Singh, A., Parker, D., Verma, R., . . . Davatzikos, C. (2026). Personalized machine learning-guided radiation dose escalation in newly diagnosed glioblastoma: prospective pilot study. Nature communications, 17(1), 6413. https://
BibTeX
@article{akbari2026perso
author = {Akbari, Hamed and Mohan, Suyash and Liu, Fang and Jiang, Cecilia and Fathi Kazerooni, Anahita and Berger, Melanie and Rathore, Saima and Bilello, Michel and Sako, Chiharu and Garcia, Jose and Brem, Steven and Bakas, Spyridon and Mamourian, Elizabeth and Pepin, Abigail and James, Paul and Dorsey, Jay and Singh, Ashish and Parker, Drew and Verma, Ragini and Cao, Quy and Bagley, Stephen J and Desai, Arati and O’Rourke, Donald M and Shinohara, Russell T and Nasrallah, MacLean P and Teo, Boon-Keng Kevin and Kurtz, Goldie and Shukla, Gaurav and Alonso-Basanta, Michelle and Lustig, Robert A and Davatzikos, Christos},
title = {{Personalized machine learning-guided radiation dose escalation in newly diagnosed glioblastoma: prospective pilot study}},
journal = {Nature communications},
year = {2026},
month = may,
volume = {17},
number = {1},
pages = {6413},
publisher = {Nature Publishing Group},
issn = {2041-1723},
doi = {10.1038/
url = {https://
pmid = {42129213},
pmcid = {PMC13377092}
}
RIS
TY - JOUR
AU - Akbari, Hamed
AU - Mohan, Suyash
AU - Liu, Fang
AU - Jiang, Cecilia
AU - Fathi Kazerooni, Anahita
AU - Berger, Melanie
AU - Rathore, Saima
AU - Bilello, Michel
AU - Sako, Chiharu
AU - Garcia, Jose
AU - Brem, Steven
AU - Bakas, Spyridon
AU - Mamourian, Elizabeth
AU - Pepin, Abigail
AU - James, Paul
AU - Dorsey, Jay
AU - Singh, Ashish
AU - Parker, Drew
AU - Verma, Ragini
AU - Cao, Quy
AU - Bagley, Stephen J
AU - Desai, Arati
AU - O’Rourke, Donald M
AU - Shinohara, Russell T
AU - Nasrallah, MacLean P
AU - Teo, Boon-Keng Kevin
AU - Kurtz, Goldie
AU - Shukla, Gaurav
AU - Alonso-Basanta, Michelle
AU - Lustig, Robert A
AU - Davatzikos, Christos
TI - Personalized machine learning-guided radiation dose escalation in newly diagnosed glioblastoma: prospective pilot study
T2 - Nature communications
J2 - Nat Commun
PY - 2026
DA - 2026/
VL - 17
IS - 1
SP - 6413
SN - 2041-1723
PB - Nature Publishing Group
DO - 10.1038/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.1038/
"type": "article-journal",
"title": "Personalized machine learning-guided radiation dose escalation in newly diagnosed glioblastoma: prospective pilot study",
"container-title": "Nature communications",
"author": [
{
"family": "Akbari",
"given": "Hamed"
},
{
"family": "Mohan",
"given": "Suyash"
},
{
"family": "Liu",
"given": "Fang"
},
{
"family": "Jiang",
"given": "Cecilia"
},
{
"family": "Fathi Kazerooni",
"given": "Anahita"
},
{
"family": "Berger",
"given": "Melanie"
},
{
"family": "Rathore",
"given": "Saima"
},
{
"family": "Bilello",
"given": "Michel"
},
{
"family": "Sako",
"given": "Chiharu"
},
{
"family": "Garcia",
"given": "Jose"
},
{
"family": "Brem",
"given": "Steven"
},
{
"family": "Bakas",
"given": "Spyridon"
},
{
"family": "Mamourian",
"given": "Elizabeth"
},
{
"family": "Pepin",
"given": "Abigail"
},
{
"family": "James",
"given": "Paul"
},
{
"family": "Dorsey",
"given": "Jay"
},
{
"family": "Singh",
"given": "Ashish"
},
{
"family": "Parker",
"given": "Drew"
},
{
"family": "Verma",
"given": "Ragini"
},
{
"family": "Cao",
"given": "Quy"
},
{
"family": "Bagley",
"given": "Stephen J"
},
{
"family": "Desai",
"given": "Arati"
},
{
"family": "O’Rourke",
"given": "Donald M"
},
{
"family": "Shinohara",
"given": "Russell T"
},
{
"family": "Nasrallah",
"given": "MacLean P"
},
{
"family": "Teo",
"given": "Boon-Keng Kevin"
},
{
"family": "Kurtz",
"given": "Goldie"
},
{
"family": "Shukla",
"given": "Gaurav"
},
{
"family": "Alonso-Basanta",
"given": "Michelle"
},
{
"family": "Lustig",
"given": "Robert A"
},
{
"family": "Davatzikos",
"given": "Christos"
}
],
"container-title-short":
"volume": "17",
"issue": "1",
"page": "6413",
"DOI": "10.1038/
"PMID": "42129213",
"PMCID": "PMC13377092",
"ISSN": "2041-1723",
"publisher": "Nature Publishing Group",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
5,
13
]
]
}
}
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.1016/j.isci.2026.115657 [code]
- Integration of machine learning to develop a disulfidptosis model for predicting glioma prognosis, immunotherapy response, and drug.Journal: iScienceIn common: survival, tidyverse, SciPy, 1 other tool, clinical / translational, other condition, 1 reference
- [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: iScienceIn common: survival, NiBabel, tidyverse, 2 other tools, clinical / translational, other condition
- [3] doi:10.1158/1078-0432.ccr-25-4419 [code]
- Framework for Statistical Parametric Mapping of the Interactions between Glioblastoma Location, Treatment, Prognostic Variables, and Survival Using a Phase III Trial.Journal: Clinical cancer research : an official journal of the American Association for Cancer ResearchIn common: NiBabel, SciPy, NumPy, clinical / translational, other condition, 2 references
- [4] 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. ClinicalIn common: survival, NiBabel, tidyverse, 2 other tools, other condition
- [5] doi:10.1016/j.cell.2026.05.026 [code]
- The critical role of the endogenous immune compartment after CAR T cell therapy in recurrent GBM.Journal: CellIn common: survival, tidyverse, SciPy, 1 other tool, other condition, 1 reference
- [6] doi:10.1016/j.xcrm.2026.102682 [code]
- TET CpG sequence-context-specifi
c DNA demethylation shapes progression of IDH-mutant gliomas. Journal: Cell reports. MedicineIn common: survival, tidyverse, NumPy, other condition, 1 reference - [7] doi:10.1038/s41467-026-74515-w [code]
- Advancing fair and explainable machine learning for neuroimaging dementia pattern classification in multi-racial and multi-ethnic populations.Journal: Nature communicationsIn common: NumPy, author Christos Davatzikos
- [8] doi:10.1038/s41467-026-72091-7 [code]
- Coupled cross-sectional and longitudinal non-negative matrix factorization reveals dominant brain aging trajectories in 48,949 individuals.Journal: Nature communicationsIn common: NumPy, author Christos Davatzikos
- [9] doi:10.1038/s41467-026-70287-5 [code]
- Cortical-limbic circuit dynamics of approach-avoidance conflict in humans.Journal: Nature communicationsIn common: survival, NiBabel, tidyverse, 2 other tools
- [10] doi:10.1126/sciadv.aee2305 [code]
- Prediction of mild cognitive impairment progression using time-sensitive multimodal biomarkers.Journal: Science advancesIn common: survival, NiBabel, tidyverse, 1 other tool, clinical / translational
Contribute
The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.
Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.
Claim this paper
Correct its record
Say what each link of this record is, remove the ones that are not the paper's, add the ones that are missing. The correction becomes a new version of the record, in its Versions section.
Validate its tracing map
You validate the map as this page shows it: 2 repositories of the authors' code, each at its verified commit and with its license, 20 scripts, and 5 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:4e1751e7d283cf4e…
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.
