Skip to content

tidylearn

0.6.0Package record

A Unified Tidy Interface to R's Machine Learning Ecosystem

0packages depend
3.7Kdownloads / year
85.3%test coverage
13/13flavors OK

Overview

About

Provides a unified tidyverse-compatible interface to R's machine learning ecosystem - from data ingestion to model publishing. The tl_read() family reads data from files ('CSV', 'Excel', 'Parquet', 'JSON'), databases ('SQLite', 'PostgreSQL', 'MySQL', 'BigQuery'), and cloud sources ('S3', 'GitHub', 'Kaggle'). The tl_model() function wraps established implementations from 'glmnet', 'randomForest', 'xgboost', 'e1071', 'rpart', 'gbm', 'nnet', 'cluster', 'dbscan', and others with consistent function signatures and tidy tibble output. Results flow into unified 'ggplot2'-based visualization and optional formatted 'gt' tables via the tl_table() family. The underlying algorithms are unchanged; 'tidylearn' simply makes them easier to use together. Access raw model objects via the $fit slot for a supervised method, or $fit$model for an unsupervised one. Methods include random forests Breiman (2001) doi:10.1023/A:1010933404324, LASSO regression Tibshirani (1996) doi:10.1111/j.2517-6161.1996.tb02080.x, elastic net Zou and Hastie (2005) doi:10.1111/j.1467-9868.2005.00503.x, support vector machines Cortes and Vapnik (1995) doi:10.1007/BF00994018, and gradient boosting Friedman (2001) doi:10.1214/aos/1013203451.

Changes in 0.6.0

Breaking Changes

  • tidylearn requires R 4.1.0 or later. The package, its README and the vignettes use the native |> pipe, which R 3.6 and 4.0 cannot parse. magrittr's %>% is still re-exported, so existing code that pipes with it after library(tidylearn) keeps working.
  • tidylearn requires ggplot2 3.4.0 or later. The plots set line widths with the linewidth aesthetic, which ggplot2 3.3 ignores with an unknown-parameter warning and draws at the default width. The rlang floor rises from 0.4.0 to 1.0.0, the version ggplot2 3.4.0 imports, so it changes nothing for an install that meets the ggplot2 one.
  • Some calls that ran in 0.5.0 are now errors, with a message naming the problem: each passed an argument tidylearn ignored or returned a meaningless result. Bug Fixes describes all of them. Among them are:
