OSCR

The aging epigenome: integrative analyses reveal intersection with Alzheimer's disease.

Code ↔ Paper

6 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 6 matches
  1. [1] § Methods › Differentially methylated regions analysis ↔ code/utility/coMethDMR_aux.R, lines 151–199 · score 0.63 · linear regression, co methylated, medians, errors, models, CpGs
  2. [2] § Methods › Pathway analysis ↔ code/utility/pathway.R, lines 69–184 · score 0.61 · methylRRA, methylGSA, pathways, UCSC, enriched, enrichment
  3. [3] § Methods › Inflation assessment and correction ↔ code/utility/annotation_and_bacon.R, lines 483–626 · score 0.57 · inflation factors, bacon corrected, bias, genomic
  4. [4] § Methods › Inflation assessment and correction ↔ code/utility/annotation_and_bacon.R, lines 483–626 · score 0.57 · Genomic inflation factors, lambda, bias, bacon
  5. [5] § Methods › Association of DNA methylation at individual CpGs with chronological age ↔ code/dmr/coMethDMR.Rmd, lines 212–240 · score 0.54 · CD4T, Gran, Mono, NK, sex, beta
  6. [6] § Methods › Pre-processing of DNA methylation data ↔ code/dmr/coMethDMR.Rmd, lines 187–210 · score 0.50 · bisulfite conversion, status, EPIC, FHS, DNAm

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

