fast.saveload.RdSave and load a minimal forest object for prediction. These functions
are designed to use substantially less disk space and load large forests
faster than saving the full fitted object with saveRDS
and loading it with readRDS. Functions are available
for a single forest or a list of forests.
fast.save(o, path = NULL, testing = TRUE, units = "Mb", compact = FALSE,
compress = 50)
fast.load(directory, path = NULL, testing = FALSE, units = "Mb")
fast.save.list(o, path = NULL, testing = FALSE, units = "Mb", compact = FALSE,
compress = 50)
fast.load.list(directory, path = NULL, testing = FALSE, units = "Mb")For fast.save(), a fitted object with class beginning
c("rfsrc", "grow") and a forest component.
Supply the fitted object, not o$forest. For
fast.save.list(), a nonempty list of these objects.
For saving, the destination directory, including its name.
The default is file.path(getwd(), "forest").
An existing destination and all its contents are deleted.
For loading, the parent directory containing directory;
NULL uses the current working directory.
Name of the saved directory relative to path.
For fast.load.list(), this directory contains the individual
forest subdirectories.
Print component memory sizes using lsos().
Defaults to TRUE for fast.save() and FALSE
for the other functions.
Units for the memory-size display, passed to
format(object.size(...), units = units).
The default is "Mb".
If TRUE, omit terminal-node information from the
saved forest and recompute it during prediction. Requires a
non-anonymous forest containing the training predictors and responses.
If FALSE (default), save the forest with its available
terminal-node information. See Compact saving below.
A single finite number between 0 and 100 specifying the
FST compression level. The default is 50 for fast saving. Use 100
for maximum compression when smaller files are more important than
saving speed. This setting is independent of compact.
fast.save() addresses the large files and slow loading that
can result from saving a full fitted forest with saveRDS().
It saves only o$forest, the minimal object used for prediction,
including its tree information and any training data it contains.
Predictions and performance summaries outside this component are
excluded. fast.load() returns the forest for use with
predict.rfsrc.
Large tabular components are saved efficiently with
fst::write_fst(), and the remaining forest information with
saveRDS(..., compress = FALSE). Saving requires the fst
and data.table packages; loading requires fst.
All files have a .rda extension despite the different formats.
Keep the directory's files together and load the forest with
fast.load().
The compress setting is passed to every
fst::write_fst() call, including each forest saved by
fast.save.list(). Higher compression can reduce file sizes
at the cost of slower saving; the reduction depends on the saved
components. The remaining forest information in forest.rda
continues to use saveRDS(..., compress = FALSE).
Compression changes the encoding of the saved components, not the
fitted forest or the choice of components. It can be combined with
compact = TRUE. Use the same fast.load() or
fast.load.list() call for any compression level; no compression
argument is needed when loading. Invalid compression values are
rejected before the destination is deleted.
With compact = TRUE, the saved forest includes the tree
structure, factor-split information, training data, seeds, and other
forest information, but omits stored terminal-node information.
Prediction recomputes this information from the saved forest and
training data without growing new trees. The fitted object in memory
is unchanged.
The saved copy has terminal.qualts = FALSE and
terminal.quants = FALSE, with nativeArrayTNDS removed.
Use the same fast.load() or fast.load.list() call
for either saving mode. Compact saving can further reduce disk space,
but prediction may take longer and peak memory use may not decrease.
Use compact = FALSE for anonymous forests. Compact saving
includes the training data. Eligibility checks run before the
destination is deleted; for lists, every forest is checked first.
Standalone fast.save() always writes a self-contained forest.
Imputers fitted with share.xvar = TRUE use the same component
serializers but store their repeated training predictors once per
bank. Load those complete banks with load.impute.learn.
Direct fast.load() calls on shared learner subdirectories
stop because their predictors depend on the bank's common table
and reconstruction mappings.
Both save functions delete an existing destination directory and all its contents. Use a dedicated directory for each forest or list. The destination and any missing parent directories are then created.
When saving, path is the complete destination. When loading,
directory is its name and path is its parent. For a
destination save.path, use
fast.load(basename(save.path), path = dirname(save.path)).
For the default destination, use fast.load("forest").
fast.save.list() saves forests in subdirectories
forest1, forest2, and so on, inside path.
List names are not saved. fast.load.list() loads every entry
listed by list.files() in that directory, so it should contain
only saved forest subdirectories.
The loaded list is unnamed and follows directory-listing order,
which can differ from the original order: forest10 can precede
forest2. To load one forest, call fast.load() with its
subdirectory name.
fast.saveSaves the forest to disk and returns the
memory-usage matrix produced by gc(FALSE).
fast.loadThe saved forest component with its original
class, usually c("rfsrc", "forest", family).
fast.save.listAn unnamed list of the memory-usage
matrices returned by the individual fast.save() calls.
fast.load.listAn unnamed list of forest objects in directory-listing order.
The sampling-size function is saved as
sampfrac = o$forest$sampsize(1) and loaded as
function(x) x * sampfrac. Use saveRDS() to save a custom
function that is not proportional to sample size.
Compact saving checks that round(sampsize(n)) equals
round(n * sampsize(1)) at the training sample size n.
A mismatch stops saving before the destination is deleted.
This check applies only at the training sample size.
## ------------------------------------------------------------
## Regression: save, load, and compare predictions
## ------------------------------------------------------------
if (requireNamespace("fst", quietly = TRUE) &&
requireNamespace("data.table", quietly = TRUE)) {
o <- rfsrc(mpg ~ ., data = mtcars)
print(o)
save.path <- tempfile("rfsrc-forest-")
fast.save(o, path = save.path, testing = FALSE)
oo <- fast.load(basename(save.path), path = dirname(save.path))
p <- predict(o)
pp <- predict(oo)
print(summary(p$predicted - pp$predicted))
print(summary(p$predicted.oob - pp$predicted.oob))
unlink(save.path, recursive = TRUE)
}
# \donttest{
## ------------------------------------------------------------
## Compact saving: the same forest, fewer saved components
## ------------------------------------------------------------
if (requireNamespace("fst", quietly = TRUE) &&
requireNamespace("data.table", quietly = TRUE)) {
o <- rfsrc(mpg ~ ., data = mtcars, ntree = 100)
set.seed(19)
reference <- predict(o, seed = -19)
save.path <- tempfile("rfsrc-compact-")
fast.save(o, path = save.path, compact = TRUE, testing = FALSE)
oo <- fast.load(basename(save.path), path = dirname(save.path))
print(oo[c("terminal.qualts", "terminal.quants")])
print(list.files(save.path, pattern = "^nativeArrayTDNS_"))
set.seed(19)
restored <- predict(oo, seed = -19)
print(all.equal(reference$predicted, restored$predicted))
print(all.equal(reference$predicted.oob, restored$predicted.oob))
unlink(save.path, recursive = TRUE)
}
## ------------------------------------------------------------
## Regression: a list of forests with different node sizes
## ------------------------------------------------------------
if (requireNamespace("fst", quietly = TRUE) &&
requireNamespace("data.table", quietly = TRUE)) {
o1 <- rfsrc(mpg ~ ., data = mtcars, nodesize = 1)
o2 <- rfsrc(mpg ~ ., data = mtcars, nodesize = 10)
print(o1)
print(o2)
models <- list(o1, o2)
save.path <- tempfile("rfsrc-forest-list-")
invisible(fast.save.list(models, path = save.path))
oo <- fast.load.list(basename(save.path), path = dirname(save.path))
print(predict(oo[[1]]))
print(predict(oo[[2]]))
unlink(save.path, recursive = TRUE)
}
## ------------------------------------------------------------
## RFQ for imbalanced classification
## ------------------------------------------------------------
## Use matching prediction seeds when comparing class labels.
if (requireNamespace("fst", quietly = TRUE) &&
requireNamespace("data.table", quietly = TRUE)) {
data(breast, package = "randomForestSRC")
dta <- na.omit(breast)
o <- imbalanced(status ~ ., data = dta, ntree = 100)
print(o)
save.path <- tempfile("rfsrc-forest-")
fast.save(o, path = save.path, testing = FALSE)
oo <- fast.load(basename(save.path), path = dirname(save.path))
set.seed(19)
p <- predict(o, seed = -19)
set.seed(19)
pp <- predict(oo, seed = -19)
print(summary(p$predicted - pp$predicted))
print(summary(p$predicted.oob - pp$predicted.oob))
print(all.equal(as.character(p$class), as.character(pp$class)))
print(all.equal(as.character(p$class.oob),
as.character(pp$class.oob)))
unlink(save.path, recursive = TRUE)
}
## ------------------------------------------------------------
## Binary classification with rfq = TRUE
## ------------------------------------------------------------
if (requireNamespace("fst", quietly = TRUE) &&
requireNamespace("data.table", quietly = TRUE)) {
data(breast, package = "randomForestSRC")
dta <- na.omit(breast)
o <- rfsrc(status ~ ., data = dta, rfq = TRUE, ntree = 100,
perf.type = "gmean", splitrule = "auc")
print(o)
save.path <- tempfile("rfsrc-forest-")
fast.save(o, path = save.path, testing = FALSE)
oo <- fast.load(basename(save.path), path = dirname(save.path))
set.seed(19)
p <- predict(o, seed = -19)
set.seed(19)
pp <- predict(oo, seed = -19)
print(summary(p$predicted - pp$predicted))
print(summary(p$predicted.oob - pp$predicted.oob))
print(all.equal(as.character(p$class), as.character(pp$class)))
print(all.equal(as.character(p$class.oob),
as.character(pp$class.oob)))
unlink(save.path, recursive = TRUE)
}
## ------------------------------------------------------------
## Anonymous RFQ: supply the same prediction data to both forests
## ------------------------------------------------------------
if (requireNamespace("fst", quietly = TRUE) &&
requireNamespace("data.table", quietly = TRUE)) {
data(breast, package = "randomForestSRC")
dta <- na.omit(breast)
o <- rfsrc.anonymous(status ~ ., data = dta, rfq = TRUE,
ntree = 100, perf.type = "gmean", splitrule = "auc")
print(o)
save.path <- tempfile("rfsrc-forest-")
fast.save(o, path = save.path, testing = FALSE)
oo <- fast.load(basename(save.path), path = dirname(save.path))
set.seed(19)
p <- predict(o, newdata = dta, seed = -19)
set.seed(19)
pp <- predict(oo, newdata = dta, seed = -19)
print(summary(p$predicted - pp$predicted))
print(all.equal(as.character(p$class), as.character(pp$class)))
unlink(save.path, recursive = TRUE)
}
## ------------------------------------------------------------
## Survival
## ------------------------------------------------------------
if (requireNamespace("fst", quietly = TRUE) &&
requireNamespace("data.table", quietly = TRUE)) {
data(pbc, package = "randomForestSRC")
o <- rfsrc(Surv(days, status) ~ ., data = pbc, ntree = 100)
print(o)
save.path <- tempfile("rfsrc-forest-")
fast.save(o, path = save.path, testing = FALSE)
oo <- fast.load(basename(save.path), path = dirname(save.path))
set.seed(19)
p <- predict(o, seed = -19)
set.seed(19)
pp <- predict(oo, seed = -19)
print(summary(p$predicted - pp$predicted))
print(summary(p$predicted.oob - pp$predicted.oob))
unlink(save.path, recursive = TRUE)
}
## ------------------------------------------------------------
## Survival with save.memory = TRUE
## ------------------------------------------------------------
if (requireNamespace("fst", quietly = TRUE) &&
requireNamespace("data.table", quietly = TRUE)) {
data(pbc, package = "randomForestSRC")
o <- rfsrc(Surv(days, status) ~ ., data = pbc,
ntree = 100, save.memory = TRUE)
print(o)
save.path <- tempfile("rfsrc-forest-")
fast.save(o, path = save.path, testing = FALSE)
oo <- fast.load(basename(save.path), path = dirname(save.path))
set.seed(19)
p <- predict(o, seed = -19)
set.seed(19)
pp <- predict(oo, seed = -19)
print(summary(p$predicted - pp$predicted))
print(summary(p$predicted.oob - pp$predicted.oob))
unlink(save.path, recursive = TRUE)
}
## ------------------------------------------------------------
## Competing risks
## ------------------------------------------------------------
if (requireNamespace("fst", quietly = TRUE) &&
requireNamespace("data.table", quietly = TRUE)) {
data(wihs, package = "randomForestSRC")
o <- rfsrc(Surv(time, status) ~ ., data = wihs, nsplit = 3, ntree = 100)
print(o)
save.path <- tempfile("rfsrc-forest-")
fast.save(o, path = save.path, testing = FALSE)
oo <- fast.load(basename(save.path), path = dirname(save.path))
set.seed(19)
p <- predict(o, seed = -19)
set.seed(19)
pp <- predict(oo, seed = -19)
print(summary(p$predicted - pp$predicted))
print(summary(p$predicted.oob - pp$predicted.oob))
unlink(save.path, recursive = TRUE)
}
## ------------------------------------------------------------
## Multivariate regression and classification
## ------------------------------------------------------------
if (requireNamespace("fst", quietly = TRUE) &&
requireNamespace("data.table", quietly = TRUE)) {
data(nutrigenomic, package = "randomForestSRC")
ydta <- data.frame(diet = nutrigenomic$diet,
genotype = nutrigenomic$genotype,
nutrigenomic$lipids)
o <- rfsrc(get.mv.formula(colnames(ydta)),
data = data.frame(ydta, nutrigenomic$genes),
ntree = 100, importance = TRUE, nsplit = 10)
print(o)
save.path <- tempfile("rfsrc-forest-")
fast.save(o, path = save.path, testing = FALSE)
oo <- fast.load(basename(save.path), path = dirname(save.path))
set.seed(19)
p <- predict(o, seed = -19)
set.seed(19)
pp <- predict(oo, seed = -19)
print(summary(get.mv.predicted(p, oob = FALSE) -
get.mv.predicted(pp, oob = FALSE)))
print(summary(get.mv.predicted(p) - get.mv.predicted(pp)))
for (yn in names(p$classOutput)) {
print(yn)
print(all.equal(as.character(p$classOutput[[yn]]$class),
as.character(pp$classOutput[[yn]]$class)))
print(all.equal(as.character(p$classOutput[[yn]]$class.oob),
as.character(pp$classOutput[[yn]]$class.oob)))
}
unlink(save.path, recursive = TRUE)
}
# }
if (FALSE) { # \dontrun{
## ------------------------------------------------------------
## Classification: optional alzheimers data from varPro
## ------------------------------------------------------------
if (requireNamespace("fst", quietly = TRUE) &&
requireNamespace("data.table", quietly = TRUE)) {
data(alzheimers, package = "varPro")
o <- rfsrc(Diagnosis ~ ., data = alzheimers)
print(o)
save.path <- tempfile("rfsrc-forest-")
fast.save(o, path = save.path, testing = FALSE)
oo <- fast.load(basename(save.path), path = dirname(save.path))
set.seed(19)
p <- predict(o, seed = -19)
set.seed(19)
pp <- predict(oo, seed = -19)
print(summary(p$predicted - pp$predicted))
print(summary(p$predicted.oob - pp$predicted.oob))
print(all.equal(as.character(p$class), as.character(pp$class)))
print(all.equal(as.character(p$class.oob),
as.character(pp$class.oob)))
unlink(save.path, recursive = TRUE)
}
## ------------------------------------------------------------
## Optional memory-intensive anonymous survival test
## ------------------------------------------------------------
## This test repeats each PBC row 250 times and can require substantial memory.
if (requireNamespace("fst", quietly = TRUE) &&
requireNamespace("data.table", quietly = TRUE)) {
data(pbc, package = "randomForestSRC")
dta <- pbc[rep(seq_len(nrow(pbc)), each = 250), ]
o <- rfsrc.anonymous(Surv(days, status) ~ ., data = dta)
print(o)
save.path <- tempfile("rfsrc-forest-")
fast.save(o, path = save.path, testing = FALSE)
oo <- fast.load(basename(save.path), path = dirname(save.path))
set.seed(19)
p <- predict(o, newdata = dta, seed = -19)
set.seed(19)
pp <- predict(oo, newdata = dta, seed = -19)
print(summary(p$predicted - pp$predicted))
unlink(save.path, recursive = TRUE)
}
} # }