Show all changes in 0.6.0Hide the rest of the changes in 0.6.0
  • an argument a method cannot use, such as maxdeth = 1 or offset = with method = "tree", a name glmnet does not take with "ridge", "lasso" or "elastic_net", and a misspelt argument to tl_pipeline();
  • an offset() term with a method that cannot apply it at predict(), which is every method but "linear", "polynomial" and "logistic";
  • a metric name tl_evaluate() or tl_cv() does not compute, such as "RMSE";
  • predict(type = "prob") or type = "class" on a regression model, and a misspelt type;
  • tl_prepare_data(impute_method = "knn"), and tl_split() with a prop outside (0, 1);
  • repeated model names in tl_compare_cv() and tl_plot_importance_comparison();
  • type in tl_plot_interaction(), and an exclude_vars in tl_auto_interactions() that is not a predictor;
  • a numeric response in tl_semisupervised(), and tl_anomaly_aware(action = "downweight") with "svm" or "deep".
  • tl_model() makes a text predictor a factor before fitting, and stores it as one in $data. method = "forest" coded a character column as numbers by the values present in whichever frame it was handed, so a row's prediction depended on the rows scored with it: on a 120-row frame drawn after set.seed(7), in which group "c" sits near 10, three "c" rows scored alone predicted -0.11, -0.15 and 0.45, and 9.47, 9.26 and 9.78 inside the full frame. A forest now splits on the column as a category, so its fitted values change, and a text column with more than 53 distinct values is refused by randomForest ("Can not handle categorical predictors with more than 53 categories"); exclude identifiers with y ~ . - id. method = "boost" fits a text predictor, where gbm refused it ("variable 1: grp is not of type numeric, ordered, or factor"), and "xgboost" predicts a single row of one, where it failed with "contrasts can be applied only to factors with 2 or more levels". A text column used only inside a term, such as as.numeric(code), keeps its type.
  • predict() reads a supervised model's categorical columns against the levels it was trained on, before any method sees them. New data holding only some of the categories works with "forest", which failed with "Type of predictors in new data do not match that of the training data" for data.frame(cyl = factor("6"), wt = 3). A value given as text, or as the number a factor was made from, reads the same. A level the model was not trained on is an error naming the column, the level and the training levels; "boost" used to return a prediction for it, and the other methods' errors came from their backends.
  • **predict() on a "ridge", "lasso" or "elastic_net" model now uses lambda_1se, so its predictions change.** It used lambda_min, while tl_coefficients(), tl_table_coefficients() and importance all report lambda_1se by default, so the coefficients on display were not the ones behind the predictions. lambda_1se is the penalty the fit itself was documented as preferring for generalisation. Metrics, cross-validation and tuning scores for these methods move with it.
  • A "ridge", "lasso" or "elastic_net" model is now the full-data fit cv.glmnet() makes itself, in place of a second glmnet() run along the same penalties. The two agreed only to glmnet's convergence tolerance, so coefficients and predictions move slightly -- by up to 0.004 at lambda_1se for mpg ~ . on mtcars with set.seed(1) -- and now match coef() and predict() on the cv.glmnet object kept in attr(model$fit, "cv_results"). When cross-validation chooses the largest penalty, every slope is now exactly zero: the second fit left one at about -6e-17, which tl_table_importance() ranked at importance 100 and tl_plot_importance_regularized() drew as a bar of 5.9e-17 (predictor b of 40 rows of noise drawn after set.seed(3)). Both now stop with the message that the penalty dropped every predictor, as for any penalty that keeps none.
  • method = "polynomial" keeps a numeric term that is also part of an interaction as it is and adds its powers as I(x^2) up to the degree. For mpg ~ wt * hp the fit and its predictions are those of 0.5.0, but the terms are now wt, hp, I(wt^2), I(hp^2) and wt:hp, where 0.5.0 named them poly(wt, degree = 2, raw = TRUE)1, poly(wt, degree = 2, raw = TRUE)2 and so on, so tl_coefficients() and tl_table_coefficients() list other names in another order.
  • predict() on an unsupervised model returns .obs_id, the row names of the data predicted on, and as many components as the model keeps, on both the training and the new-data path. A two-dimensional MDS fit from tl_reduce_dimensions(n_components = 2) predicted .obs_id and Dim1 only, and Dim1 and Dim2 without .obs_id for tibble input. PCA's training projection returned every component however many were kept. k-means assignments of new data had no .obs_id, and PCA projections of new data numbered the rows "1", "2" whatever they were called.
  • predict(type = "prob") on an "xgboost" model returns a tibble, as every other method does. It returned a data frame.
  • tl_split(stratify = ) cuts a numeric column with more than five distinct values at its quartiles. Each distinct value used to be a stratum, and a stratum holding a single row corrupted the split: sample() on one number draws from 1:n, so that stratum drew a row from elsewhere in the data -- sometimes one already drawn -- and left its own row in test. On 50 rows of a continuous y with seed = 1, 0.5.0 drew 50 training rows holding only 22 distinct observations and put 28 in test; the same call now splits 38/12, each quartile at prop. On mtcars stratified by mpg, most of whose values occur once, the split with seed = 1 returned 43 rows from 32, and now splits 24/8. A numeric column with five or fewer distinct values, such as cyl, is still split by value. An integer ID such as 1:50 has more than five, so it is cut at its quartiles like any other numeric column. A stratum of a single row goes to the training set, so a level seen once is one the model was trained on. When such strata together hold more than a tenth of the rows, as in a character ID column, they are pooled into one stratum and split together; for a column of 50 distinct strings that is the unstratified draw, 40/10. A split that leaves the test set empty, which only a single row now does, warns.
  • tl_model(method = "deep") holds out a random set of rows for validation_split, recorded in $fit$validation_rows. keras holds out the last rows as given, which on iris, sorted by species, were rows 121 to 150: 30 of the 50 virginica rows, so the model trained on 20 virginica against 50 of each other class and was validated on virginica alone. A row with a missing value is dropped from the predictors and the response together; the response kept it, so keras trained on pairs shifted by one row. A constant predictor is no longer scaled by its standard deviation of 0, which turned it into NaN and gave every row the same prediction.
  • tl_tune_xgboost(), tl_tune_nn() and tl_tune_deep() read the task from the response, as tl_model() does. is_classification defaults to NULL, which treats a factor or character response, including one the formula computes such as factor(am), as classification. With the old default of FALSE, tl_tune_xgboost(iris, Species ~ .) was tuned as a regression on the class codes without a message, and tl_tune_nn() and tl_tune_deep() failed. is_classification = FALSE with a factor response is an error, and so is is_classification = TRUE with a computed response that is not a factor, such as I(mpg > 20), which tl_tune_nn() ran; the message points to factor() on the left-hand side. The response is reduced to the classes it holds, so a two-class subset of iris that still declares setosa is tuned as two classes; tl_tune_xgboost() had tuned it with multi:softprob and a setosa probability column.
  • tl_tune_deep() returns the best configuration as a tidylearn_model in $model, so predict() and the deep plots take it; the keras model is at $model$fit$model. It returned the internal list, and predict() on it failed with no applicable method. Every configuration is scored on the same randomly held-out rows.
  • tl_default_param_grid("xgboost") returns a grid: the values tl_tune_xgboost() searches by default, plus nrounds, which that function picks by early stopping and tl_tune_grid() has to tune. It warned "Unknown method" and returned an empty list. is_classification, which changed no grid, now changes two regression grids: "svm" also tunes epsilon, and the large "forest" grid uses nodesize = c(3, 5, 10) around randomForest's regression default of 5 in place of c(1, 3, 5). With the default is_classification = TRUE the grids are unchanged.
  • tl_plot_xgboost_importance() returns a ggplot, as documented, and ranks by the measure importance_type names. It returned xgb.plot.importance()'s data.table, drew with base graphics, and ignored importance_type. A linear booster (booster = "gblinear") has only coefficients, which importance_type = "weight" draws, ranked by size; left at its default, importance_type takes them for such a model.
  • tl_plot_partial_dependence() on a classification model draws one line per class when there are three or more, and the positive class (the second level) for two, named on the y axis. Its data has a class column for the class each row describes. The curve was the mean probability of the second class alone, and the multiclass class column held whichever class had the highest mean probability, which was not the class drawn.
  • ... in tl_semisupervised() and tl_stratified_models() reaches the supervised model only, and the new cluster_args takes the clustering step's settings. Both stages got ..., so cp = 0.001 failed in k-means with "unused argument", and nstart = 5 reached k-means and then broke glm(). A clustering setting now goes in cluster_args, e.g. cluster_args = list(nstart = 5); one left in ..., such as nstart, iter.max, algorithm, hclust_method or pam's variant, is refused with a message saying so. sampsize, keep.data and trace, which randomForest, gbm and nnet take, still reach the supervised model.
  • tl_semisupervised() with a response the formula computes, such as factor(am) ~ wt + hp + qsec, writes each propagated label to the column the response is computed from, as that column's own value in a labelled row of the same class. The returned $data$am therefore holds 0 and 1, where it held a factor.
  • tl_interaction_effects() holds a variable it does not vary at its most frequent value, as tl_plot_interaction() does. It held a factor at its first level: with carb a factor, mpg ~ wt * hp + carb was evaluated at carb = 1 by one function and carb = 2 by the other.
  • tl_interaction_effects() returns a factor variable in its results -- var, by_var or a variable it holds fixed -- as a factor with the model's levels, where it was a character vector; the values are unchanged. That is what lets it work for a forest with a factor predictor, which failed with Type of predictors in new data do not match that of the training data because the grid held the factor as text. Both it and tl_plot_interaction() leave out a factor level no row uses: on iris without setosa, both predicted at setosa, which predict() refused as a new level. They also leave out a missing value of a character variable, which tl_interaction_effects() failed on with 0 (non-NA) cases. A logical variable is treated as two-level; both functions failed with variable 'lg' was fitted with type "logical" but type "numeric" was supplied. A factor value given in at_values or fixed_values takes the column's levels, and one that is not a level is refused. mpg ~ log(wt) * hp no longer warns that the model has no wt:hp interaction.
  • tl_interaction_effects() reports fit, lower, upper and slope on the response scale whether or not intervals = TRUE, and its se column is removed. With intervals a logistic model's values were log odds (am ~ wt * hp gave fit from -32 to 40) and without them probabilities. A glm's interval is now built on the link scale and transformed back, and a linear model's is the t-based interval predict.lm() gives. For a glm the se column was on the link scale. A model with no standard errors, such as a tree, failed with $ operator is invalid for atomic vectors and now returns point estimates with a message.
  • augment_hclust() attaches clusters by position. It joined on row_number(), which counts within each group, so on a grouped tibble of USArrests cut at k = 3 34 of 50 rows received another row's cluster. Data with a different number of rows from the tree was padded with NA or cut short without a message; it is now an error naming both counts. The caller's grouping stays on the returned data, and so do its row names, which the join reset to "1", "2", ...; a cluster column the data already has is kept beside the new one under dplyr's repaired names (cluster...5 and cluster...6 for USArrests), where the join gave cluster.x and cluster.y.
  • tidy_rules(), and so tidy_apriori()'s rules_tbl, gains the list columns lhs_items and rhs_items, each side's items as a character vector, after the quality measures. The item-matching helpers read them; a table of rules without them is refused with a message saying to keep them, and a tidy_apriori() result saved without them is rebuilt from the rules it carries. An empty rule set now gives a zero-row tibble with the usual columns. It gave a tibble with no columns, so recommend_products() failed with object 'confidence' not found, filter_rules_by_item() and find_related_items() with object 'lhs' not found, and visualize_rules() when the plot was drawn; they now return zero rows, or an empty plot.
  • tidy_pam()'s medoid_index is the medoid's integer row position. pam() reports medoids by label when the distances carry labels, so tidy_pam(mtcars, k = 3) gave "Toyota Corona", "Merc 450SE" and "Duster 360" where the same data as a tibble gave 21, 12 and 7. Both now give 21, 12 and 7.
  • calc_validation_metrics() and compare_clusterings() gain an n_noise column, after avg_size, counting the points labelled 0, DBSCAN's label for noise. The other clustering methods number their clusters from 1, so it is 0 for them. The columns after it move one place along.
  • Counts that ran a range backwards or reached cutree() as a vector are refused with a message naming the argument. get_pca_loadings() and augment_pca() with n_components = 0 returned PC1, since 1:0 is c(1, 0), and get_pca_loadings(n_components = 5) on a four-component PCA returned all four; n_components must now be between 1 and the number of components. tidy_cutree(k = 2:3) returned 100 rows

