funcml

funcml is a functional machine learning framework for tabular data in R.

It provides one explicit interface for the core modeling workflow:

The package is intentionally compact and opinionated: preprocessing happens before modeling, inputs stay explicit, and the API stays small instead of expanding into a large orchestration layer.

Installation

install.packages("remotes")
remotes::install_github("ielbadisy/funcml")

Core API

The design of funcml centers on a small set of functions:

fit()
predict()
evaluate()
tune()
compare_learners()
interpret()
estimate()

Explore the registry

funcml exposes a session-aware registry of learners, metrics, and interpretation methods.

list_learners()
#>         learner   fit   predict   tune has_fit has_predict has_tune available
#> 15     adaboost fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 22         bart fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 9           C50 fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 18      cforest fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 17        ctree fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 6     e1071_svm fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 11        earth fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 14          fda fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 12          gam fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 8           gbm fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 1           glm fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 3        glmnet fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 10         kknn fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 19          lda fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 21     lightgbm fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 13   naivebayes fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 5          nnet fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 16          pls fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 20          qda fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 7  randomForest fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 4        ranger fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 2         rpart fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 24     stacking fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 25 superlearner fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 23      xgboost fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
list_tunable_learners()
#>         learner   fit   predict   tune has_fit has_predict has_tune available
#> 15     adaboost fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 22         bart fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 9           C50 fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 18      cforest fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 17        ctree fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 6     e1071_svm fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 11        earth fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 14          fda fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 12          gam fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 8           gbm fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 1           glm fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 3        glmnet fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 10         kknn fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 19          lda fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 21     lightgbm fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 13   naivebayes fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 5          nnet fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 16          pls fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 20          qda fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 7  randomForest fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 4        ranger fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 2         rpart fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 24     stacking fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 25 superlearner fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
#> 23      xgboost fit() predict() tune()    TRUE        TRUE     TRUE      TRUE
list_metrics()
#>               metric direction
#> 1               rmse  minimize
#> 2                mae  minimize
#> 3                mse  minimize
#> 4              medae  minimize
#> 5               mape  minimize
#> 6                rsq  maximize
#> 7           accuracy  maximize
#> 8          precision  maximize
#> 9             recall  maximize
#> 10       specificity  maximize
#> 11                f1  maximize
#> 12 balanced_accuracy  maximize
#> 13           logloss  minimize
#> 14             brier  minimize
#> 15               auc  maximize
#> 16      auc_weighted  maximize
#> 17               ece  minimize
#> 18               mce  minimize
#>                                                       summary     range
#> 1         Root mean squared error for regression predictions.  [0, Inf)
#> 2             Mean absolute error for regression predictions.  [0, Inf)
#> 3              Mean squared error for regression predictions.  [0, Inf)
#> 4           Median absolute error for regression predictions.  [0, Inf)
#> 5  Mean absolute percentage error for regression predictions.  [0, Inf)
#> 6    Coefficient of determination for regression predictions. (-Inf, 1]
#> 7                                    Classification accuracy.    [0, 1]
#> 8                    Macro-averaged classification precision.    [0, 1]
#> 9                       Macro-averaged classification recall.    [0, 1]
#> 10                 Macro-averaged classification specificity.    [0, 1]
#> 11                                   Macro-averaged F1 score.    [0, 1]
#> 12                          Macro-averaged balanced accuracy.    [0, 1]
#> 13  Negative log-likelihood for classification probabilities.  [0, Inf)
#> 14              Brier score for classification probabilities.    [0, 2]
#> 15                                  Area under the ROC curve.    [0, 1]
#> 16              Weighted multiclass area under the ROC curve.    [0, 1]
#> 17      Expected calibration error for binary classification.    [0, 1]
#> 18       Maximum calibration error for binary classification.    [0, 1]
list_interpretability_methods()
#>                                  compute   plot has_compute has_plot
#> 1              interpret(method = "vip") plot()        TRUE     TRUE
#> 2          interpret(method = "permute") plot()        TRUE     TRUE
#> 3              interpret(method = "pdp") plot()        TRUE     TRUE
#> 4              interpret(method = "ice") plot()        TRUE     TRUE
#> 5              interpret(method = "ale") plot()        TRUE     TRUE
#> 6            interpret(method = "local") plot()        TRUE     TRUE
#> 7             interpret(method = "lime") plot()        TRUE     TRUE
#> 8             interpret(method = "shap") plot()        TRUE     TRUE
#> 9      interpret(method = "local_model") plot()        TRUE     TRUE
#> 10     interpret(method = "interaction") plot()        TRUE     TRUE
#> 11       interpret(method = "surrogate") plot()        TRUE     TRUE
#> 12         interpret(method = "profile") plot()        TRUE     TRUE
#> 13 interpret(method = "ceteris_paribus") plot()        TRUE     TRUE
#> 14     interpret(method = "calibration") plot()        TRUE     TRUE

