Nothing
print.rhf <- function(x, digits = 3, label.width = 34, ...) {
## ---- Class / mode -------------------------------------------------------
is_rhf <- inherits(x, "rhf")
is_grow <- "grow" %in% class(x)
is_predict <- any(c("predict", "predict.rhf") %in% class(x))
if (!(is_rhf && (is_grow || is_predict))) {
stop("print.rhf() supports only objects of class c('rhf','grow') or c('rhf','predict').")
}
has_test <- is_predict && !is.null(x$risk.test)
is_restore <- is_predict && !has_test
## ---- Helpers ------------------------------------------------------------
.lab <- function(label) sprintf("%*s: ", label.width, label)
.fmt <- function(label, value) paste0(.lab(label), value)
.is_num1 <- function(v) is.numeric(v) && length(v) == 1 && is.finite(v)
fnum <- function(v) if (.is_num1(v)) format(round(v, digits), scientific = FALSE, trim = TRUE) else "NA"
fint <- function(v) if (.is_num1(v)) format(as.integer(round(v)), big.mark = ",", trim = TRUE) else "NA"
## ---- Identify yvar indices (id/status if available) ---------------------
status_idx <- NA_integer_
id_idx <- NA_integer_
if (!is.null(x$yvar.names)) {
id_idx <- match("id", x$yvar.names, nomatch = NA_integer_)
status_idx <- match("status", x$yvar.names, nomatch = NA_integer_)
} else if (!is.null(colnames(x$yvar))) {
id_idx <- match("id", colnames(x$yvar), nomatch = NA_integer_)
status_idx <- match("status", colnames(x$yvar), nomatch = NA_integer_)
}
if (is.na(status_idx) && !is.null(x$yvar) && NCOL(x$yvar) >= 3) status_idx <- 3
## ---- Counts: grow/restore vs predict-with-test --------------------------
n_records <- NA_real_
n_ids <- NA_real_
rec_per <- NA_real_
if (is_grow || is_restore) {
## Training domain
n_records <- if (!is.null(x$n)) as.integer(x$n) else if (!is.null(x$yvar)) NROW(x$yvar) else NA_integer_
n_ids <- if (!is.null(x$id)) length(unique(x$id))
else if (!is.null(x$yvar) && !is.na(id_idx) && id_idx <= NCOL(x$yvar))
length(unique(x$yvar[, id_idx])) else NA_integer_
rec_per <- if (.is_num1(n_records) && .is_num1(n_ids) && n_ids > 0) n_records / n_ids else NA_real_
} else {
## Predict with test data
## Cases (prefer xvar rows; yvar rows may be CP or condensed; n may be training n)
n_cases <- if (!is.null(x$xvar)) NROW(x$xvar)
else if (!is.null(x$id)) length(unique(x$id))
else if (!is.null(x$yvar)) NROW(x$yvar)
else if (!is.null(x$n)) as.integer(x$n) else NA_integer_
## Unique IDs for test
n_ids <- if (!is.null(x$id) && length(x$id) == n_cases) length(unique(x$id))
else if (!is.null(x$yvar) && !is.na(id_idx) && id_idx <= NCOL(x$yvar))
length(unique(x$yvar[, id_idx]))
else n_cases
## Records: if yvar carries CP rows and is >= ids, use it; otherwise fall back to cases
if (!is.null(x$yvar)) {
nr <- NROW(x$yvar)
n_records <- if (.is_num1(nr) && .is_num1(n_ids) && nr >= n_ids) nr else n_cases
} else {
n_records <- n_cases
}
## Note: rec_per from test rows can be misleading (many predict objects don't carry CP rows),
## so we intentionally do NOT print average records/case for predict-with-test.
}
## ---- Deaths/events (available if yvar has status) -----------------------
n_deaths <- if (!is.null(x$yvar) && !is.na(status_idx)) sum(x$yvar[, status_idx], na.rm = TRUE) else NA_integer_
## ---- Forest stats (always present) --------------------------------------
avg_tree_size <- if (!is.null(x$forest$leafCount)) mean(as.numeric(x$forest$leafCount), na.rm = TRUE) else NA_real_
nodeSZ <- NA_real_
na_arr <- x$forest$nativeArray
if (!is.null(na_arr) && all(c("brnodeID", "nodeSZ", "treeID") %in% names(na_arr))) {
arr0 <- na_arr[!is.na(na_arr$brnodeID) & na_arr$brnodeID == 0, , drop = FALSE]
if (NROW(arr0)) nodeSZ <- mean(tapply(arr0$nodeSZ, arr0$treeID, mean, na.rm = TRUE), na.rm = TRUE)
}
## ---- Time-varying features & TDC line ----------------------------------
n_tdc <- if (!is.null(x$xvar.time)) sum(x$xvar.time > 0, na.rm = TRUE)
else if (!is.null(x$forest$xvar.time)) sum(x$forest$xvar.time > 0, na.rm = TRUE)
else NA_integer_
fam <- if (!is.null(x$family)) tolower(as.character(x$family)) else ""
is_tdc_family <- grepl("tdc", fam)
if (is_grow || is_restore) {
tdc_note <- if (!isTRUE(rec_per > 1)) {
"NO (records per ID = 1)"
} else if (!isTRUE(n_tdc > 0)) {
"NO (0 time-varying features)"
} else "YES"
} else {
## predict-with-test: CP rows may not be present; base on model + features
if (!isTRUE(is_tdc_family)) {
tdc_note <- "NO (family is not TDC)"
} else if (!isTRUE(n_tdc > 0)) {
tdc_note <- "NO (0 time-varying features)"
} else {
tdc_note <- "YES"
}
}
## ---- Risk vectors / ordering -------------------------------------------
risks <- list(
"In-bag" = if (!is.null(x$risk.inbag)) x$risk.inbag[is.finite(x$risk.inbag)] else NULL,
"OOB" = if (!is.null(x$risk.oob)) x$risk.oob[is.finite(x$risk.oob)] else NULL,
"Test" = if (!is.null(x$risk.test)) x$risk.test[is.finite(x$risk.test)] else NULL
)
rmean <- function(v) if (!is.null(v) && length(v)) mean(v, na.rm = TRUE) else NA_real_
## ---- Print --------------------------------------------------------------
out <- c(
.fmt("Number of records", fint(n_records)),
.fmt("Sample size (unique IDs)", fint(n_ids))
)
if (is_grow || is_restore) {
out <- c(out, .fmt("Average records per ID",
fnum(if (.is_num1(n_records) && .is_num1(n_ids) && n_ids > 0) n_records / n_ids else NA_real_)))
}
if (!is.na(n_deaths)) out <- c(out, .fmt("Number of deaths/events", fint(n_deaths)))
if (!is.null(x$sampsize)) out <- c(out, .fmt("Tree sample size", paste(x$sampsize, collapse = ", ")))
if (!is.null(x$ntree)) out <- c(out, .fmt("Number of trees", fint(x$ntree)))
out <- c(out,
.fmt("Average tree size (leaves)", fnum(avg_tree_size)),
.fmt("Average node size", fnum(nodeSZ)))
if (!is.null(x$forest$parms) && !is.null(x$forest$parms$mtry)) {
out <- c(out, .fmt("No. features tried at each split", fint(x$forest$parms$mtry)))
}
out <- c(out, .fmt("Total no. time-varying features", if (!is.na(n_tdc)) fint(n_tdc) else "NA"))
if (!is.null(x$forest$parms) && !is.null(x$forest$parms$xvar.wt)) {
out <- c(out, .fmt("Total no. features", fint(length(x$forest$parms$xvar.wt))))
}
if (!is.null(x$family)) out <- c(out, .fmt("Family", as.character(x$family)))
if (!is.null(x$splitrule)) out <- c(out, .fmt("Splitrule", as.character(x$splitrule)))
if (!is.null(x$forest$parms) && !is.null(x$forest$parms$nsplit)) {
out <- c(out, .fmt("No. of random splits", fint(x$forest$parms$nsplit)))
}
## Risk lines
if (is_grow || is_restore) {
oob_lbl <- if (is_restore) "OOB (restore)" else "OOB"
if (!is.null(risks[["OOB"]])) {
out <- c(out, .fmt(paste0(oob_lbl, " risk"), fnum(rmean(risks[["OOB"]]))))
}
if (is_restore) out <- c(out, .fmt("Predict restore mode", "YES (using original forest)"))
} else {
if (!is.null(risks[["Test"]])) {
out <- c(out, .fmt("Test risk", fnum(rmean(risks[["Test"]]))))
}
if (!is.null(risks[["OOB"]])) {
out <- c(out, .fmt("OOB risk", fnum(rmean(risks[["OOB"]]))))
}
}
out <- c(out, .fmt("TDC analysis", tdc_note))
message(paste(out, collapse = "\n"))
invisible(x)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.