The NEWS section is longer than shown here.

From NEWS.md in the release

Install

Health

CRAN checks
13OK
Slowest check: 13.5 min · r-oldrel-windows-x86_64
Status changes
  • OK13 OK2026-08-04
  • NOTE12 OK, 1 NOTE2026-08-01
  • OK13 OK2026-06-09
  • ERROR12 OK, 1 ERROR2026-06-08
  • OK14 OK2026-04-14
Show 2 earlier changesHide 2 earlier changes
  • ERROR13 OK, 1 ERROR2026-04-10
  • OK14 OK2026-03-10
Advisories

none known

Documentation

In release 0.6.0
READMEYes · 1,343 wordsVignettesYes · 11 · evaluation depends on the environmentNEWSYes · 100% structured · mentions 0.6.0Citation fileYes · computed when R runs itWebsiteYes · pkgdown
Help pages
243 (39 internal)includes a package overview page
Examples that run
17%30 run in a plain check (6 of them under a condition) · 140 only when donttest examples are enabled (R CMD check --as-cran) · 9 never run
Exported functions with examples
99%
Documented parameters
100%
Return-value docs
100%
Help pages citing references
0%

Downloads

3.7K
CRAN downloads in the past year
Rank #8,813 · ~10/day · ~311/mo
Daily download trend is not available in this view yet.
40430 days
1.1K90 days
3.7K1 year
Compare downloads with other packages →
Also on109 r2u5 autocran

