Skip to contents

Compose split construction, fitting, evaluation, residual-offset and optimism audits, response-level selection, and final aggregation. This function is filesystem orchestration around public helpers; it is not a separate statistical estimator and it does not read a project manifest.

Usage

modelPipeline(
  .path.datasets,
  .path.train,
  .path.model,
  .path.metrics,
  .path.response,
  .path.summary,
  .path.export,
  .path.iter = NULL,
  key,
  responses,
  datasets,
  colsId = character(0),
  features = NULL,
  setCol = "set",
  methods = c("ranger", "earth", "gbm"),
  seed = NULL,
  ensemble = "ensemble.RMSE",
  boundsMin = -Inf,
  boundsMax = Inf,
  iterSuffix = NULL,
  mode = "full",
  responsesActive = NULL,
  wipe = NULL,
  shadow = FALSE
)

Arguments

.path.datasets

Existing directory of assembled CSV files. Every non-recursive filename ending in .csv is processed by buildDataset(), whether or not its basename occurs in datasets.

.path.train, .path.model, .path.metrics, .path.response, .path.summary, .path.export

Output directories for splits, fitted models, cell metrics, cell response predictions, summary products, and final exports. Missing directories are created recursively after any configured wipe. See Wipe and cache policy for destructive behavior.

.path.iter

NULL, or an iteration directory. When supplied, aggregateResponses() writes or updates Y.csv there for a later chain iteration.

key

A non-empty character key name passed to buildDataset() and aggregateResponses(). Final response aggregation currently requires a column named SampleID independently of this argument.

responses

Non-empty character vector of assembled response-column names. Names are inserted unescaped into regular expressions used for split and model discovery.

datasets

Non-empty character vector of assembled dataset basenames used only by final aggregateResponses() feature extraction. Among these declared files, the last one that exists supplies X.csv and Xo.csv. This vector does not restrict upstream split construction, fitting, OOF reconstruction, or prediction.

colsId

Character vector of additional identifier columns excluded from inferred predictors.

features

NULL, or exact base predictor names passed to buildDataset(). NULL delegates predictor inference to that helper.

setCol

Non-empty character name of the assembled row-role column, expected to distinguish "train" and "predict".

methods

Character vector of fitted caret method identifiers. The default is c("ranger", "earth", "gbm").

seed

NULL, or a value passed to set.seed() before split construction in every mode. It controls fitting/resampling and other downstream random operations only to the extent documented by each helper.

ensemble

Forwarded without initial validation to predictModel(). That helper later requires one of "ensemble.RMSE" or "ensemble.R2" for its response-level selector. Final aggregateResponses() output nevertheless always uses ensemble.RMSE candidates.

boundsMin, boundsMax

Numeric response bounds forwarded through OOF, point-prediction, audit, and aggregation paths. Their order and finiteness are not validated.

iterSuffix

NULL, or the suffix identifying prior-iteration response features in buildDataset(), commonly ".o".

mode

A value in c("full", "train", "predict").

responsesActive

NULL, or a value used without subset or type validation to filter fitting, OOF/audit reconstruction, and prediction. NULL uses responses. All responses are still split and passed to final aggregation. See Partial-response state.

wipe

NULL, or any value. NULL and the literal logical scalar TRUE enable wiping; every other value disables it through isTRUE(). See Wipe and cache policy.

shadow

Logical value passed to buildDataset() to add its Gaussian shadow predictor.

Value

Invisibly, NULL. Results are the files produced by the selected mode and its composed helper calls.

Mode composition

Initial validation checks the type/non-emptiness conditions shown for key, responses, datasets, setCol, and non-null features, plus membership of mode. It does not validate responsesActive, methods, ensemble, wipe, shadow, or the response bounds. A non-null seed is passed directly to set.seed(). Other conditions are delegated to the called helpers and can therefore fail after destructive or expensive work.

Every mode prepares directories and calls buildDataset(), which scans every CSV in .path.datasets. The response-column expression is the unescaped anchored alternation ^(r1|r2|...)$, applied case-insensitively. Fitting and prediction then discover dataset identifiers independently from the generated split filenames. Active response filtering of those names is exact and case-sensitive; the OOF and overfit model-file parsers receive an unescaped, unanchored active-response alternation inside their case-sensitive regular expressions.

  • "train" then calls trainModel() for active responses and stops. No OOF audit, prediction, overfit audit, or aggregation runs.

  • "predict" skips fitting, then calls auditQuantiles(), predictModel(), auditOverfit(), and aggregateResponses() in that order. Existing compatible models are therefore required.

  • "full" performs the training call followed by the complete prediction sequence above.

The offset audit must precede prediction because prediction consumes prediction_quantiles.csv. Aggregation then consumes unadjusted long point predictions, OOF residual rows, metric rows, and offsets. The overfit audit is diagnostic; aggregation does not use overfit.csv. In particular, ensemble is first checked when predictModel() starts: after wiping, split construction, and the offset audit in prediction mode, and additionally after fitting in full mode. An invalid value can therefore leave partial products before it errors.

