torch is no longer a dependency. The mlp
learner now runs on the densemlp engine (C++,
RcppArmadillo) as a plain multilayer perceptron: ReLU hidden layers,
Adam, standardized inputs, no batch normalization by default. Task
support (regression, binary, multiclass) and the arguments
hidden_units, dropout,
batch_norm, epochs, batch_size,
lr, validation, early_stopping,
patience, min_delta, seed and
verbose are unchanged. activation,
optimizer, weight_decay,
standardize and device have no equivalent:
their default values ("relu", "adam",
0, TRUE,
"auto"/"cpu") are accepted silently, any other
value is ignored with a warning. The default mlp tuning
grid now varies batch_norm instead of
weight_decay. Fitted mlp models are plain R
objects, so they can be saved with saveRDS() and reused
across forked workers. Use the densemlp learner for the
engine’s advanced options (residual and gated blocks, ensembles,
learning-rate schedules).bart fits now survive
saveRDS()/readRDS(). dbarts keeps the sampler
state outside R, so a reloaded fit predicted a constant probability; the
state is now stored in the object at fit time.interpret(method = "ceteris_paribus") now profiles the
row(s) of newdata (default: the first row of
data), with each feature’s grid built from
data. It used to run ICE on every row of data
and ignore newdata. The result also carries
newdata and its observed prediction.plot() on an
interpret(method = "ceteris_paribus") result has its own
method: it is titled “Ceteris paribus profile” (not “ICE plot”), draws
one profile per observation in newdata without the ICE mean
curve, and marks the observed feature value and its prediction with a
point on each profile."local", "local_model",
"lime"): contributions are now
beta * (x - mean(x)), centred on the reference data, and
sum to local_prediction - baseline (baseline
is new in result). Before, numeric contributions were
beta * x, so 0/1 predictors at 0 gave empty explanations.
k now picks the k largest contributions after
dropping zero ones (it used to rank by |beta| and then drop zeros)."lime" is now a distinct method: the surrogate is
fitted on nperturb points sampled from the feature
marginals with an exponential kernel, as in LIME. "local"
and "local_model" remain aliases of the similarity-weighted
surrogate on the observed data.estimate() checks positivity up front: a clear error
when the treatment has one observed value, a warning when an arm has
fewer than 10 rows. With interval = "bootstrap", a resample
without treated or control rows is redrawn instead of stopping the whole
call with “Treatment must be binary”, and a failing resample is dropped
with a warning. The counts are returned in $bootstrap.interpret(method = "shap") no longer warns “row names
were found from a short variable” with learners that return named
predictions (ranger).Bug fixes found while benchmarking every learner on 63 biomedical datasets.
compare(ncores > 1) now keeps the per-fold results
in $details. The parallel worker stored them with
<<-, which is lost in a forked process, so only the
summaries survived.glmnet learner is no longer an
intercept-only model. With lambda = NULL it predicted at
the largest lambda of the path, where every coefficient is zero; lambda
is now chosen by cross-validation (cv.glmnet(),
lambda.min). glmnet also accepts a single
predictor.gam: predictors with too few distinct values (binary,
dummy-coded) enter linearly instead of as smooths, and non-syntactic
column names such as agegp35-44 no longer break the
formula.randomForest predicts correctly when dummy-column names
are not syntactic; the new data was built with
check.names = TRUE and no longer matched the training
columns.adaboost handles non-syntactic column names and maps
the probability columns to the class labels by the sorted label order
that ada uses.stacking and superlearner no longer
include glm (binary only) among the default base learners
for a multiclass outcome.glmnet with a given lambda (as in tuning
grids) is fitted along the whole path with that lambda added, instead of
from a single cold start. A single small lambda took minutes on 15,000
rows and often failed to converge, returning an empty (intercept-only)
model.interpret(method = "vip", importance_type = "model")
returns the learner’s native importance again (e.g. impurity for
ranger and rpart, relative influence for
gbm). It had been silently replaced by permutation
importance. Scores of dummy-coded factor levels are summed per feature;
"auto" uses native importance when the learner has one, and
"model" on a learner without one is now an error.ranger learner exposes its native importance; the
function had been attached to nnet by mistake.default_tune_grid() returns a default
hyperparameter grid for each learner. tune() and
compare(tune = TRUE) use it when grid or
grids is not supplied; a learner with no hyperparameters is
evaluated with its own specs entry. Previously they stopped
with “grids must be supplied”.Remotes: ielbadisy/fastgbm now that
fastgbm is itself on CRAN; it was the only thing blocking
this package’s own CRAN resubmission..rbind_dt() row-accumulation
helper from data.table to basetable.
data.table dropped from Imports entirely (this
was its only use site); basetable added.fastgbm as a new registry learner: a
histogram-based gradient boosting engine (RcppParallel) covering
regression, binary, and multiclass classification, alongside the
existing gbm, xgboost, and
lightgbm tree ensembles. fastgbm is not yet on
CRAN, so it is listed under
Remotes: ielbadisy/fastgbm.densemlp learner wrapper: it was still
calling the retired torch-based densemlp API
(task = "classification", new_data,
activation/optimizer/weight_decay/label_smoothing/focal_gamma/
device). densemlp on CRAN is now a
C++/RcppArmadillo engine with a
task = "regression"/"binary"/"multiclass" interface and no
torch dependency; the wrapper, its default hyperparameters,
and the torch_is_installed() availability check (only
mlp still needs it) and fork-safety list are all updated to
match.compare_learners() to compare()
for consistency with the other short, verb-named entry points
(fit(), evaluate(), tune(),
interpret(), estimate()). This is a breaking
change with no backward-compatible alias: code calling
compare_learners() must be updated to call
compare(). Note that compare() masks
testthat::compare() when both packages are attached.Author/Maintainer
DESCRIPTION fields (they had drifted out of sync with
Authors@R, triggering a R CMD check NOTE) in
favor of deriving them from Authors@R, and fixed a
non-canonical CRAN task view URL in the README.
R CMD check --as-cran now passes with 0 errors, 0 warnings,
0 notes.inst/CITATION, which
hardcoded “R package version 0.7.1” and had drifted six releases behind.
R now falls back to the default citation auto-generated from
DESCRIPTION, which always reflects the installed
version.citation("funcml") output instead of hardcoded text.+0.148/-0.089 style,
signed), SHAP feature importance, SHAP interaction strength, and local
surrogate (interpret(method = "local_model"))
contributions. The local surrogate plot’s colors were also swapped to
match the SHAP convention (positive = red, negative = green).interpret(method = "shap", ncores = <n>) with
xgboost, lightgbm, mlp,
densemlp, or bart on Unix could hang
indefinitely, because functionals::fmap() forks the process
(parallel::mclapply()) and those models’ fitted state holds
a C/C++ handle that is not valid in the forked child.
ncores is now ignored (with a warning) for those models,
falling back to sequential; other models parallelize as before.kind = "waterfall") is now a
zero-anchored per-feature contribution bar chart instead of a cumulative
chained waterfall: every bar starts at 0 and extends to its own SHAP
value, so no bar crosses from one side of the reference line to the
other. The vertical reference line is fixed at 0 instead of the baseline
prediction.kind = "summary"/"beeswarm") now uses the
standard SHAP blue (low) to red (high) colorbar on the right, instead of
the previous bottom yellow-to-purple legend, and drops the per-feature
numeric labels for plain feature names. It also gained a v
argument to restrict the plot to a single feature.interpret(method = "shap") gained an
ncores argument that parallelizes the per-observation Monte
Carlo SHAP computation via functionals::fmap() (the same
backend already used by
evaluate()/tune()/compare_learners()).
Each observation is now seeded independently
(seed + observation_index - 1) so results are identical
whether run sequentially or in parallel; this changes the exact values
produced by a seeded interpret(method = "shap") call
compared to earlier releases, though the estimator itself (Monte Carlo
permutation SHAP) is unchanged.evaluate(),
compare_learners(), tune(),
interpret(method = "calibration"),
interpret(method = "dca"), roc_curve(),
auc_ci()) now round numeric columns to 4 digits by default
(digits argument on the relevant
print()/summary() methods and on
auc_ci()), instead of printing full floating-point
precision.kind = "beeswarm" / "summary") to show mean
|SHAP value| next to each feature name, a yellow-to-purple
viridis “plasma” feature-value gradient, and a bottom
legend with Low/High endpoints. Also fixed a row-order misalignment bug
in the per-feature value scaling introduced by the 0.8.0 native SHAP
plot rewrite.densemlp as a new learner, wrapping the published
densemlp CRAN package. It complements the existing built-in
mlp learner with richer architecture options (residual
connections, gated blocks, input projection, focal loss, label
smoothing, LR schedules) for regression and classification.roc_curve() and auc_ci(), backed by
the pROC package: roc_curve() returns the full
sensitivity/specificity curve plus a plot() method, and
auc_ci() reports AUC with a DeLong (default) or bootstrap
confidence interval. funcml’s own fast auc() is unchanged
and remains what resampling/tuning use internally.dca() computes net benefit across risk thresholds for the
model, “treat all”, and “treat none” strategies, and
interpret(method = "dca") runs it directly on a fitted
binary classifier with a plot() method.shapviz dependency. All SHAP plot kinds
(waterfall, force,
summary/beeswarm,
importance/bar, dependence,
dependence2d, interaction) are now native
ggplot2 implementations reading directly from funcml’s own
SHAP result table. The underlying SHAP values were already funcml’s own
Monte Carlo permutation estimate
(interpret(method = "shap")); shapviz was only ever used
for plotting.theme_funcml() to match the CLAVUS Nature
Medicine figure style: theme_classic() base, Okabe-Ito
colorblind-safe palette, bold unboxed strip labels, and
grey92 major gridlines. All package plots
(interpret(), evaluate(),
compare_learners(), tune(),
estimate()) now share this theme instead of each building
its own ad-hoc theme_bw()/theme_minimal()
variant.do.call(rbind, ...) to data.table::rbindlist()
for faster combination of many small result frames. All public return
objects remain plain data.frames; no API or behavior
change.DESCRIPTION, covering the plug-in g-computation
method.plot.funcml_pdp() now fixes the y-axis to the [0, 1]
probability scale for classification PDPs (type = "prob"),
instead of auto-scaling to the local range of the curve, which could
visually exaggerate small effects. Regression PDPs are unaffected.MASS,
mgcv, nnet, rpart,
glmnet, ranger, e1071,
randomForest, gbm, C50,
kknn, earth, naivebayes,
mda, ada, pls,
partykit, dbarts, torch,
xgboost, lightgbm, densemlp) from
Suggests to Imports, so a standard
installation always has every advertised learner available and
learners()/fit() cannot fail with a
missing-package error for a registered model.mlp as an internal torch-backed learner for
regression, binary classification, and multiclass classification.funcml companion paper is
submitted to JMLR.vip
to use permutation importance consistently while retaining
shapviz-enhanced SHAP plotting when the optional plotting
packages are installed.funcml as a machine learning framework for
R with stable S3 interfaces for fitting, prediction, evaluation, tuning,
learner comparison, interpretation, and plug-in g-computation.evaluate() and
compare_learners(), including fold-level standard errors
and confidence intervals in summaries and plots.search = "random" and
n_evals, plus nested resampling support in
tune() for outer-fold performance estimates of the
model-selection procedure.list_learners() as a learner capability catalog
and improved package metadata, citation, and repository scaffolding for
release and paper preparation.catboost learner backend from the registry
and package metadata.lightgbm as a standard learner dependency
available with funcml.evaluate() and
compare_learners(), including fold-level standard errors
and confidence intervals in summaries and plots.estimate() with configurable interval
reporting, including bootstrap percentile intervals for average causal
estimands.search = "random" and
n_evals for budgeted hyperparameter search.tune() via
outer_resampling, so tuning can report unbiased outer-fold
performance estimates for the selected workflow.vip, pdp, iml, and a minimal
internal shapviz layer.vip and pdp dependencies
with internal implementations while preserving the existing
funcml entrypoints.local / local_model to an
iml::LocalModel-style sparse local surrogate using
glmnet and Gower weighting.