R · 629 lines · 24 KB · MIT · 2 matches

  1. #######################################################################################################
  2. # =================================================================================================== #
  3. # Function for annotation and inflation adjusted
  4. # =================================================================================================== #
  5. #######################################################################################################
  6. library(SummarizedExperiment)
  7. library(tidyverse)
  8. library(bacon)
  9. library(GWASTools)
  10. library(minfi)
  11. library(rGREAT)
  12. # ===================================================================================================
  13. # Annotation Single CpGs
  14. # ===================================================================================================
  15. # Function: get_anno_gr
  16. # ------------------------------------------------------------------------------
  17. # Description:
  18. # Retrieves annotation information as a GRanges object for the specified methylation array and genome.
  19. #
  20. # Parameters:
  21. # array : Character. An input array (e.g., methylation array) for which genomic annotations
  22. # are required. Supported options include "HM450", "EPICv1", "EPIC", and "EPICv2".
  23. # genome : Character. A string specifying the genome build used for annotation, such as "hg19"
  24. # or "hg38".
  25. # dir.data.aux : (Optional) Character. A directory path containing auxiliary data used by the
  26. # annotation function, particularly for reading external manifest files when using
  27. # genome "hg38".
  28. #
  29. # Returns:
  30. # A GRanges object containing the genomic annotation data.
  31. get_anno_gr <- function(array = "HM450",
  32. genome = "hg19",
  33. dir.data.aux = NULL) {
  34. if(array == "HM450"){
  35. library(IlluminaHumanMethylation450kanno.ilmn12.hg19)
  36. anno <- minfi::getAnnotation(IlluminaHumanMethylation450kanno.ilmn12.hg19)
  37. }
  38. if(array %in% c("EPICv1", "EPIC")){
  39. if(genome == "hg19") {
  40. library(IlluminaHumanMethylationEPICanno.ilm10b4.hg19)
  41. anno <- minfi::getAnnotation(IlluminaHumanMethylationEPICanno.ilm10b4.hg19)
  42. }
  43. if(genome == "hg38") {
  44. anno <- read_csv(
  45. file.path(dir.data.aux, "infinium-methylationepic-v-1-0-b5-manifest-file.csv"),
  46. show_col_types = F,
  47. skip = 7
  48. )
  49. }
  50. }
  51. if(array == "EPICv2") {
  52. library(IlluminaHumanMethylationEPICv2anno.20a1.hg38)
  53. anno <- minfi::getAnnotation(IlluminaHumanMethylationEPICv2anno.20a1.hg38)
  54. }
  55. if(array %in% c("EPICv1", "EPIC") & genome == "hg38") {
  56. anno.gr <- anno %>% makeGRangesFromDataFrame(
  57. seqnames.field = "CHR_hg38",
  58. start.field = "Start_hg38", end.field = "End_hg38",
  59. strand.field = "Strand_hg38",
  60. keep.extra.columns = T,
  61. na.rm = T
  62. )
  63. } else {
  64. anno.gr <- anno %>% makeGRangesFromDataFrame(
  65. start.field = "pos", end.field = "pos", keep.extra.columns = T
  66. )
  67. }
  68. anno.gr
  69. }
  70. # ------------------------------------------------------------------------------
  71. # Function: annotate_results
  72. # ------------------------------------------------------------------------------
  73. # Description:
  74. # Annotates a CpG results data frame by merging genomic annotation (from get_anno_gr) with
  75. # additional GREAT analysis results.
  76. #
  77. # Parameters:
  78. # result : Data frame. A table containing CpG IDs and associated statistics to annotate.
  79. # array : Character. The methylation array type (e.g., "HM450", "EPICv1", "EPIC").
  80. # genome : Character. The genome version ("hg19" or "hg38").
  81. # dir.data.aux : Character. Directory path for auxiliary data files containing precomputed annotations.
  82. # save : Logical. Whether to save the annotated result as a CSV file.
  83. # dir.save : Character. Directory path where the annotated result file will be saved.
  84. # prefix : Character. A prefix used for naming the output file.
  85. #
  86. # Returns:
  87. # A data frame with additional columns for genomic annotation and GREAT analysis.
  88. annotate_results <- function(result,
  89. array = "HM450",
  90. genome = "hg19",
  91. dir.data.aux = NULL,
  92. save = T,
  93. dir.save = NULL,
  94. prefix = "Framingham"){
  95. # load(file.path(dir.data.aux,"E073_15_coreMarks_segments.rda"))
  96. # load(file.path(dir.data.aux,"meta_analysis_cpgs.rda"))
  97. anno.gr <- get_anno_gr(array = array, genome = genome, dir.data.aux = dir.data.aux)
  98. anno_df <- as.data.frame(anno.gr)
  99. if(genome == "hg19") {
  100. if(array == "HM450"){
  101. load(file.path(dir.data.aux,"great_HM450_array_annotation.rda"))
  102. }
  103. if(array %in% c("EPICv1", "EPIC")){
  104. load(file.path(dir.data.aux,"great_EPIC_array_annotation.rda"))
  105. }
  106. result <- cbind(
  107. result,
  108. anno_df[result$cpg,c("seqnames", "start", "end", "width", "Relation_to_Island", "UCSC_RefGene_Name", "UCSC_RefGene_Group")]
  109. )
  110. result <- dplyr::left_join(result, great, by = c("seqnames","start","end","cpg"))
  111. }
  112. # Add annotation
  113. if(genome == "hg38"){
  114. if(array %in% c("EPICv1", "EPIC")) {
  115. load(file.path(dir.data.aux,"great_EPIC_array_annotation.rda"))
  116. anno_df <- anno_df %>%
  117. mutate(cpg = Name) %>%
  118. dplyr::select(cpg, seqnames, start, end, width,
  119. UCSC_RefGene_Group, UCSC_RefGene_Name, Relation_to_UCSC_CpG_Island) %>%
  120. unique()
  121. } else {
  122. load(file.path(dir.data.aux,"great_EPICv2_array_annotation.rda"))
  123. anno_df <- anno_df %>%
  124. mutate(cpg = gsub("_.*", "",anno_df$Name)) %>%
  125. dplyr::select(cpg, seqnames, start, end, width,
  126. UCSC_RefGene_Group, UCSC_RefGene_Name, Relation_to_Island) %>%
  127. unique()
  128. }
  129. result <- left_join(
  130. result,
  131. anno_df
  132. )
  133. result <- dplyr::left_join(result, great %>% ungroup %>% dplyr::select(cpg, GREAT_annotation))
  134. }
  135. if(save){
  136. write_csv(
  137. result,
  138. file.path(dir.save, paste0(prefix, "_annotated_results.csv"))
  139. )
  140. }
  141. return(result)
  142. }
  143. # ===================================================================================================
  144. # Annotation DMR
  145. # ===================================================================================================
  146. # Annotate the regions with E073 15-core marks segmentation states
  147. # ------------------------------------------------------------------------------
  148. # Description:
  149. # Annotates regions with ChromHMM segmentation states based on E073 15-core marks segmentation data.
  150. #
  151. # Parameters:
  152. # result : Data frame. Regions to be annotated.
  153. # ChmmModels.gr: GRanges object. ChromHMM segmentation data containing state information.
  154. # region_var : Character. The column name in 'result' representing region identifiers.
  155. #
  156. # Returns:
  157. # The original data frame with an added column "E073_15_coreMarks_segments_state" for segmentation states.
  158. annotate_coreMarks_segments <- function(result, ChmmModels.gr, region_var) {
  159. # Create a GRanges object from the result data frame
  160. result.gr <- result %>%
  161. makeGRangesFromDataFrame(start.field = "start",
  162. end.field = "end",
  163. seqnames.field = "seqnames")
  164. # Find overlaps between the result regions and the ChromHMM models
  165. hits <- findOverlaps(result.gr, ChmmModels.gr) %>% as.data.frame()
  166. hits$state <- ChmmModels.gr$state[hits$subjectHits]
  167. hits$region <- result[[region_var]][hits$queryHits]
  168. # Match the state information to each region based on the 'region' string
  169. result$E073_15_coreMarks_segments_state <- hits$state[match(result[[region_var]], hits$region)]
  170. return(result)
  171. }
  172. # ------------------------------------------------------------------------------
  173. # Function: annotate_great
  174. # ------------------------------------------------------------------------------
  175. # Description:
  176. # Annotates regions with gene associations using GREAT analysis.
  177. #
  178. # Parameters:
  179. # result : Data frame. Regions to be annotated.
  180. # genome : Character. The genome version ("hg19" or "hg38") used in GREAT analysis.
  181. #
  182. # Returns:
  183. # A data frame with an additional column "GREAT_annotation" containing GREAT-derived gene information.
  184. # ------------------------------------------------------------------------------
  185. annotate_great <- function(result, genome) {
  186. # Create a GRanges object from the result data frame
  187. result.gr <- result %>%
  188. makeGRangesFromDataFrame(start.field = "start",
  189. end.field = "end",
  190. seqnames.field = "seqnames")
  191. # Submit the GREAT job and retrieve gene associations
  192. job <- submitGreatJob(result.gr, species = genome)
  193. regionsToGenes_gr <- rGREAT::getRegionGeneAssociations(job)
  194. regionsToGenes <- as.data.frame(regionsToGenes_gr)
  195. # Create annotation strings for each region
  196. GREAT_annotation <- lapply(seq_len(length(regionsToGenes$annotated_genes)), function(i) {
  197. g <- ifelse(regionsToGenes$dist_to_TSS[[i]] > 0,
  198. paste0(regionsToGenes$annotated_genes[[i]], " (+", regionsToGenes$dist_to_TSS[[i]], ")"),
  199. paste0(regionsToGenes$annotated_genes[[i]], " (", regionsToGenes$dist_to_TSS[[i]], ")"))
  200. paste0(g, collapse = ";")
  201. })
  202. # Select key columns from GREAT output and combine with the annotation strings
  203. great <- dplyr::select(regionsToGenes, seqnames, start, end, width)
  204. great <- data.frame(great, GREAT_annotation = unlist(GREAT_annotation))
  205. # Merge the GREAT annotation with the original result data frame
  206. result <- dplyr::left_join(result, great, by = c("seqnames", "start", "end"))
  207. return(result)
  208. }
  209. # ------------------------------------------------------------------------------
  210. # Function: annotate_region
  211. # ------------------------------------------------------------------------------
  212. # Description:
  213. # Annotates regions with CpG UCSC information by summarizing overlapping CpG details.
  214. #
  215. # Parameters:
  216. # result : Data frame. Regions to be annotated.
  217. # array : Character. The methylation array type (e.g., "HM450", "EPIC").
  218. # genome : Character. The genome version ("hg19" or "hg38").
  219. # dir.data.aux: Character. Directory path for auxiliary annotation data.
  220. # cpg : Vector. List of CpG identifiers to be considered.
  221. # region_var : Character. (Optional) Column name in 'result' that contains region identifiers. Default is "region".
  222. # cores : Numeric. Number of CPU cores to use for parallel processing. Default is 30.
  223. #
  224. # Returns:
  225. # A data frame with additional columns summarizing UCSC CpG annotation information.
  226. annotate_region <- function(result, array, genome, dir.data.aux, cpg, region_var = "region", cores = 30) {
  227. anno.gr <- get_anno_gr(array = array, genome = genome, dir.data.aux = dir.data.aux)
  228. anno_df <- as.data.frame(anno.gr)
  229. if(genome == "hg38" & array %in% c("EPIC","EPICv1")) island_var <- "Relation_to_UCSC_CpG_Island"
  230. else island_var <- "Relation_to_Island"
  231. # Create a GRanges object from the result data frame
  232. result.gr <- result %>%
  233. makeGRangesFromDataFrame(start.field = "start",
  234. end.field = "end",
  235. seqnames.field = "seqnames")
  236. doParallel::registerDoParallel(cores)
  237. anno <- plyr::ldply(
  238. 1:length(result.gr),
  239. .fun = function (i) {
  240. rg <- result.gr[i]
  241. overlap <- findOverlaps(rg, anno.gr)
  242. hit <- subjectHits(overlap)
  243. anno_df_sub <- anno_df[hit,]
  244. cpgs <- intersect(anno_df_sub$Name, cpg)
  245. anno_df_sub <- anno_df_sub[match(cpgs, anno_df_sub$Name),]
  246. # cpg in region
  247. cpgs_in_region <- paste(cpgs, collapse = ",")
  248. # UCSC_RefGene_Name
  249. UCSC_RefGene_Name <- paste0(unique(anno_df_sub[,"UCSC_RefGene_Name"]), collapse = ";")
  250. # UCSC_RefGene_Accession
  251. UCSC_RefGene_Accession <- paste0(unique(anno_df_sub[,"UCSC_RefGene_Accession"]), collapse = ";")
  252. # UCSC_RefGene_Group
  253. UCSC_RefGene_Group <- paste0(unique(anno_df_sub[,"UCSC_RefGene_Group"]), collapse = ";")
  254. # Relation_to_Island
  255. Relation_to_Island <- paste0(unique(anno_df_sub[,island_var]), collapse = ";")
  256. df <- data.frame(
  257. num_probes = length(cpgs),
  258. UCSC_RefGene_Name = UCSC_RefGene_Name,
  259. UCSC_RefGene_Accession = UCSC_RefGene_Accession,
  260. UCSC_RefGene_Group = UCSC_RefGene_Group,
  261. Relation_to_Island = Relation_to_Island,
  262. cpgs_in_region = cpgs_in_region
  263. )
  264. df[df == "NA"] <- NA
  265. df
  266. }, .parallel = T
  267. )
  268. cbind(result, anno)
  269. }
  270. # ------------------------------------------------------------------------------
  271. # Function: annotate_enhancer
  272. # ------------------------------------------------------------------------------
  273. # Description:
  274. # Annotates regions with enhancer overlap information using an external enhancer dataset.
  275. #
  276. # Parameters:
  277. # result : Data frame. Regions to be annotated.
  278. # nasser.enhancer.gr: GRanges object. Enhancer regions with associated cell type information.
  279. # cpg : Vector. List of CpG identifiers used in the analysis.
  280. # genome : Character. The genome version ("hg19" or "hg38").
  281. # array : Character. The methylation array type.
  282. #
  283. # Returns:
  284. # A data frame with two additional columns:
  285. # - nasser_is_enhancer: Logical indicating enhancer overlap.
  286. # - nasser_is_enhancer_cell_types: Character string of associated cell types.
  287. annotate_enhancer <- function(result, nasser.enhancer.gr, cpg, genome, array) {
  288. # Create a GRanges object from the result data frame
  289. result.gr <- result %>%
  290. makeGRangesFromDataFrame(start.field = "start",
  291. end.field = "end",
  292. seqnames.field = "seqnames")
  293. # Find overlaps between the result regions and the enhancer regions
  294. hits <- findOverlaps(result.gr, nasser.enhancer.gr) %>% as.data.frame()
  295. # Initialize the enhancer annotation columns
  296. result$nasser_is_enhancer <- FALSE
  297. result$nasser_is_enhancer[unique(hits$queryHits)] <- TRUE
  298. result$nasser_is_enhancer_cell_types <- NA
  299. result$nasser_is_enhancer_cell_types[unique(hits$queryHits)] <- sapply(unique(hits$queryHits), function(x) {
  300. paste(unique(nasser.enhancer.gr$CellType[hits$subjectHits[hits$queryHits %in% x]]), collapse = ",")
  301. })
  302. return(result)
  303. }
  304. annotate_chmm <- function(result, dir.data.aux = dir.data.aux) {
  305. load(file.path(dir.data.aux,"E073_15_coreMarks_segments.rda"))
  306. message("Annotating E073_15_coreMarks_segments")
  307. result$region <- paste0(result$seqnames,":",result$start,"-", result$end)
  308. result$start <- as.numeric(result$start)
  309. result$end <- as.numeric(result$end)
  310. result.gr <- result %>% makeGRangesFromDataFrame(
  311. start.field = "start",
  312. end.field = "end",
  313. seqnames.field = "seqnames"
  314. )
  315. hits <- findOverlaps(result.gr, ChmmModels.gr) %>% as.data.frame()
  316. hits$state <- ChmmModels.gr$state[hits$subjectHits]
  317. hits$region <- result$region[hits$queryHits]
  318. result$E073_15_coreMarks_segments_state <- hits$state[match(result$region,hits$region)]
  319. result$region <- NULL
  320. result
  321. }
  322. # ------------------------------------------------------------------------------
  323. # Function: add_dmr_annotation
  324. # ------------------------------------------------------------------------------
  325. # Description:
  326. # Integrates multiple annotation methods (region, enhancer, coreMarks segmentation, GREAT) for DMRs.
  327. #
  328. # Parameters:
  329. # result : Data frame. DMRs (differentially methylated regions) to be annotated.
  330. # cpg : Vector. List of CpG identifiers used for regional annotation.
  331. # dir.data.aux : Character. Directory path for auxiliary data files (e.g., segmentation, enhancer data).
  332. # region_var : (Optional) Character. Column name in 'result' containing region identifiers.
  333. # If NULL, a region identifier is created using chromosome, start, and end.
  334. # array : Character. The methylation array type (default "EPIC").
  335. # genome : Character. Genome version ("hg19" or "hg38").
  336. # annotate : Vector of characters. Specifies which annotation types to apply. Options include:
  337. # "region", "enhancer", "E073_15_coreMarks_segments", "GREAT".
  338. #
  339. # Returns:
  340. # A data frame with multiple annotation columns added.
  341. add_dmr_annotation <- function(result,
  342. cpg,
  343. dir.data.aux,
  344. region_var = NULL,
  345. array = "EPIC",
  346. genome = "hg19",
  347. annotate = c("region", "enhancer", "E073_15_coreMarks_segments", "GREAT")) {
  348. # Prepare the result data frame for genomic range creation
  349. if(is.null(region_var)) {
  350. result$seqnames <- paste0("chr", result$`#chrom`)
  351. result$region <- paste0(result$seqnames, ":", result$start, "-", result$end)
  352. region_var <- "region"
  353. } else {
  354. region <- str_split(result[[region_var]], ":|-", simplify = T)
  355. result$seqnames <- region[,1]
  356. result$start <- region[,2]
  357. result$end <- region[,3]
  358. }
  359. result$start <- as.numeric(result$start)
  360. result$end <- as.numeric(result$end)
  361. # Annotate with E073_15_coreMarks_segments if selected.
  362. if ("E073_15_coreMarks_segments" %in% annotate) {
  363. load(file.path(dir.data.aux, "E073_15_coreMarks_segments.rda"))
  364. message("Annotating E073_15_coreMarks_segments")
  365. result <- annotate_coreMarks_segments(result, ChmmModels.gr, region_var)
  366. }
  367. # Annotate with GREAT if selected.
  368. if ("GREAT" %in% annotate) {
  369. message("Annotating GREAT")
  370. result <- annotate_great(result, genome)
  371. }
  372. # Annotate with enhancer if selected.
  373. if ("enhancer" %in% annotate) {
  374. # Load enhancer data and filter
  375. data <- readr::read_tsv(file.path(dir.data.aux, "AllPredictions.AvgHiC.ABC0.015.minus150.ForABCPaperV3.txt.gz"),
  376. show_col_types = F)
  377. CellType.selected <- readxl::read_xlsx(file.path(dir.data.aux, "Nassser study selected biosamples.xlsx"),
  378. col_names = FALSE) %>% dplyr::pull(1)
  379. data.filtered <- data %>%
  380. dplyr::filter(CellType %in% CellType.selected) %>%
  381. dplyr::filter(!isSelfPromoter) %>%
  382. dplyr::filter(class != "promoter")
  383. nasser.enhancer.gr <- data.filtered %>%
  384. makeGRangesFromDataFrame(start.field = "start",
  385. end.field = "end",
  386. seqnames.field = "chr",
  387. keep.extra.columns = TRUE)
  388. message("Annotating enhancer")
  389. result <- annotate_enhancer(result, nasser.enhancer.gr, cpg, genome, array)
  390. }
  391. # Annotate with UCSC (island annotation) if selected.
  392. if ("region" %in% annotate) {
  393. message("Annotating region")
  394. result <- annotate_region(result, array, genome, dir.data.aux, cpg, region_var = region_var)
  395. }
  396. return(result)
  397. }
  398. # ===================================================================================================
  399. # Bacon correction
  400. # ===================================================================================================
  401. # Function: bacon_adj
  402. # ------------------------------------------------------------------------------
  403. # Description:
  404. # Adjusts for bias and genomic inflation in EWAS data using the bacon method.
  405. # Supports correction using either z-scores or effect sizes with standard errors.
  406. #
  407. # Parameters:
  408. # data : Data frame. The EWAS results containing statistics to be adjusted.
  409. # est_var : Character. Column name for effect size estimates.
  410. # z_var : Character. Column name for z-scores.
  411. # std_var : Character. Column name for standard errors.
  412. # use_z : Logical. If TRUE, bacon correction is performed using z-scores only; otherwise, effect sizes and SEs are used.
  413. # save : Logical. Whether to save the bacon-corrected data and inflation statistics to files.
  414. # dir.save: Character. Directory path where the output files will be saved.
  415. # prefix : Character. A prefix used for naming the output files.
  416. #
  417. # Returns:
  418. # A list containing:
  419. # - data.with.inflation: The corrected EWAS data frame.
  420. # - bacon.obj : The bacon object from the initial analysis.
  421. # - inflation.stat : A data frame summarizing inflation and bias statistics.
  422. bacon_adj <- function(data, est_var, z_var, std_var,
  423. use_z = F,
  424. save = F,
  425. dir.save = NULL,
  426. prefix = "Framingham"){
  427. ### 1. Compute genomic inflation factor before bacon adjustment
  428. data <- data %>% mutate(
  429. chisq = get(z_var)^2
  430. )
  431. # inflation factor - last term is median from chisq distrn with 1 df
  432. inflationFactor <- median(data$chisq,na.rm = TRUE) / qchisq(0.5, 1)
  433. print("lambda")
  434. print(inflationFactor)
  435. ### 2. bacon analysis
  436. if(use_z){
  437. ### 2. bacon analysis
  438. z_scores <- data[[z_var]]
  439. bc <- bacon(
  440. teststatistics = z_scores,
  441. na.exclude = TRUE,
  442. verbose = F
  443. )
  444. # inflation factor
  445. print("lambda.bacon")
  446. print(inflation(bc))
  447. # bias
  448. print("estimate bias")
  449. print(bias(bc))
  450. print("estimates")
  451. print(bacon::estimates(bc))
  452. ### 3. Create final dataset
  453. data.with.inflation <- data %>% mutate(
  454. zScore.bacon = tstat(bc)[,1],
  455. pValue.bacon.z = pval(bc)[,1],
  456. fdr.bacon.z = p.adjust(pval(bc), method = "fdr"),
  457. ) %>% mutate(z.value = z_scores)
  458. print("o After bacon correction")
  459. print("Conventional lambda")
  460. lambda.con <- median((data.with.inflation$zScore.bacon) ^ 2,na.rm = TRUE)/qchisq(0.5, 1)
  461. print(lambda.con)
  462. # percent_null <- trunc ( bacon::estimates(bc)[1]*100, digits = 0)
  463. # percent_1 <- trunc ( bacon::estimates(bc)[2]*100, digits = 0 )
  464. # percent_2 <- 100 - percent_null - percent_1
  465. bc2 <- bacon(
  466. teststatistics = data.with.inflation$zScore.bacon,
  467. na.exclude = TRUE,
  468. priors = list(
  469. sigma = list(alpha = 1.28, beta = 0.36),
  470. mu = list(lambda = c(0, 3, -3), tau = c(1000, 100, 100)),
  471. epsilon = list(gamma = c(90, 5, 5)))
  472. )
  473. } else {
  474. est <- data[[est_var]]
  475. se <- data[[std_var]]
  476. bc <- bacon(
  477. teststatistics = NULL,
  478. effectsizes = est,
  479. standarderrors = se,
  480. na.exclude = TRUE,
  481. verbose = F
  482. )
  483. # posteriors(bc)
  484. # inflation factor
  485. print("lambda.bacon")
  486. print(inflation(bc))
  487. # bias
  488. print("estimate bias")
  489. print(bias(bc))
  490. print("estimates")
  491. print(bacon::estimates(bc))
  492. ### 3. Create final dataset
  493. data.with.inflation <- data.frame(
  494. data,
  495. Estimate.bacon = bacon::es(bc),
  496. StdErr.bacon = bacon::se(bc),
  497. pValue.bacon = pval(bc),
  498. fdr.bacon = p.adjust(pval(bc), method = "fdr"),
  499. stringsAsFactors = FALSE
  500. )
  501. print("o After bacon correction")
  502. print("Conventional lambda")
  503. lambda.con <- median((data.with.inflation$Estimate.bacon/data.with.inflation$StdErr.bacon) ^ 2,na.rm = TRUE)/qchisq(0.5, 1)
  504. print(lambda.con)
  505. # percent_null <- trunc ( estimates(bc)[1]*100, digits = 0)
  506. # percent_1 <- trunc ( estimates(bc)[2]*100, digits = 0 )
  507. # percent_2 <- 100 - percent_null - percent_1
  508. bc2 <- bacon(
  509. teststatistics = NULL,
  510. effectsizes = data.with.inflation$Estimate.bacon,
  511. standarderrors = data.with.inflation$StdErr.bacon,
  512. na.exclude = TRUE,
  513. priors = list(
  514. sigma = list(alpha = 1.28, beta = 0.36),
  515. mu = list(lambda = c(0, 3, -3), tau = c(1000, 100, 100)),
  516. epsilon = list(gamma = c(99, .5, .5)))
  517. )
  518. }
  519. print("inflation")
  520. print(inflation(bc2))
  521. print("estimates")
  522. print(bacon::estimates(bc2))
  523. data.with.inflation$chisq <- NULL
  524. inflation.stat <- data.frame(
  525. "Inflation.org" = inflationFactor,
  526. "Inflation.bacon" = inflation(bc),
  527. "Bias.bacon" = bias(bc),
  528. "Inflation.after.correction" = lambda.con,
  529. "Inflation.bacon.after.correction" = inflation(bc2),
  530. "Bias.bacon.after.correction" = bias(bc2)
  531. )
  532. if(save){
  533. readr::write_csv(
  534. data.with.inflation,
  535. file.path(dir.save, paste0(prefix, "_bacon_correction.csv"))
  536. )
  537. writexl::write_xlsx(
  538. inflation.stat,
  539. file.path(dir.save, paste0(prefix, "_inflation_stats.xlsx"))
  540. )
  541. }
  542. return(
  543. list(
  544. "data.with.inflation" = data.with.inflation,
  545. "bacon.obj" = bc,
  546. "inflation.stat" = inflation.stat
  547. )
  548. )
  549. }