Wipe and cache policy

With wipe = NULL or true, the function recursively removes and recreates .path.train, .path.metrics, .path.response, and .path.summary in every mode. In "full" mode only, it also recursively removes .path.model and .path.export; this same condition sets OVERRIDE = TRUE for fitting. These operations are destructive and have no rollback.

In "train" or "predict" mode, wiping preserves existing model and export directories. Training mode then uses OVERRIDE = FALSE, so surviving models can be reused under trainModel()'s predictor-name-only cache rule. With wipe = FALSE, every existing output is preserved, missing directories are created, and full-mode fitting also uses OVERRIDE = FALSE. Current metric, residual, export, and iteration helpers then apply their own merge or overwrite rules.

Products, selectors, and state

Every mode can overwrite split files. Train mode can additionally write fitted model and hash files, then returns without summary or delivery calls. Prediction mode never fits or writes model/hash files; it can write cell metrics and responses, metrics.csv, response_long.csv, residuals_oof.csv, prediction_quantiles.csv, overfit.csv, Yo.csv, X.csv, Xo.csv, optional Y.csv, and dataset-named intermediate exports. Full mode can write all train- and prediction-mode products.

The ensemble argument governs only predictModel()'s per-response dataset selector. aggregateResponses() independently forms its final rowwise selection from ensemble.RMSE candidates and cell R2. These selectors must not be described as one common "best model" rule.

Supplying seed changes the caller's RNG state. Both fitting and the evaluation engine invoked by predictModel() register a bounded PSOCK backend and leave foreach sequential under their accepted contracts. Shadow generation and prediction method randomization have their documented RNG effects. Errors and partial files from any helper propagate; orchestration is not transactional.

Partial-response state

With a non-null responsesActive, the helpers do not follow one common accumulation rule. auditQuantiles() replaces residual rows for active responses in an existing residuals_oof.csv and regenerates offsets from the merged residual table. predictModel() overwrites response_long.csv with current active-response predictions; its metrics.csv is the union of every cell-metric CSV currently present. auditOverfit() overwrites overfit.csv from models matching the active-response expression. aggregateResponses() preserves old Yo.csv rows only for responses absent from the current unseen result, and optional Y.csv preserves old non-overlapping response columns; both use their own replacement rules. X.csv and Xo.csv are overwritten from the last existing declared dataset. Thus wipe = FALSE preserves inputs for mixed accumulation but does not make every summary cumulative.

See also

buildDataset() for assembled input, trainModel() for fitting, predictModel() for the first selector, and aggregateResponses() for final delivery.

Examples

# \donttest{
root <- tempfile("ssel-pipeline-")
datasets_dir <- file.path(root, "datasets")
dir.create(datasets_dir, recursive = TRUE)

assembled <- data.frame(
  SampleID = c(paste0("S", 1:16), "P1", "P2"),
  set = c(rep("train", 16), "predict", "predict"),
  x = 1:18,
  z = rep(c(0, 1), 9),
  target = c(1:16 / 3 + rep(c(-0.5, 0.5), 8), NA, NA)
)
utils::write.csv(
  assembled,
  file.path(datasets_dir, "demo.csv"),
  row.names = FALSE,
  na = ""
)

old_quiet <- getOption("aR.quiet")
options(aR.quiet = TRUE)
modelPipeline(
  .path.datasets = datasets_dir,
  .path.train = file.path(root, "train"),
  .path.model = file.path(root, "model"),
  .path.metrics = file.path(root, "metrics"),
  .path.response = file.path(root, "response"),
  .path.summary = file.path(root, "summary"),
  .path.export = file.path(root, "export"),
  key = "SampleID",
  responses = "target",
  datasets = "demo",
  methods = "lm",
  seed = 2026,
  ensemble = "ensemble.RMSE",
  mode = "full"
)
options(aR.quiet = old_quiet)

sort(basename(list.files(file.path(root, "summary"))))
#> [1] "metrics.csv"              "overfit.csv"             
#> [3] "prediction_quantiles.csv" "residuals_oof.csv"       
#> [5] "response_long.csv"       
data.table::fread(file.path(root, "export", "Yo.csv"))
#>    SampleID response     p    value    r2 dataset
#>      <char>   <char> <num>    <num> <int>  <char>
#> 1:       P1   target  0.50 5.166667     1    demo
#> 2:       P2   target  0.50 6.500000     1    demo
#> 3:       P1   target  0.90 5.166667     1    demo
#> 4:       P2   target  0.90 6.500000     1    demo
#> 5:       P1   target  0.95 5.166667     1    demo
#> 6:       P2   target  0.95 6.500000     1    demo

unlink(root, recursive = TRUE)
# }