funcml is a functional machine learning framework for tabular data in
R.
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.
install.packages("remotes")
remotes::install_github("ielbadisy/funcml")The design of funcml centers on a small set of functions:
fit()
predict()
evaluate()
tune()
compare_learners()
interpret()
estimate()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 TRUElist_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 TRUElist_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 TRUEThis 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() 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: 4856The 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 Yespred_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.49358952evaluate() 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.10178991plot(eval_obj)funcml also supports grouped cross-validation, time-based resampling,
and holdout validation through group_cv(), time_cv(), and
holdout().
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.5229124plot(tune_obj)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 2plot(compare_obj)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.0003398597plot(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.
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() 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 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.50149842funcml 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.
Contributions are welcome.
For development setup, coding standards, and pull request guidelines,
see CONTRIBUTING.md.
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}
}