Repository

5Stars
1Forks
0Open issues
0Open PRs
0Releases
188Commits
2Commit identities
188 commits · Last activity 2026-10-09 · 0% stars, 30d · Default branch at 0.6.0.9000, ahead of CRAN 0.6.0 (checked 2026-10-18)
Responsiveness
How these are sampled
PRs merged (all time)
100%
Median days to close, 50 most recently updated closed issues
26
Median days to close, 50 most recently updated closed PRs
0

Stars over time

2026-04-13 · 32026-07-07 · 5
PracticesBeta

10 development-tooling and community-health practices detected across 5 families in the upstream repository

Checks run against github.com/ces0491/tidylearn on 2026-10-18.

Continuous integration (2)
GitHub ActionsR CMD check workflow

The R CMD check workflow runs on Linux, macOS and Windows, and on R-devel

Governance and community (1)
Contributing guide
Docs source (3)
pkgdown

GitHub Pages site last deployed 2026-10-09 · The repository has a site deploy workflow

pkgdown site last built 2026-10-09

CRAN release process (2)
cran-comments.mdCRAN-SUBMISSION
Show all practicesHide 1 practice
Lint, format, editor (2)
lintrRStudio project
How this is detected·Detection ruleset v3 (2026-09-26)
AI coding toolsBeta

