1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322 | #' EnsembleAge Static Clock Predictions
#'
#' Predict age using the main EnsembleAge static clocks for mouse data.
#' This is the primary clock for mouse age predictions.
#'
#' For the simplest interface, consider using \code{\link{predictEnsemble}} which
#' automatically handles data loading, platform detection, and preprocessing.
#'
#' @param dat0sesame Data frame containing methylation data with CGid column
#' @param samps Data frame containing sample information (must include Age column)
#' @param efficient_loading Logical indicating whether to use efficient loading (default: TRUE)
#' @param verbose Logical indicating whether to print progress messages (default: TRUE)
#' @return Data frame with age predictions and acceleration values for static ensemble clocks
#' @export
#' @references Haghani, A., et al. (2025). GeroScience. DOI: 10.1007/s11357-025-01808-1
#' @examples
#' \donttest{
#' # Main mouse age prediction
#' results <- predict_ensemble_static(methylation_data, sample_info)
#' }
predict_ensemble_static <- function(dat0sesame, samps, efficient_loading = TRUE, verbose = TRUE) {
if (verbose) cat("=== EnsembleAge Static Clock Predictions ===\n")
# Run full prediction
prediction_results <- predict_age_simple(dat0sesame, samps,
efficient_loading = efficient_loading,
verbose = verbose)
# Get the long format results
all_results <- attr(prediction_results, "long_format")
if (is.null(all_results)) {
stop("Long format results not available. Please check the prediction function.")
}
# Filter to only EnsembleAge.Static results (includes both Ensemble.Static and EnsembleAge.Static)
static_results <- all_results %>%
dplyr::filter(grepl("Ensemble.*\\.Static", clockFamily)) %>%
dplyr::select(Basename, Age, epiClock, epiAge, AgeAccelation, Female, Tissue, clockFamily)
if (verbose) {
cat("EnsembleAge Static predictions complete!\n")
cat("Predicted", nrow(static_results), "samples using",
length(unique(static_results$epiClock)), "static clocks\n")
}
return(static_results)
}
#' EnsembleAge Dynamic Clock Predictions
#'
#' Predict age using individual EnsembleAge dynamic clocks for mouse data.
#' These are individual clocks that can be analyzed separately.
#'
#' @param dat0sesame Data frame containing methylation data with CGid column
#' @param samps Data frame containing sample information (must include Age column)
#' @param efficient_loading Logical indicating whether to use efficient loading (default: TRUE)
#' @param verbose Logical indicating whether to print progress messages (default: TRUE)
#' @return Data frame with age predictions and acceleration values for dynamic ensemble clocks
#' @export
#' @examples
#' \donttest{
#' # Individual mouse clock predictions
#' results <- predict_ensemble_dynamic(methylation_data, sample_info)
#' }
predict_ensemble_dynamic <- function(dat0sesame, samps, efficient_loading = TRUE, verbose = TRUE) {
if (verbose) cat("=== EnsembleAge Dynamic Clock Predictions ===\n")
# Run full prediction
prediction_results <- predict_age_simple(dat0sesame, samps,
efficient_loading = efficient_loading,
verbose = verbose)
# Get the long format results
all_results <- attr(prediction_results, "long_format")
if (is.null(all_results)) {
stop("Long format results not available. Please check the prediction function.")
}
# Filter to only EnsembleAge.Dynamic results
dynamic_results <- all_results %>%
dplyr::filter(grepl("EnsembleAge\\.Dynamic", clockFamily)) %>%
dplyr::select(Basename, Age, epiClock, epiAge, AgeAccelation, Female, Tissue, clockFamily)
if (verbose) {
cat("EnsembleAge Dynamic predictions complete!\n")
cat("Predicted", nrow(dynamic_results), "samples using",
length(unique(dynamic_results$epiClock)), "individual dynamic clocks\n")
}
return(dynamic_results)
}
#' EnsembleDual Static Clock Predictions
#'
#' Predict age using EnsembleDual static clocks for both human and mouse data.
#' These clocks work across species and include relative age transformations.
#'
#' @param dat0sesame Data frame containing methylation data with CGid column
#' @param samps Data frame containing sample information (must include Age column)
#' @param efficient_loading Logical indicating whether to use efficient loading (default: TRUE)
#' @param verbose Logical indicating whether to print progress messages (default: TRUE)
#' @return Data frame with age predictions and acceleration values for dual-species clocks
#' @export
#' @examples
#' \dontrun{
#' # Cross-species age prediction (human and mouse)
#' results <- predict_ensemble_dual_static(methylation_data, sample_info)
#' }
predict_ensemble_dual_static <- function(dat0sesame, samps, efficient_loading = TRUE, verbose = TRUE) {
if (verbose) cat("=== EnsembleDual Static Clock Predictions ===\n")
# Run full prediction
prediction_results <- predict_age_simple(dat0sesame, samps,
efficient_loading = efficient_loading,
verbose = verbose)
# Get the long format results
all_results <- attr(prediction_results, "long_format")
if (is.null(all_results)) {
stop("Long format results not available. Please check the prediction function.")
}
# Filter to only EnsembleDualAge.Static results
dual_results <- all_results %>%
dplyr::filter(grepl("EnsembleDualAge\\.Static", clockFamily)) %>%
dplyr::select(Basename, Age, epiClock, epiAge, AgeAccelation, Female, Tissue, clockFamily)
if (verbose) {
cat("EnsembleDual Static predictions complete!\n")
cat("Predicted", nrow(dual_results), "samples using",
length(unique(dual_results$epiClock)), "dual-species clocks\n")
}
return(dual_results)
}
#' Original Clock Predictions
#'
#' Predict age using the original clock implementations (Ake clocks, Universal clocks, etc.).
#' These are the pre-ensemble clock methods.
#'
#' @param dat0sesame Data frame containing methylation data with CGid column
#' @param samps Data frame containing sample information (must include Age column)
#' @param efficient_loading Logical indicating whether to use efficient loading (default: TRUE)
#' @param verbose Logical indicating whether to print progress messages (default: TRUE)
#' @return Data frame with age predictions and acceleration values for original clocks
#' @export
#' @examples
#' \dontrun{
#' # Original clock predictions
#' results <- predict_original_clocks(methylation_data, sample_info)
#' }
predict_original_clocks <- function(dat0sesame, samps, efficient_loading = TRUE, verbose = TRUE) {
if (verbose) cat("=== Original Clock Predictions ===\n")
# Run full prediction
prediction_results <- predict_age_simple(dat0sesame, samps,
efficient_loading = efficient_loading,
verbose = verbose)
# Get the long format results
all_results <- attr(prediction_results, "long_format")
if (is.null(all_results)) {
stop("Long format results not available. Please check the prediction function.")
}
# Filter to exclude ensemble clocks (get original clocks)
original_results <- all_results %>%
dplyr::filter(!grepl("EnsembleAge\\.|EnsembleDualAge\\.", clockFamily)) %>%
dplyr::select(Basename, Age, epiClock, epiAge, AgeAccelation, Female, Tissue, clockFamily)
if (verbose) {
cat("Original clock predictions complete!\n")
cat("Predicted", nrow(original_results), "samples using",
length(unique(original_results$epiClock)), "original clocks\n")
cat("Clock families:", paste(unique(original_results$clockFamily), collapse = ", "), "\n")
}
return(original_results)
}
#' All Clock Predictions
#'
#' Predict age using all available clocks (ensemble and original).
#' This is equivalent to the main predict_age_simple function but with clearer naming.
#'
#' For the simplest interface, consider using \code{\link{predictEnsemble}} which
#' automatically handles data loading, platform detection, and preprocessing.
#'
#' @param dat0sesame Data frame containing methylation data with CGid column
#' @param samps Data frame containing sample information (must include Age column)
#' @param efficient_loading Logical indicating whether to use efficient loading (default: TRUE)
#' @param verbose Logical indicating whether to print progress messages (default: TRUE)
#' @return Data frame with age predictions and acceleration values for all clocks
#' @export
#' @examples
#' \dontrun{
#' # All available clock predictions
#' results <- predict_all_clocks(methylation_data, sample_info)
#' }
predict_all_clocks <- function(dat0sesame, samps, efficient_loading = TRUE, verbose = TRUE) {
if (verbose) cat("=== All Clock Predictions ===\n")
# Run full prediction
prediction_results <- predict_age_simple(dat0sesame, samps,
efficient_loading = efficient_loading,
verbose = verbose)
# Get the long format results
all_results <- attr(prediction_results, "long_format")
if (is.null(all_results)) {
stop("Long format results not available. Please check the prediction function.")
}
if (verbose) {
cat("All clock predictions complete!\n")
cat("Predicted", nrow(all_results), "samples using",
length(unique(all_results$epiClock)), "total clocks\n")
# Summary by clock family
family_summary <- all_results %>%
dplyr::group_by(clockFamily) %>%
dplyr::summarise(
n_clocks = length(unique(epiClock)),
n_predictions = dplyr::n(),
.groups = "drop"
)
cat("Clock family summary:\n")
print(family_summary)
}
return(all_results)
}
#' Get Clock Information
#'
#' Get information about available clocks in the package.
#'
#' @param clock_type Character string to filter by clock type (optional)
#' @param verbose Logical indicating whether to print detailed information (default: TRUE)
#' @return Data frame with clock information
#' @export
#' @examples
#' \dontrun{
#' # Get all clock information
#' clock_info <- get_clock_info()
#'
#' # Get only ensemble static clocks
#' ensemble_static <- get_clock_info("EnsembleAge.Static")
#' }
get_clock_info <- function(clock_type = NULL, verbose = TRUE) {
# Load clock coefficients
clock_file_path <- system.file("data", "Clock_coefficients.RDS", package = "EnsembleAge")
if (clock_file_path == "") {
clock_file_path <- file.path("data", "Clock_coefficients.RDS")
}
if (!file.exists(clock_file_path)) {
stop("Clock coefficients file not found.")
}
epiclocks <- readRDS(clock_file_path)
# Extract clock information
clock_info <- data.frame(
clockFamily = character(0),
clockName = character(0),
n_probes = numeric(0),
stringsAsFactors = FALSE
)
for (family_name in names(epiclocks)) {
family_clocks <- epiclocks[[family_name]]
for (clock_name in names(family_clocks)) {
clock <- family_clocks[[clock_name]]
n_probes <- length(clock$CGid[clock$CGid != "Intercept"])
clock_info <- rbind(clock_info, data.frame(
clockFamily = family_name,
clockName = clock_name,
n_probes = n_probes,
stringsAsFactors = FALSE
))
}
}
# Filter by clock type if specified
if (!is.null(clock_type)) {
clock_info <- clock_info %>%
dplyr::filter(grepl(clock_type, clockFamily, ignore.case = TRUE))
}
if (verbose) {
cat("Available clocks:\n")
cat("Total families:", length(unique(clock_info$clockFamily)), "\n")
cat("Total clocks:", nrow(clock_info), "\n")
cat("Total unique probes:", length(unique(unlist(lapply(epiclocks, function(fam) {
unlist(lapply(fam, function(clk) clk$CGid[clk$CGid != "Intercept"]))
})))), "\n\n")
# Summary by family
family_summary <- clock_info %>%
dplyr::group_by(clockFamily) %>%
dplyr::summarise(
n_clocks = dplyr::n(),
total_probes = sum(n_probes),
avg_probes = round(mean(n_probes), 1),
.groups = "drop"
)
print(family_summary)
}
return(clock_info)
}
|