R Observatory
Search
install.packages("tidylearn")
CRAN 30-day downloads, method
393−5.1% down on the 30 days before, the worse direction
Test coverage, method
85%of lines run by tests

Provides a unified tidyverse-compatible interface to R's machine learning ecosystem - from data ingestion to model publishing.

Full description

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>.

Maintainer
Cesaire Tobias
Latest release
8 Oct 2026
First release
6 Feb 2026

Compare with another package

More details
Releases
8
Needs compilation
No
Needs R
>= 4.1.0
Config/testthat/edition
3
RoxygenNote
7.3.3
Subjects (1) Method, Subjects
Cite

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.

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-28. https://doi.org/10.5281/zenodo.21843040
About

From data release v2026-10-28, which the citation names so these numbers can be found later.

All 13 check platforms pass.

  • r-devel-linux-x86_64-debian-clang

    The unreleased R on Linux, x86_64, debian-clang

    OK

    Version checked
    0.6.0
    Time taken
    557 s
  • r-devel-linux-x86_64-debian-gcc

    The unreleased R on Linux, x86_64, debian-gcc

    OK

    Version checked
    0.6.0
    Time taken
    373 s
  • r-devel-linux-x86_64-fedora-clang

    The unreleased R on Linux, x86_64, fedora-clang

    OK

    Version checked
    0.6.0
    Time taken
    401 s
  • r-devel-linux-x86_64-fedora-gcc

    The unreleased R on Linux, x86_64, fedora-gcc

    OK

    Version checked
    0.6.0
    Time taken
    368 s
  • r-devel-windows-x86_64

    The unreleased R on Windows, x86_64

    OK

    Version checked
    0.6.0
    Time taken
    706 s
  • r-oldrel-macos-arm64

    The previous release of R on macOS, arm64

    OK

    Version checked
    0.6.0
    Time taken
    136 s
  • r-oldrel-macos-x86_64

    The previous release of R on macOS, x86_64

    OK

    Version checked
    0.6.0
    Time taken
    419 s
  • r-oldrel-windows-x86_64

    The previous release of R on Windows, x86_64

    OK

    Version checked
    0.6.0
    Time taken
    772 s
  • r-patched-linux-x86_64

    The patched release of R on Linux, x86_64

    OK

    Version checked
    0.6.0
    Time taken
    536 s
  • r-release-linux-x86_64

    The current release of R on Linux, x86_64

    OK

    Version checked
    0.6.0
    Time taken
    530 s
  • r-release-macos-arm64

    The current release of R on macOS, arm64

    OK

    Version checked
    0.6.0
    Time taken
    111 s
  • r-release-macos-x86_64

    The current release of R on macOS, x86_64

    OK

    Version checked
    0.6.0
    Time taken
    695 s
  • r-release-windows-x86_64

    The current release of R on Windows, x86_64

    OK

    Version checked
    0.6.0
    Time taken
    630 s
  • 13 OK

Over time

No change since 4 Aug 2026

As a list (7)
ChangedWorst statusOKNotesWarningsErrors
4 Aug 2026OK13000
1 Aug 2026Note12100
9 Jun 2026OK13000
8 Jun 2026Error12001
14 Apr 2026OK14000
10 Apr 2026Error13001
10 Mar 2026OK14000

Since March 2026

Check results on CRAN

Total downloads in the last 30 days
410−7.2% down on the 30 days before, the worse directionIt is the sum of 3 channels: CRAN, r2u and autoCRAN.

CRAN rank

8,675 of 26,530

CRAN

393 downloads in the last 30 days

Rank
8,675 of 26,530
Change
−5.1% down on the 30 days before, the worse direction

It is in the total. Take it out

r2u

15 downloads in the last 30 days

Rank
5,485 of 30,526
Change
+15.4% up on the 30 days before, the better direction

It is in the total. Take it out

autoCRAN

2 downloads in the last 30 days

Rank
22,452 of 29,212
Change
−86.7% down on the 30 days before, the worse direction

It is in the total. Take it out

Over time

Compare downloads

Functions
524
Public exports
157
Lines of R code
33,052
Median complexity
4
Functions (524)
Size and composition

Lines by kind (68,005)