annotation_and_bacon.R at commit d2cc5c5, under MIT · at the source

Overview

Authors: Wei Zhang1, David Lukacsovich1, Juan I Young2,3, Lissette Gomez3, Michael A Schmidt2,3, Brian W Kunkle2,3, Xi Chen1,4, Eden R Martin2,3, Lily Wang1,2,3,4,5
ORCID iDs: Lily Wang
  1. Division of Biostatistics, Department of Public Health Sciences, University of Miami, Miller School of Medicine, Miami, FL 33136 USA
  2. Dr. John T Macdonald Foundation Department of Human Genetics, University of Miami, Miller School of Medicine, Miami, FL 33136 USA
  3. John P. Hussman Institute for Human Genomics, University of Miami Miller School of Medicine, Miami, FL 33136 USA
  4. Sylvester Comprehensive Cancer Center, University of Miami, Miller School of Medicine, Miami, FL 33136 USA
  5. Soffer Clinical Research Ctr, University of Miami Miller School of Medicine, 1120 NW 14Th St, Miami, FL 33136 USA
Institutions: University of Miami (United States); Sylvester Comprehensive Cancer Center (United States)
Journal: GeroScience, volume 48, issue 3, pages 3185-3203
Dates: received 8 September 2025; accepted 7 March 2026; published online 14 April 2026; in print June 2026
Type: Research article · Language: English
License: CC BY
Identifiers: DOI 10.1007/s11357-026-02195-x · PMID 41975027 · PMCID PMC13356189 · OpenAlex W7154153233
Open access: hybrid, a free copy (OpenAlex)
Status: code verified
Categories: genetics / omics (modality), human (organism), Alzheimer's / dementia (population)
Methods: Statistics, Smoothing, state filtering, decompositions
Keywords: Aging, Alzheimer’s disease, Epigenetics, DNA methylation
MeSH: Aging*, Alzheimer Disease*, DNA Methylation*, Epigenome*, Aged, Aged, 80 and over, Epigenesis, Genetic, Female, Genome-Wide Association Study, Humans, Male (* major topic)
Topic: Epigenetics and DNA Methylation (Molecular Biology, Biochemistry, Genetics and Molecular Biology), according to OpenAlex
Funding: NIA NIH HHS (R01AG062634, R01 AG062634, U01 AG024904); NINDS NIH HHS (R61NS135587, R01 NS128145, R61 NS135587, RF1 NS128145, R01NS128145)
Citations: not cited yet (Europe PMC); 77 references in the paper

