This is the first CRAN release since 1.3.0. It includes all changes
listed below for versions 1.3.1 to 1.5.1, notably the 1.3.7 fix:
cross-validation in train_frm() no longer requires the
suggested package toscutil, so model training no longer
fails in a plain CRAN install without Suggests packages.
Changes in this version:
Replaced a structure(.Names = ) call in the GUI
server code with stats::setNames(), fixing the R-devel CRAN
check NOTE about deprecated special names.
The xgboost grid search (tune_grid) now passes the
training objective inside params, as xgboost 3.x requires;
xgboost had warned that the old form will become an error in a future
version.
Added an inst/CITATION file and a reference to the
FastRet paper (Fadil et al., 2026, doi:10.1021/acs.jcim.6c01344) in the package description
and README.
Fixed the privacy-contact link in the GUI, which pointed to a page of the University of Regensburg that no longer exists.
Fixed a typo in the biocViews field of
DESCRIPTION.
README: installation now leads with the CRAN release, mentions the hosted GUI at https://fastret.spang-lab.de and lists Selective Measuring as a feature.
Vignettes: corrected installation instructions, broken anchors, outdated function names and typos; documented the hyperparameter-tuning checkbox (Train) and the compound-matching option (Adjust) of the GUI; extended the contribution guidelines.
CI: updated GitHub Actions to their current major versions.
updateCachedCDs()) and
the example-data generator
(misc/scripts/make-example-data.R) now download
Measurements_v10P.xlsx from the version-independent
example-data release tag instead of the v1.3.0
package release, so all example/source artifacts live in one place and
the build no longer pins an old package-version tag.Example datasets & models refresh:
The bundled RP dataset (and
inst/extdata/RP.xlsx) was regenerated from the published
Measurements_v10P.xlsx and now contains
458 metabolites (was 442), with an added
INCHIKEY column.
inst/extdata/RP_adj.xlsx (returned by
read_rpadj_xlsx()) is now real data: 25
RP metabolites re-measured under a steeper gradient
(dataset RP_Steep in the FastRet paper), replacing the
previous synthetic file. It also gains an INCHIKEY
column.
inst/extdata/RP_lasso_model.rds was retrained on the
new 458-metabolite RP.
The shipped chemical-descriptor cache
(inst/cachedata/CDs.sqlite) was rebuilt from
Measurements_v10P.xlsx; the outdated
inst/extdata/Measurements_v8.xlsx is no longer
shipped.
Documentation and the Shiny GUI now offer direct download links to the example files (hosted as GitHub release assets), so web-app users can follow the tutorials without installing the package.
Model adjustment (compound matching):
The default compound matching used by adjust_frm()
now matches on "INCHIKEY" alone (when complete InChIKeys
are available in both new_data and frm$df),
instead of the previous c("SMILES", "INCHIKEY"). The
InChIKey is a structure-invariant identifier and alone uniquely
identifies a molecule, whereas SMILES is matched as an exact raw string
and often differs in spelling between datasets — so including it only
made matching more fragile without adding identifying power. This also
aligns the package default with the InChIKey-based matching used
throughout the FastRet paper’s adjustment benchmarks. When InChIKeys are
unavailable the fallback is unchanged
(c("SMILES", "NAME")), and an explicit
match_keys argument still overrides the default.
The GUI’s Adjust tab gained a “Compound matching”
dropdown that exposes this choice: Automatic (recommended;
InChIKey when available, else Name+SMILES), InChIKey,
Name, or Name + SMILES. The selection is passed to
adjust_frm() as match_keys.
Hyperparameter tuning:
train_frm()’s tune_grid argument now
also accepts the grid-size keywords "tiny",
"small" and "large" (in addition to an
explicit data.frame),
e.g. train_frm(method = "brt", tune_grid = "small").
The built-in "small" grid was changed to a fast,
effective 8-combination Retip-style grid (max_depth 2-5,
eta 0.01/0.02, with gamma = 1,
colsample_bytree/subsample 0.5,
min_child_weight 10; the number of boosting rounds is
chosen by early stopping). In the FastRet paper’s benchmark this
internal grid search matches the accuracy of Retip’s own grid search.
(The predefined grids were not previously exposed, so this is not a
breaking change.)
The GUI’s Train tab gained a “Tune hyperparameters (grid search)” checkbox. When enabled for XGBoost it runs the small grid search (a few extra seconds); it has no effect for Lasso.
Bug fixes (GUI):
Training from an uploaded workbook that contained an
INCHIKEY column crashed the whole GUI session (the UI
greyed out and had to be restarted). train_frm() keeps
INCHIKEY in frm$df as metadata, but the
Train tab’s result handler excluded only
NAME/RT/SMILES before calling
round(cds, 2), so the character INCHIKEY
column made round() error. As this ran inside a reactive
status observer without a tryCatch, the error tore down the
session. The handler now excludes INCHIKEY too, and the
extended-task status observers are wrapped so any future handler error
shows a notification instead of killing the session. (This was not fixed
by the 1.4.1 robust-upload change, which deliberately keeps
INCHIKEY.)
Dropped upload columns are no longer silent. When an uploaded
workbook contains columns FastRet does not use (anything other than
NAME/RT/SMILES/INCHIKEY/RT_ADJ
and chemical descriptors), the GUI now shows a notification naming the
ignored columns, so it is clear they are not carried into the
results/download.
train_frm() gains a tune_grid argument:
supplying a data.frame of xgboost hyperparameters runs a
cross-validated grid search over those rows for gbtree/BRT
models (instead of the fixed default parameters), making FastRet’s
existing grid-search machinery user-accessible. NULL
(default) is unchanged.GUI upload fixes:
Large uploads are now accepted. Shiny’s default request-size
limit of 5 MB rejected normal inputs such as an 8 MB adjusted model. The
GUI now raises the limit to 500 MB, so any model or data file a user is
likely to upload is accepted (shiny.maxRequestSize, set in
fastret_app()).
Excel uploads are read robustly. Instead of always reading the
first worksheet, FastRet now searches every worksheet for the first one
that contains the required columns
(RT/SMILES/NAME for training,
selective measuring and adjustment;
NAME/SMILES for prediction) and silently drops
any extra columns. Previously, uploading a workbook with additional
columns besides the required ones - or with the data on a sheet other
than the first - could cause model training to stall. New internal
helpers read_input_xlsx() and
drop_unsupported_columns() implement this and are covered
by tests.
Chemical-descriptor cache:
The chemical-descriptor cache is now a pure on-disk SQLite
database (CDs.sqlite) instead of an in-memory R option
backed by CDs.rds. On first use the shipped database is
copied into the per-user cache directory
(tools::R_user_dir("FastRet", "cache")) and all reads and
writes go there. Because the cache lives on disk, descriptors computed
in one process are immediately visible to every other process and
worker, so parallel training and the GUI’s background workers now share
a single cache. Concurrent access is made safe via SQLite WAL mode and
INSERT OR IGNORE.
getCDs(), preprocess_data(),
train_frm(), predict.frm() and
adjust_frm() gained a cache argument. With
cache = TRUE (default) descriptors are read from and
written to the on-disk cache; with cache = FALSE the cache
is bypassed and every descriptor is recomputed via rCDK (useful for
benchmarking the uncached runtime).
Removed the internal FastRet.cachedCDs option and
the N_SMI_CACHED constant. CDK / rcdklibs
>= 2.9 is required (already enforced at GUI startup by
check_cdk_version()), as it provides all descriptors in
CDFeatures.
GUI:
Reworked the model-adjustment controls in the Adjust
tab. The old “Components of linear model” checkbox group (which let
users toggle the RT, RT^2, RT^3,
log(RT), exp(RT), and sqrt(RT)
predictors of a linear adjustment model) has been replaced by an
“Adjustment method” radio button that lets users pick the model family
used for the correction: Lasso (recommended), Linear
model, or XGBoost. Lasso and XGBoost adjust using the base
retention time together with the molecular descriptors and can therefore
capture compound-specific shifts, whereas the linear model fits a simple
straight-line correction from the base retention time only. The GUI now
passes adj_type to adjust_frm() accordingly;
the deprecated RT-transformation predictors are no longer
exposed.
Promoted the four workflows to dedicated navbar tabs (Train, Select, Adjust, Predict) instead of selecting them from a single drop-down. Each tab shows a short label with the full mode description on hover, and carries only its own controls and results. The Privacy Policy, Contact, and About pages remain as separate tabs.
Simplified the Train sidebar to the essentials: data
upload, method (XGBoost/Lasso), seed, and the console log. The “Show
advanced settings” toggle and the “Preprocessing Options” checkbox group
were removed – GUI training now always uses the package defaults of
train_frm().
GUI-trained models are now reproducible by default. The training
seed previously defaulted to the current system time and was never
actually passed to train_frm(); it now defaults to a fixed
value (42) and is applied, so training the same data twice yields
identical models. The seed remains user-editable.
The console log is now always visible in every mode (the per-mode “Show console logs” checkboxes were removed), including a new console-log box for Selective Measuring.
The Selective Measuring tab now exposes the selection variant (named as in the paper: SMmax, SM1, SM0, SMinf, with an info button explaining each) and the random seed, so users can pick the variant and reproduce a selection from the GUI.
Reviewed the GUI help texts for clarity, tone and formatting, and reworded the prediction console output so it no longer implies that descriptors are recomputed when they are served from the cache.
Each tab’s sidebar now starts with a heading (the mode name) and a help button that explains, in a few sentences, what the mode is for and when to use it.
Testing:
shinytest2 end-to-end GUI tests
(tests/testthat/test-gui-e2e.R) that drive the real app via
headless Chrome and exercise every mode and model type (Train: Lasso +
XGBoost; Selective Measuring; Predict; Adjust: Lasso + Linear model +
XGBoost). They are skipped on CRAN and when Chrome/Java are
unavailable.Documentation:
misc/scripts/make-gui-screenshots.R.Bugfix:
toscutil::stub() development call
from the cross-validation path of train_frm(). The call had
no effect on results (it only assigned predict.frm argument
defaults into a function environment that was never read again), but it
made toscutil — a Suggests package — a hard
runtime dependency. As a result, model training failed with “there is no
package called ‘toscutil’” whenever Suggests packages were
not installed (e.g. a plain CRAN install).Dependencies:
future (>= 1.40.0).
start_gui() uses
with(future::plan(...), local = TRUE), which relies on the
with.FutureStrategyList method introduced in future
1.40.0.Documentation:
GUI-Usage vignette, and fixed minor wording in
the GUI help texts.Bugfix:
predict.frm() now imputes missing/non-finite values not
only for base model predictors, but also for adjustment model
predictors. This prevents NA predictions if the adjustment
model depends on predictors that are missing/non-finite in the new
data.Internal Improvements:
predict.frm() into
a shared internal helper.Internal Improvements:
start_gui() and start_gui_in_devmode() now
rely on with(future::plan(...), local = TRUE) so that
temporary future plans are restored automatically without manual
bookkeeping.API Improvements:
selective_measuring() accepts "max" and
"inf" as additional values for its rt_coef
parameter:
"max" is an alias for the existing
"max_ridge_coef""inf" sets all chemical descriptor features to zero
before clustering so that RT alone drives the distance metric (i.e., it
is “infinitely” more important than the chemical descriptors).Bugfix:
adjust_frm() automatically switched to “lm” adjustment
if predictors contained only one predictor, regardless of
whether add_cds was TRUE or FALSE. This has now been fixed,
so that “lasso”, “ridge” and “gbtree” adjustment is now possible if
either add_cds is TRUE, add_cds is
NULL or predictors contains more than one
predictor.API Improvements:
match_rts and match_keys
to adjust_frm():
match_rts=TRUE (default), RTs are obtained by
matching rows in new_data to rows in frm$df
based on match_keys.match_rts=FALSE, RTs are obtained by applying the
base model to new_data.match_keys can be any combination of “INCHIKEY”,
“SMILES” and “NAME”. If left at default NULL, SMILES+INCHIKEY is used if
both columns are present in the adjusted and the original training data.
Otherwise, SMILES+NAME is used.API Improvements:
getCDs():
plot_frm():
preprocess_data():
add_cds to control whether chemical
descriptors should be added to the input data using
getCDs().rm_ucs to control whether unsupported
columns (i.e. columns that are neither mandatory nor optional) should be
removed from the input data.rt_terms to control whether
transformations of the RT column (square, cube, log, exp, sqrt) should
be added to the input data.CDFeatures
are allowed as optional columns.train_frm():
do_cv to control whether
cross-validation should be performed for performance estimation. Default
is TRUE.method now accepts two values for training
models with xgbtree base: “gbtreeDefault” (train xgboost with default
params) and “gbtreeRP” (train xgboost with parameters optimized for the
RP dataset). The old value “gbtree” still works and is now an alias for
“gbtreeDefault”.frm
objects are fully specified now).clip_predictions(). Of
course, the clipping is always based on the RT range of training folds,
not the whole original training data.predict.frm():
degree_polynomial>1 and/or
interaction_terms=TRUE, unless the transformations were
manually applied to the new data beforehand.clip to allow clipping of predictions to
be within the RT range of the training data. Works for both adjusted and
unadjusted models.clip=FALSE.
See clip_predictions() for details.impute=FALSE in
predict.frm().selective_measuring():
rt_coef, allowing user to control the
influence of RT on the clustering. A value of 0 means that RT is
ignored, a value of “max_ridge_coefficient” means that RT has the same
weight as the most important chemical descriptor and a value of 1 means
no scaling at all (except standardization to z-scores, which is applied
before to the whole dataset before the ridge regression is
trained).adjust_frm():
seed to allow reproducible results.do_cv to control whether
cross-validation should be performed for performance estimation. Default
is TRUE.adj_type to control which model should
be trained for adjustment: supported options are “lm”, “lasso”, “ridge”,
or “gbtree”. Previously, only “lm” was supported. To stay backwards
compatible, the default is “lm”.add_cds to control whether chemical
descriptors should be added to the input data using
getCDs(). Only recommended for adj_type other than
“lm”.clip_predictions(). Of
course, the clipping is always based on the RT range of training folds,
not the whole original training data.print.frm():
clip_predictions():
train_frm(),
predict.frm() and adjust_frm().get_predictors():
base and adjust to control
whether predictors for the base model, the adjustment model or both
should be returned.Bugfixes:
preprocess_data() are
now generated correctly as product of the involved features instead of a
division. This follows common practice in regression modeling and avoids
division by zero issues. Passing older models, trained with
division-based interaction terms, to downstream functions like
predict.frm() or adjust_frm() will now lead to
an error. (This is not a breaking change, as predict.frm()
and friends have in fact never been able to handle such models).plot_frm() with type “scatter.cv.adj” or
“scatter.train.adj” now correctly shows retention times from the new
data (used for model adjustment) as x-axis values instead of the
original training retention times.catf() now only emits escape codes (i.e. colored
output), it the output is directed to a terminal. If the output is
redirected to a file or a pipe, no escape codes are emitted anymore.
Since catf() is used throughout the package for logging,
this fixes the output for the whole package.Internal Improvements:
adjust_frm()fit_gbtree()fit_glmnet()get_param_grid()get_predictors()getCDs()plot_frm()predict_frm()preprocess_data()selective_measuring()train_frm()validate_inputdata()caret dependency by adding custom
implementations for:
createFolds()nearZeroVar()adjust_frm() into a
private function merge_dfs().fit_glmnet(), fit_lasso() and
fit_ridge() with a single function
fit_glmnet(), that takes the method (“lasso” or “ridge”) as
parameter. Instead of a dataframe df that has to contain
only predictors plus the RT column (as response), the function now takes
a matrix of predictors X and a vector of responses
y. This makes the function more flexible and easier to
test.fit_gbtree_grid() with a much simpler function
find_params_best(). Instead of allowing the specification
of every grid parameter, the new function instead accepts a keyword
searchspace for specifying predefined grids to choose
from.fit_gbtree by exposing lots of hardcoded
internal xgboost parameters as function parameters with sensible
defaults. In particular, the user can now set xpar to
“default”, “rpopt” or a predefined grid-size to train the model with
different hyperparameter settings. Furthermore, the function is now
written in a way that works with both, version 1.7.9.1 and the new
3.1.2.1 version published on 2025/12/03 (yes, version 2.x was skipped
completely).get_param_grid() for returning
predefined hyperparameter grids for xgboost model training based on
keywords like “tiny”, “small” or “large”.benchmark_find_params() to benchmark
runtime of find_params_best() for different numbers of
cores and/or threads. As it turns out, choosing a higher number of cores
is usually more efficient (at the cost of worse progress output).named(), as_str(),
is_valid_smiles() and as_canonical()selective_measuring() by aligning glmnet
coefficients to columns by name (more stable) and by including RT,
scaled by max(abs(coefs)), in PAM clustering.libwebp-dev as dependency to Dockerfile.Measurements_v8.xlsx to
inst/extdata/. The new list contains corrections to the old
RP dataset plus 1660 new measurements measured on a total
of 18 different chromatographic environments.seed parameter to
selective_measuring() function for reproducible clustering
resultstrain_frm() functiondigest and shinybusy
dependenciesinst/mockdata/getCDsFor1Molecule(),
get_cache_dir(), ram_cache (these were
exported, but declared as internal)parLapply2Improved read_retip_hilic_data(): the dataset is now
only downloaded from GitHub if the package is not installed. If it is
installed, the dataset is loaded directly.
Internal Changes:
TODOS.mdutil.R to
data.Rmisc/datasetsload_all() and document()
to util.Rxlsx and readxl packages with
openxlsxAdded a cache cleanup handler that gets registered via
reg.finalizer() upon package loading to ensure that the
cache directory is removed if it doesn’t contain any files that should
persist between R sessions.
Added an article about installation details incl. a troubleshooting section
Improved function docs
Improved examples by removing donttest
blocks
Improved examples & tests by using smaller example datasets to reduce runtime
Moved patch.R from the R folder to
misc/scripts, which is excluded from the package build
using .Rbuildignore. The file is conditionally sourced by
the private function start_gui_in_devmode() if available,
allowing its use during development without including it in the
package.
Added \value tags to the mentioned .Rd
files describing the functions’ return values.
Added Bonini et al. (2020) doi:10.1021/acs.analchem.9b05765 as reference to
the description part of the DESCRIPTION file, listing it as Related
work. This reference is used in the documentation for
read_retip_hilic_data() and ram_cache. No
additional references are used in the package documentation.
Added Fadi Fadil as a contributor. Fadi measured the example datasets shipped with FastRet.
Added ORCID IDs for contributors as described in CRAN’s checklist for submissions.
read_rp_xlsx() and
read_rpadj_xlsx() into donttest to prevent
note “Examples with CPU time > 2.5 times elapsed time: …”. By now I’m
pretty sure the culprit is the xlsx package, which uses a
java process for reading the file. Maybe we should switch to openxlsx or
readxl in the future.preprocess_data() to prevent note
“Examples with CPU time > 2.5 times elapsed time: preprocess_data
(CPU=2.772, elapsed=0.788)”.getCDs()Added examples to start_gui(),
fastret_app(), getCDsFor1Molecule(),
analyzeCDNames(), check_lm_suitabilitym(),
plot_lm_suitability(), extendedTask(),
selective_measuring(), train_frm(),
adjust_frm(), get_predictors()
Improved lots of existing examples
Added additional logging messages at various places
Submitted to CRAN, but rejected because the following examples caused at least one of the following notes on the CRAN testing machines: (1) “CPU time > 5s”, (2) “CPU time > 2.5 times elapsed time”. In this context, “CPU time” is calculated as the sum of the measured “user” and “system” times.
| function | user | system | elapsed | ratio |
|---|---|---|---|---|
| check_lm_suitability | 5.667 | 0.248 | 2.211 | 2.675 |
| predict.frm | 2.477 | 0.112 | 0.763 | 3.393 |
| getCDs | 2.745 | 0.089 | 0.961 | 2.949 |
Completely refactored source code, e.g.:
Added a test suite covering all important functions
The UI now uses Extended Tasks for background processing, allowing GUI usage by multiple users at the same time
The clustering now uses Partitioning Around Medoids (PAM) instead of k-means, which is faster and much better suited for our use case
The training of the Lasso and/or XGBoost models is no longer done
using caret but using glmnet and
xgboost directly. The new implementation is much faster and
allows for full control over the number of workers started.
Function getCDs now caches the results on Disk,
making the retrieval of chemical descriptors much faster
The GUI now has a console element, showing the progress of the background tasks like clustering and model training
The GUI has a cleaner interface, because lots of the options are now hidden in the “Advanced” tab by default and are only displayed upon user request
Initial version.
Copy of commit cd243aa82a56df405df8060b84535633cf06b692
of Christian
Amesöders Repository. (Christian wrote this initial version of
FastRet as part of his master thesis at the Institute of functional
Genomics, University of Regensburg).