KindLinesShare
R code33,05249%
Tests21,83432%
Documentation9,07813%
Guides4,0416%

Lines by language

LanguageLinesShare
R54,88681%
Rd9,07813%
Vignettes4,0416%

Languages are counted from file extensions.

Files
372
R functions
524
Object systems
S3: 26 methods
Complexity
Median
4
Mean
5.6
Highest
54
Median lines per function
26
About complexity

Cyclomatic complexity counts the independent paths through a function: 1 is a straight line, higher is harder to test. R functions only.

Call graph figures
R functions
524
Calls
970
Unconnected
50
Groups
3
Growth (8 releases)
Total lines by release
20,736 on 6 Feb 202668,005 on 8 Oct 2026
Release changes

The tests ran and coverage was measured.

Lines run by tests
85.3%
Expressions run by tests
86.2%
Test cases
1,065
Exports named in tests
88.5%
Coverage by file (39)
Coverage run
Lines counted
15,346
Lines the tests ran
13,090
Tests passed
Yes
Measured with
covr 3.6.5 on R 4.6.1
Test suite
Has tests
Yes
Test frameworks
testthat
Test cases
1,065
Lines of tests
21,834
Test lines per line of code
0.66
Exports documented
99.4%
Arguments documented
99.7%
Return value documented
100%
Help pages with examples
73.7%
Examples run in checks
16.8%
Guides (11)
Other documentation
README
Yes, 1,343 words
Release notes file
Yes
Help pages
243
Lines of documentation
9,078

ces0491 / tidylearn on github.com

Stars
5no change on 30 days ago
Forks
1
Open issues
0
Last commit
9 Oct 2026
Activity
Commits
188
Open pull requests
0
Tagged releases
0
Latest tagged release
–
In development
Default branch at 0.6.0.9000, ahead of CRAN 0.6.0 (checked 2026-10-25)
Issues closed in
26 days (median)
Pull requests closed in
0 days (median)
Pull requests merged
100%
Created
9 Nov 2025
Licence file reads as
–
Development practices (10)
KindFound
Continuous integrationGitHub Actions, R CMD check workflow
The R CMD check workflow runs on Linux, macOS and Windows, and on R-devel
Governance and communityContributing guide
Docs sourcepkgdown
GitHub Pages site last deployed 2026-10-09
The repository has a site deploy workflow
pkgdown site last built 2026-10-09
CRAN release processcran-comments.md, CRAN-SUBMISSION
Lint, format, editorlintr, RStudio project

Method, repository practices

Across ces0491

Claude Codeat least 134 crediting itClaude CodeFirst seen 19 Jan 2026at least 134 crediting it
Claude Opus 5.5Claude Opus 5.55 Oct 2026 to 8 Oct 2026At least 42 commits
Claude Opus 51MClaude Opus 51M context window3 Aug 2026 to 21 Sep 2026At least 47 commits
Claude Opus 4.71MClaude Opus 4.71M context window22 May 2026At least 3 commits
Claude Opus 4.61MClaude Opus 4.61M context window18 Mar 2026 to 9 Apr 2026At least 8 commits

Tools

ToolFirst seenFoundCommits crediting it
Claude Code19 Jan 2026Named in .Rbuildignore.claudeNamed in .gitignore.claudePull request it wrote: opened by a project member134 at least
  • Named in .Rbuildignore
  • Named in .gitignore
  • Pull request

Models

ModelContext windowCommitsFirst commitLast commitCredit lines of
Claude Opus 5.542 at least5 Oct 20268 Oct 2026Claude Code
Claude Opus 51M47 at least3 Aug 202621 Sep 2026Claude Code
Claude Opus 4.71M3 at least22 May 202622 May 2026Claude Code
Claude Opus 4.61M8 at least18 Mar 20269 Apr 2026Claude Code

Across ces0491

R releases
  • On CRAN
  • Release
VersionReleasedR
0.6.0 current8 Oct 20264.6.1
0.5.02 Sep 20264.6.1
0.4.03 Aug 20264.6.1
0.3.119 May 20264.6.0
0.3.09 Apr 20264.5.3
0.2.016 Mar 20264.5.3
0.1.113 Mar 20264.5.3
0.1.06 Feb 20264.5.2
Release notes (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:
  • 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 notes are cut short here.