Abstract

Aging is the strongest risk factor for Alzheimer’s disease (AD), yet the role of age-associated DNA methylation (DNAm) changes in blood and their relevance to AD remains poorly understood. We performed a meta-analysis of blood DNAm samples from 475 dementia-free subjects aged over 65 years across two independent cohorts, the Framingham Heart Study (FHS) at Exam 9 and the Alzheimer’s Disease Neuroimaging Initiative (ADNI). We adjusted for sex and immune cell-type proportions and corrected batch effects and genomic inflation. Integrative analyses included pathway enrichment, mQTL analysis, colocalization with Alzheimer’s disease and related dementia (ADRD) GWAS summary statistics, brain-blood DNAm correlations, and comparison to independent AD methylation studies. We identified 3758 CpGs and 556 differentially methylated regions (DMRs) consistently associated with chronological age in both cohorts at a 5% false discovery rate. Our pathway enrichment analyses highlighted metabolic regulation and synaptic signaling, processes previously implicated in Alzheimer’s disease. Colocalization with ADRD GWAS summary statistics identified 32 genomic regions consistent with shared genetic signals for DNAm and ADRD risk. Roughly one-third of aging-associated CpGs overlapped CpGs associated with AD or AD neuropathology in external studies. Finally, we prioritized nine promoter CpGs (including those located in PDE1B, ELOVL2, and PODXL2) showing strong positive blood-to-brain methylation concordance and external AD associations, nominating them as candidate blood-based biomarkers. Our study demonstrated that late-life aging signatures in blood DNAm converge on processes implicated in AD and intersect with dementia genetics. A small set of CpGs with blood-brain concordance and external AD support offers promising candidate blood-based biomarkers for future validation.