Example data

This README uses funcml::arthritis as the main running example.

Here, status is the outcome for a binary classification task.

demo_dat <- funcml::arthritis
demo_dat$status <- as.factor(demo_dat$status)
levels(demo_dat$status)
#> [1] "No"  "Yes"

Fit a classification model

fit() trains a model and returns a funcml_fit object.

xgb_spec <- list(
  nrounds = 30,
  max_depth = 3,
  eta = 0.1,
  subsample = 1,
  colsample_bytree = 1
)

fit_obj <- fit(
  status ~ age + gender + bmi + diabetes + smoke + covered_health,
  data = demo_dat,
  model = "xgboost",
  spec = xgb_spec,
  seed = 42
)

fit_obj
#> <funcml_fit> classification model: xgboost
#> Formula: status ~ age + gender + bmi + diabetes + smoke + covered_health
#> Features: 6 | Obs: 4856

Generate predictions

The same fitted object can produce class predictions or class probabilities.

predict(fit_obj, demo_dat[1:6, ])
#> [1] Yes No  No  No  No  No 
#> Levels: No Yes
pred_prob <- predict(
  fit_obj,
  demo_dat[1:6, ],
  type = "prob"
)

pred_prob
#>             No        Yes
#> [1,] 0.4382392 0.56176078
#> [2,] 0.5414010 0.45859897
#> [3,] 0.8288925 0.17110750
#> [4,] 0.9638367 0.03616334
#> [5,] 0.5076765 0.49232352
#> [6,] 0.5064105 0.49358952

Evaluate predictive performance

evaluate() applies the same learner under a resampling plan and returns fold-level results with summary statistics.

eval_obj <- evaluate(
  data = demo_dat,
  formula = status ~ age + gender + bmi + diabetes + smoke + covered_health,
  model = "xgboost",
  spec = xgb_spec,
  resampling = cv(v = 4, seed = 42)
)

eval_obj
#> <funcml_eval> model: xgboost | task: classification
#>               metric       mean          sd n   std_error conf_level   conf_low
#> 1           accuracy 0.74732290 0.014617703 4 0.007308852       0.95 0.72406287
#> 2          precision 0.69316319 0.023420234 4 0.011710117       0.95 0.65589637
#> 3             recall 0.64049156 0.017832484 4 0.008916242       0.95 0.61211610
#> 4        specificity 0.64049156 0.017832484 4 0.008916242       0.95 0.61211610
#> 5                 f1 0.66573813 0.019521730 4 0.009760865       0.95 0.63467470
#> 6  balanced_accuracy 0.64049156 0.017832484 4 0.008916242       0.95 0.61211610
#> 7            logloss 0.49248120 0.008783385 4 0.004391692       0.95 0.47850488
#> 8              brier 0.32776953 0.007550594 4 0.003775297       0.95 0.31575485
#> 9                auc 0.78694529 0.011843752 4 0.005921876       0.95 0.76809924
#> 10               ece 0.03590688 0.004195513 4 0.002097757       0.95 0.02923089
#> 11               mce 0.08002388 0.013678803 4 0.006839402       0.95 0.05825786
#>     conf_high
#> 1  0.77058293
#> 2  0.73043001
#> 3  0.66886702
#> 4  0.66886702
#> 5  0.69680156
#> 6  0.66886702
#> 7  0.50645753
#> 8  0.33978421
#> 9  0.80579135
#> 10 0.04258288
#> 11 0.10178991
plot(eval_obj)

funcml also supports grouped cross-validation, time-based resampling, and holdout validation through group_cv(), time_cv(), and holdout().

Tune hyperparameters

tune() searches candidate hyperparameter settings using the same evaluation framework.

tune_grid <- expand.grid(
  max_depth = c(2, 3),
  eta = c(0.05, 0.1),
  nrounds = c(20, 30)
)

tune_obj <- tune(
  data = demo_dat,
  formula = status ~ age + gender + bmi + diabetes + smoke + covered_health,
  model = "xgboost",
  grid = tune_grid,
  resampling = cv(v = 3, seed = 42),
  metric = "logloss",
  subsample = 1,
  colsample_bytree = 1,
  seed = 42
)

tune_obj
#> <funcml_tune> metric=logloss direction=min search=grid
#> Best:
#>   max_depth eta nrounds      mean       sd n   std_error conf_level conf_low
#> 8         3 0.1      30 0.4932667 0.011934 3 0.006890096       0.95 0.463621
#>   conf_high
#> 8 0.5229124
plot(tune_obj)

Compare learners

compare_learners() benchmarks multiple learners under a common resampling design.

compare_obj <- compare_learners(
  data = demo_dat,
  formula = status ~ age + gender + bmi + diabetes + smoke + covered_health,
  models = c("glm", "rpart", "xgboost"),
  metrics = c("accuracy", "logloss"),
  resampling = cv(v = 4, seed = 42),
  specs = list(xgboost = xgb_spec)
)