This repository shows signs of AI coding tools.

  • Claude Codefirst seen 2026-01-19
    Named in .Rbuildignore: .claude
    Named in .gitignore: .claude
    Pull request it wrote: opened by a project member
    Commits: at least 134 crediting it in the message
Models named in its commits
  • Claude Opus 547 commits · Aug to Sep 2026
  • Claude Opus 5.542 commits · Oct 2026
  • Claude Opus 4.68 commits · Mar to Apr 2026
  • Claude Opus 4.73 commits · May 2026

Some of these counts are a minimum, because the search stopped before the oldest commits.

Counts are commits, not lines of code. Commits by a tool's accounts count once across all of its accounts. Commits crediting it are the largest count among its credit lines, a minimum.How this is detected·Detection ruleset v4 (updated 2026-09-27)

Dependencies

Declared dependencies
50 external dependencies (excludes base and recommended)

Installing tidylearn adds 122 packages (67 with compiled code, 95 MB of source tarballs). Heaviest: stringi 11 MB, ggplot2 6.0 MB, data.table 5.7 MB.

Depends (1)
R >= 4.1.0
LinkingTo (0)
none
Enhances (0)
none
Reverse dependencies
0direct
0indirect

Nothing depends on this yet.

People & History

People (1)
Author, Maintainer since 0.1.0 (2026)
Releases (8)

Pick two releases to compare their code metrics.

  • 0.6.0Latest
    record
    2026-10-08 · current release · diff ↗ ·
    added 1 export
    tl_coefficients
  • 0.5.0
    record
    2026-09-02 · diff ↗ ·
    added 4 exports
    tl_cloud_allow_host, tl_cloud_allowed_hosts, tl_cloud_consent, tl_cloud_jobs
  • 0.4.0
    record
    2026-08-03 · diff ↗ ·
    added 2 exports
    tl_check_gpu, tl_compute_advisor
  • 0.3.1
    record
    2026-05-19 · diff ↗
  • R
    R 4.6.0 released · 2026-04-24
  • 0.3.0
    record
    2026-04-09 · diff ↗ ·
    added 18 exports
    tl_read, tl_read_bigquery, tl_read_csv, tl_read_db, tl_read_dir, tl_read_excel, tl_read_github, tl_read_json, tl_read_kaggle, tl_read_mysql, tl_read_parquet, tl_read_postgres, tl_read_rdata, tl_read_rds, tl_read_s3, tl_read_sqlite, tl_read_tsv, tl_read_zip
  • 0.2.0
    record
    2026-03-16 · diff ↗ ·
    added 9 exports
    tl_table, tl_table_clusters, tl_table_coefficients, tl_table_comparison, tl_table_confusion, tl_table_importance, tl_table_loadings, tl_table_metrics, tl_table_variance
  • 0.1.1
    record
    2026-03-13 · diff ↗
  • 0.1.0
    record
    2026-02-06
  • R
    R 4.5.0 released · 2025-04-11

Package metadata

First published
2026-02-06
Total releases
8 / 1 yrs
License
MIT + file LICENSE OSI
Minimum R
≥ 4.1.0
Download size
1.3 MB

Cite

Cite this package

Run in R for the authors' preferred citation:

citation("tidylearn")

The package provides a citation file that builds its entry when R runs it. Run citation() to see it.

Cite the R Observatory

For a number measured here: a download total, a coverage figure, an archival date.

APA

Balamuta, J. J. (2026). R Observatory: Metrics for tidylearn version 0.6.0 [Data set]. HJJB, LLC. Data release v2026-10-22. https://doi.org/10.5281/zenodo.21843040

From data release v2026-10-22, which the citation names so these numbers can be found later. More on citing and the projects behind them.

Report a problem with this page →

Privacy choices

These apply to this browser and are stored on this device only. Nothing about your choice is sent to us.

Read the privacy policy