Supplementary Information: The online version contains supplementary material available at 10.1007/s11357-026-02195-x.

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

TransBioInfoLab/AD-Aging-blood-sample-analysis

License: MIT
State: the link answers, verified on 29 September 2026
Evidence: files inventoried
Commit: d2cc5c5d37b2512bdcdc11a402a38a9bd6c7fcdc, 5 June 2025
Languages: R (14)
Size: 18 files, 14 scripts
Software Heritage: not archived
Found in: “Data availability”
Holds: README, license file, 5 notebooks
Not found: CITATION.cff, environment file, tests, continuous integration, documentation
Tools: tidyverse (11 files), survival (4 files), data.table (2 files), cowplot (1 file), ggplot2 (1 file), ggpubr (1 file), lme4 (1 file), lmerTest (1 file), metafor (1 file)
Availability: 1 check, the latest on 29 September 2026: the link answers
  • 29 September 2026: the link answers
16 files

The paper's code and data availability statement is in the Data section.

Tracing map

Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.

What the map holds:

  • 1 repository of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 14 scripts, each with its path and the digest of its content;
  • 6 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

The ADNI and Framingham Heart Study datasets can be accessed from http://adni.loni.usc.edu and the dbGap database (accession: phs000974.v5.p4). The scripts for the analyses performed in this study are at https://github.com/TransBioInfoLab/AD-Aging-blood-sample-analysis.

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

