funcml is a functional machine learning framework for tabular data in
R.
funcml is listed in the CRAN Task View: Machine Learning &
Statistical Learning.
It provides one explicit interface for the core modeling workflow:
- fit models with
fit() - generate predictions with
predict() - validate performance with
evaluate() - tune hyperparameters with
tune() - compare learners with
compare_learners() - interpret fitted models with
interpret() - estimate causal effects with
estimate()
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.
A companion paper for funcml is submitted to JMLR.
Installation
install.packages("funcml") 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 #> 17 adaboost fit() predict() tune() TRUE TRUE TRUE TRUE #> 24 bart fit() predict() tune() TRUE TRUE TRUE TRUE #> 11 C50 fit() predict() tune() TRUE TRUE TRUE TRUE #> 20 cforest fit() predict() tune() TRUE TRUE TRUE TRUE #> 19 ctree fit() predict() tune() TRUE TRUE TRUE TRUE #> 7 densemlp fit() predict() tune() TRUE TRUE TRUE TRUE #> 8 e1071_svm fit() predict() tune() TRUE TRUE TRUE TRUE #> 13 earth fit() predict() tune() TRUE TRUE TRUE TRUE #> 16 fda fit() predict() tune() TRUE TRUE TRUE TRUE #> 14 gam fit() predict() tune() TRUE TRUE TRUE TRUE #> 10 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 #> 12 kknn fit() predict() tune() TRUE TRUE TRUE TRUE #> 21 lda fit() predict() tune() TRUE TRUE TRUE TRUE #> 23 lightgbm fit() predict() tune() TRUE TRUE TRUE TRUE #> 6 mlp fit() predict() tune() TRUE TRUE TRUE TRUE #> 15 naivebayes fit() predict() tune() TRUE TRUE TRUE TRUE #> 5 nnet fit() predict() tune() TRUE TRUE TRUE TRUE #> 18 pls fit() predict() tune() TRUE TRUE TRUE TRUE #> 22 qda fit() predict() tune() TRUE TRUE TRUE TRUE #> 9 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 #> 26 stacking fit() predict() tune() TRUE TRUE TRUE TRUE #> 27 superlearner fit() predict() tune() TRUE TRUE TRUE TRUE #> 25 xgboost fit() predict() tune() TRUE TRUE TRUE TRUE
list_tunable_learners() #> learner fit predict tune has_fit has_predict has_tune available #> 17 adaboost fit() predict() tune() TRUE TRUE TRUE TRUE #> 24 bart fit() predict() tune() TRUE TRUE TRUE TRUE #> 11 C50 fit() predict() tune() TRUE TRUE TRUE TRUE #> 20 cforest fit() predict() tune() TRUE TRUE TRUE TRUE #> 19 ctree fit() predict() tune() TRUE TRUE TRUE TRUE #> 7 densemlp fit() predict() tune() TRUE TRUE TRUE TRUE #> 8 e1071_svm fit() predict() tune() TRUE TRUE TRUE TRUE #> 13 earth fit() predict() tune() TRUE TRUE TRUE TRUE #> 16 fda fit() predict() tune() TRUE TRUE TRUE TRUE #> 14 gam fit() predict() tune() TRUE TRUE TRUE TRUE #> 10 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 #> 12 kknn fit() predict() tune() TRUE TRUE TRUE TRUE #> 21 lda fit() predict() tune() TRUE TRUE TRUE TRUE #> 23 lightgbm fit() predict() tune() TRUE TRUE TRUE TRUE #> 6 mlp fit() predict() tune() TRUE TRUE TRUE TRUE #> 15 naivebayes fit() predict() tune() TRUE TRUE TRUE TRUE #> 5 nnet fit() predict() tune() TRUE TRUE TRUE TRUE #> 18 pls fit() predict() tune() TRUE TRUE TRUE TRUE #> 22 qda fit() predict() tune() TRUE TRUE TRUE TRUE #> 9 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 #> 26 stacking fit() predict() tune() TRUE TRUE TRUE TRUE #> 27 superlearner fit() predict() tune() TRUE TRUE TRUE TRUE #> 25 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 conf_high #> 1 accuracy 0.7473 0.0146 4 0.0073 0.95 0.7241 0.7706 #> 2 precision 0.6932 0.0234 4 0.0117 0.95 0.6559 0.7304 #> 3 recall 0.6405 0.0178 4 0.0089 0.95 0.6121 0.6689 #> 4 specificity 0.6405 0.0178 4 0.0089 0.95 0.6121 0.6689 #> 5 f1 0.6657 0.0195 4 0.0098 0.95 0.6347 0.6968 #> 6 balanced_accuracy 0.6405 0.0178 4 0.0089 0.95 0.6121 0.6689 #> 7 logloss 0.4925 0.0088 4 0.0044 0.95 0.4785 0.5065 #> 8 brier 0.3278 0.0076 4 0.0038 0.95 0.3158 0.3398 #> 9 auc 0.7869 0.0118 4 0.0059 0.95 0.7681 0.8058 #> 10 ece 0.0359 0.0042 4 0.0021 0.95 0.0292 0.0426 #> 11 mce 0.0800 0.0137 4 0.0068 0.95 0.0583 0.1018
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 conf_high #> 8 3 0.1 30 0.4933 0.0119 3 0.0069 0.95 0.4636 0.5229
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 conf_high #> 1 glm accuracy 0.7451 0.0170 4 0.0085 0.95 0.7180 0.7722 #> 2 glm logloss 0.4897 0.0131 4 0.0066 0.95 0.4688 0.5106 #> 3 rpart accuracy 0.7337 0.0167 4 0.0084 0.95 0.7071 0.7603 #> 4 rpart logloss 0.5311 0.0130 4 0.0065 0.95 0.5104 0.5517 #> 5 xgboost accuracy 0.7473 0.0146 4 0.0073 0.95 0.7241 0.7706 #> 6 xgboost logloss 0.4925 0.0088 4 0.0044 0.95 0.4785 0.5065 #> tuned rank #> 1 FALSE 2 #> 2 FALSE 1 #> 3 FALSE 3 #> 4 FALSE 3 #> 5 FALSE 1 #> 6 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)
Partial dependence shows the model-implied effect of one feature, averaged over the rest of the data.
pdp_obj <- interpret( fit = fit_obj, data = demo_dat, method = "pdp", features = c("age"), type = "prob" ) plot(pdp_obj)
SHAP values explain an individual prediction.
interpret(method = "shap") computes them with funcml’s own Monte Carlo
permutation estimate (no external SHAP dependency); plot() supports
waterfall, force, beeswarm/summary, importance, dependence,
dependence2d, and interaction views.
shap_obj <- interpret( fit = fit_obj, data = demo_dat, method = "shap", newdata = demo_dat[1, , drop = FALSE], nsim = 30, type = "prob", seed = 42 ) plot(shap_obj, kind = "waterfall")
The beeswarm/summary view explains the model across many observations at once, ordered by mean absolute SHAP value and colored by feature value.
shap_many_obj <- interpret( fit = fit_obj, data = demo_dat, method = "shap", newdata = demo_dat[1:80, , drop = FALSE], nsim = 15, type = "prob", seed = 42 ) plot(shap_many_obj, kind = "beeswarm")
Other supported methods include ICE, local explanations, surrogate models, and interaction diagnostics.
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)
Decision curve analysis
interpret(method = "dca") reports net benefit across risk thresholds
against the “treat all” and “treat none” strategies (Vickers and Elkin,
2006).
dca_obj <- interpret( fit = fit_obj, data = demo_dat, method = "dca" ) plot(dca_obj)
ROC curve and AUC confidence interval
roc_curve() and auc_ci() are standalone metric functions (backed by
pROC) for a full ROC curve and a DeLong or bootstrap confidence
interval on AUC.
truth_vec <- demo_dat$status prob_vec <- predict(fit_obj, demo_dat, type = "prob")[, "Yes"] roc_obj <- roc_curve(truth_vec, prob_vec) plot(roc_obj)
auc_ci(truth_vec, prob_vec) #> auc conf_low conf_high conf_level method #> 1 0.8056 0.7929 0.8183 0.95 delong
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]
By default, plot() shows the model-implied potential outcome
distributions under treatment and control, with dashed lines marking the
corresponding means. The unit-level effect histogram remains available
with plot(est_obj, style = "effects").
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:
- train models
- generate predictions
- validate performance
- tune hyperparameters
- compare learners
- interpret fitted models
- estimate causal effects
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, please cite it.
pkgload::unload("funcml") library(funcml) citation("funcml") #> To cite package 'funcml' in publications use: #> #> El Badisy I (2026). _funcml: Functional Machine Learning Framework_. #> R package version 0.8.8, <https://github.com/ielbadisy/funcml>. #> #> A BibTeX entry for LaTeX users is #> #> @Manual{, #> title = {funcml: Functional Machine Learning Framework}, #> author = {Imad {El Badisy}}, #> year = {2026}, #> note = {R package version 0.8.8}, #> url = {https://github.com/ielbadisy/funcml}, #> }