compare_obj
#> <funcml_compare> task: classification | tuned: FALSE
#>     model   metric      mean          sd n   std_error conf_level  conf_low
#> 1     glm accuracy 0.7450577 0.017034681 4 0.008517341       0.95 0.7179517
#> 2     glm  logloss 0.4897129 0.013140445 4 0.006570223       0.95 0.4688036
#> 3   rpart accuracy 0.7337315 0.016711299 4 0.008355649       0.95 0.7071401
#> 4   rpart  logloss 0.5310715 0.012975648 4 0.006487824       0.95 0.5104243
#> 5 xgboost accuracy 0.7473229 0.014617703 4 0.007308852       0.95 0.7240629
#> 6 xgboost  logloss 0.4924812 0.008783385 4 0.004391692       0.95 0.4785049
#>   conf_high tuned rank
#> 1 0.7721636 FALSE    2
#> 2 0.5106223 FALSE    1
#> 3 0.7603229 FALSE    3
#> 4 0.5517186 FALSE    3
#> 5 0.7705829 FALSE    1
#> 6 0.5064575 FALSE    2
plot(compare_obj)

Interpret fitted models

interpret() operates directly on fitted funcml_fit objects.

permute_obj <- interpret(
  fit = fit_obj,
  data = demo_dat,
  method = "permute",
  nsim = 20,
  seed = 42
)

summary(permute_obj)
#>          feature   importance      std_dev
#> 1            age 0.0768121911 0.0039101175
#> 2         gender 0.0192030478 0.0032380942
#> 3            bmi 0.0175658979 0.0038212586
#> 4 covered_health 0.0056013180 0.0021176594
#> 5          smoke 0.0053953871 0.0017159311
#> 6       diabetes 0.0005663097 0.0003398597
plot(permute_obj)

A second example shows accumulated local effects for one feature from the same fitted model.

ale_obj <- interpret(
  fit = fit_obj,
  data = demo_dat,
  method = "ale",
  features = c("age"),
  type = "prob"
)

plot(ale_obj)

Other supported methods include PDP, ICE, SHAP, local explanations, surrogate models, interaction diagnostics, and calibration plots.

Inspect calibration

For classification, the same interface also supports calibration diagnostics.

calibration_obj <- interpret(
  fit = fit_obj,
  data = demo_dat,
  method = "calibration",
  type = "prob",
  bins = 10,
  strategy = "quantile"
)

plot(calibration_obj)

Estimate causal effects

estimate() extends the same framework to plug-in g-computation estimands such as the ATE.

The example below treats smoke as the treatment variable and status as the outcome, adjusting for the remaining covariates.

est_obj <- estimate(
  data = demo_dat,
  formula = status ~ smoke + diabetes + age + gender + bmi + covered_health,
  model = "glm",
  estimand = "ATE",
  treatment = "smoke",
  interval = "normal",
  seed = 42
)

est_obj
#> <funcml_estimand> ATE via g-computation
#> Treatment: smoke (Yes vs No)
#> Estimate: 0.0897 | SE: 0.0006 | 95% normal CI [0.0886, 0.0908]
plot(est_obj)

The same interface also supports ATT, CATE, and IATE.

Ensembles as first-class learners

Ensembles live in the same learner registry as base models.

stack_fit <- fit(
  status ~ age + gender + bmi + diabetes + smoke + covered_health,
  data = demo_dat,
  model = "superlearner", # or "stacking"
  spec = list(
    learners = c("glm", "rpart", "xgboost", "nnet"),
    learner_specs = list(xgboost = xgb_spec),
    meta_model = "glmnet"
  ),
  seed = 42
)

predict(stack_fit, demo_dat[1:5, ], type = "prob")
#>             No        Yes
#> [1,] 0.3184784 0.68152164
#> [2,] 0.5011472 0.49885283
#> [3,] 0.8758539 0.12414610
#> [4,] 0.9258312 0.07416884
#> [5,] 0.4985016 0.50149842

Summary

funcml provides a compact interface for tabular machine learning in R.

Use it to:

The package is designed to keep the main analysis workflow explicit.

Contributing

Contributions are welcome.

For development setup, coding standards, and pull request guidelines, see CONTRIBUTING.md.

Citation

If you use funcml in your work, cite the repository using GitHub’s Cite this repository panel or the metadata in CITATION.cff.

APA:

El Badisy, I. (2026). funcml (Version 0.7.1) [Computer software]. https://github.com/ielbadisy/funcml

BibTeX:

@software{El_Badisy_funcml_2026, author = {El Badisy, Imad}, 
license = {GPL-3.0-only},
month = apr,
title = {{funcml}},
url = {https://github.com/ielbadisy/funcml},
version = {0.7.1},
year = {2026}
}