Recorded: type, language, journal, volume, issue, pages, dates, 9 authors, 4 keywords, 11 MeSH terms, 2 funders, 75 references.

Cite

This paper

Zhang, W., Lukacsovich, D., Young, J. I., Gomez, L., Schmidt, M. A., Kunkle, B. W., Chen, X., Martin, E. R., & Wang, L. (2026). The aging epigenome: integrative analyses reveal intersection with Alzheimer's disease. GeroScience, 48(3), 3185-3203. https://doi.org/10.1007/s11357-026-02195-x

BibTeX

@article{zhang2026aging,
author = {Zhang, Wei and Lukacsovich, David and Young, Juan I and Gomez, Lissette and Schmidt, Michael A and Kunkle, Brian W and Chen, Xi and Martin, Eden R and Wang, Lily},
title = {{The aging epigenome: integrative analyses reveal intersection with Alzheimer's disease}},
journal = {GeroScience},
year = {2026},
month = apr,
volume = {48},
number = {3},
pages = {3185--3203},
publisher = {Springer},
issn = {2509-2715},
doi = {10.1007/s11357-026-02195-x},
url = {https://doi.org/10.1007/s11357-026-02195-x},
pmid = {41975027},
pmcid = {PMC13356189}
}

RIS

TY - JOUR
AU - Zhang, Wei
AU - Lukacsovich, David
AU - Young, Juan I
AU - Gomez, Lissette
AU - Schmidt, Michael A
AU - Kunkle, Brian W
AU - Chen, Xi
AU - Martin, Eden R
AU - Wang, Lily
TI - The aging epigenome: integrative analyses reveal intersection with Alzheimer's disease
T2 - GeroScience
J2 - Geroscience
PY - 2026
DA - 2026/04/14
VL - 48
IS - 3
SP - 3185
EP - 3203
SN - 2509-2715
PB - Springer
DO - 10.1007/s11357-026-02195-x
UR - https://doi.org/10.1007/s11357-026-02195-x
LA - en
ER -

CSL-JSON

{
"id": "10.1007/s11357-026-02195-x",
"type": "article-journal",
"title": "The aging epigenome: integrative analyses reveal intersection with Alzheimer's disease",
"container-title": "GeroScience",
"author": [
{
"family": "Zhang",
"given": "Wei"
},
{
"family": "Lukacsovich",
"given": "David"
},
{
"family": "Young",
"given": "Juan I"
},
{
"family": "Gomez",
"given": "Lissette"
},
{
"family": "Schmidt",
"given": "Michael A"
},
{
"family": "Kunkle",
"given": "Brian W"
},
{
"family": "Chen",
"given": "Xi"
},
{
"family": "Martin",
"given": "Eden R"
},
{
"family": "Wang",
"given": "Lily"
}
],
"container-title-short": "Geroscience",
"volume": "48",
"issue": "3",
"page": "3185-3203",
"DOI": "10.1007/s11357-026-02195-x",
"PMID": "41975027",
"PMCID": "PMC13356189",
"ISSN": "2509-2715",
"publisher": "Springer",
"URL": "https://doi.org/10.1007/s11357-026-02195-x",
"language": "en",
"issued": {
"date-parts": [
[
2026,
4,
14
]
]
}
}

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.1186/s13073-026-01698-8 [code]
From aging to Alzheimer's disease: concordant brain DNA methylation changes in late life.
Journal: Genome medicine
In common: survival, ggpubr, ggplot2, 1 other tool, Alzheimer's / dementia, genetics / omics, 25 references, author Lily Wang
[2] doi:10.1002/trc2.70257 [code]
Blood DNA methylation signature of cognitive reserve moderates the association between CSF tau pathology and memory in prodromal Alzheimer's disease.
Journal: Alzheimer's & dementia (New York, N. Y.)
In common: lmerTest, lme4, ggpubr, 2 other tools, Alzheimer's / dementia, genetics / omics, 2 references, author Lily Wang
[3] doi:10.1038/s41586-026-10877-x [code]
Human brain organoids record the passage of time over multiple years.
Journal: Nature
In common: lmerTest, lme4, cowplot, 4 other tools, genetics / omics, 2 references
[4] doi:10.1038/s41467-026-73865-9 [code]
Histamine shapes the neurocomputational dynamics of human learning.
Journal: Nature communications
In common: metafor, lmerTest, lme4, 5 other tools
[5] doi:10.1038/s44400-026-00100-z [code]
Peripheral blood microarray-based transcriptomic and epigenetic analyses identify immune, inflammation, and metabolic dysregulation in Alzheimer's disease.
Journal: NPJ dementia
In common: survival, lme4, ggpubr, 2 other tools, Alzheimer's / dementia, genetics / omics, 2 references
[6] doi:10.1186/s13195-026-02036-1 [code]
Genetic drivers of progression in Alzheimer's disease are distinct from disease risk.
Journal: Alzheimer's research & therapy
In common: metafor, lmerTest, lme4, 4 other tools, Alzheimer's / dementia, genetics / omics
[7] doi:10.1002/ece3.73881 [code]
Epigenetic Aging in Brain Tissue of the Self-Fertilizing Vertebrate, &lt;i&gt;Kryptolebias marmoratus&lt;/i&gt;.
Journal: Ecology and evolution
In common: ggpubr, ggplot2, tidyverse, genetics / omics, 5 references
[8] doi:10.1038/s41588-026-02722-8 [code]
A multiancestry polygenic risk score for Alzheimer's disease is associated with cognitive decline and neuropathological hallmarks in diverse populations.
Journal: Nature genetics
In common: survival, lmerTest, lme4, 3 other tools, Alzheimer's / dementia, genetics / omics, 1 reference
[9] doi:10.1038/s41467-026-77170-3 [code]
DNA methylation profiling identifies long-range epigenetic silencing of clustered protocadherins as a key determinant of meningioma progression.
Journal: Nature communications
In common: survival, lmerTest, lme4, 4 other tools, genetics / omics
[10] doi:10.1093/bioinformatics/btag592 [code]
Network-based stratification of allele-specific expression reveals patient subgroups in Huntington's disease.
Journal: Bioinformatics (Oxford, England)
In common: survival, lme4, cowplot, 4 other tools, genetics / omics

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.