
Add Dials Parameter
Create custom tuning parameters for hyperparameter tuning in Tidymodels
Guide for creating new dials parameters for hyperparameter tuning. Use when a developer needs to define custom tuning parameters for models, recipes, or workflows, including quantitative parameters (continuous/integer), qualitative parameters (categorical), parameters with transformations, and data-dependent parameters requiring finalization.
Two Development Contexts
This skill supports two distinct development contexts with different capabilities and constraints:
1. Extension Development (Primary Context)
Use when: Creating a new R package that defines custom tuning parameters
- ✅ Build new packages extending Tidymodels with custom parameters
- ✅ Use all exported dials functions with
dials::prefix - ❌ Cannot use internal functions (
:::) - 📘 Start here: Extension Development Guide
Package detection: DESCRIPTION file does NOT have Package: dials
2. Source Development (Advanced Context)
Use when: Contributing parameter definitions directly to tidymodels/dials repository
- ✅ Contribute parameters to dials package itself
- ✅ Access internal helper functions without
dials::prefix - ✅ Use validation helpers (
check_type(),check_range()) - ✅ Create custom finalize functions with
range_get()/range_set() - 📗 Start here: Source Development Guide
Package detection: DESCRIPTION file has Package: dials
Getting Started
Before you begin, verify your development context:
# Extension development (most common)
usethis::create_package("myextension")
# DESCRIPTION will have: Package: myextension
# Source development (contributing to dials)
# Clone repository: git clone https://github.com/tidymodels/dials
# DESCRIPTION will have: Package: dialsOverview
dials is the tuning parameter infrastructure package for Tidymodels. It provides:
- Parameter object definitions (quantitative and qualitative)
- Parameter range specifications and transformations
- Grid generation methods (regular, random, space-filling)
- Integration with tune, parsnip, recipes, and workflows packages
The name reflects the idea that tuning predictive models can be like turning a set of dials on a complex machine.
Key Concepts
- Parameter Types: Quantitative (numeric) vs Qualitative (categorical)
- Range Specification: Fixed ranges, unknown bounds, transformations
- Finalization: Resolving data-dependent parameters with training data
- Grid Integration: How parameters work with grid generation functions
Parameter Type Decision Tree
┌─────────────────────────────────────────────────────────────┐
│ What type of tuning parameter do you need? │
└─────────────────────────────────────────────────────────────┘
│
┌───────────────────┴───────────────────┐
│ │
▼ ▼
Numeric values Categorical choices
(continuous or integer) (discrete options)
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ QUANTITATIVE │ │ QUALITATIVE │
│ PARAMETER │ │ PARAMETER │
└─────────────────┘ └─────────────────┘
│ │
│ │
├───────────┬────────────┐ │
▼ ▼ ▼ ▼
Simple Transformed Data- Examples:
range (log scale) dependent - activation()
- weight_func()
│ │ │ - prune_method()
▼ ▼ ▼
Examples: Examples: Examples:
- threshold - penalty - mtry
- mixture - learn_rate - num_comp
- neighbors - cost - sample_size
Decision guide:
- Quantitative, simple range: Fixed numeric bounds, no transformation → Quantitative Parameters
- Quantitative, transformed: Log scale or other transformation → Quantitative Parameters + Transformations
- Quantitative, data-dependent: Upper bound depends on dataset → Quantitative Parameters + Data-Dependent Parameters
- Qualitative: Discrete categorical options → Qualitative Parameters
Complete Examples
Example 1: Simple Quantitative Parameter
A threshold parameter with fixed range (extension pattern):
# R/param_my_threshold.R
#' Threshold value
#'
#' A threshold parameter for filtering or classification decisions.
#'
#' @param range A two-element vector with the lower and upper bounds.
#' @param trans A transformation object (default NULL for no transformation).
#'
#' @details
#' This parameter is used for models or recipes that require a threshold value.
#'
#' @examples
#' my_threshold()
#' my_threshold(range = c(0, 0.5))
#'
#' @export
my_threshold <- function(range = c(0, 1), trans = NULL) {
dials::new_quant_param(
type = "double",
range = range,
inclusive = c(TRUE, TRUE),
trans = trans,
label = c(my_threshold = "Threshold Value"),
finalize = NULL
)
}Example 2: Transformed Quantitative Parameter
A penalty parameter on log scale (extension pattern):
# R/param_my_penalty.R
#' Penalty amount
#'
#' A penalty parameter for regularization on log scale.
#'
#' @param range A two-element vector with the lower and upper bounds
#' (in log10 units).
#' @param trans A transformation object (default log10 transformation).
#'
#' @details
#' This parameter uses a log10 transformation, so `range = c(-5, 0)`
#' represents actual penalty values from 10^-5 to 1.
#'
#' @examples
#' my_penalty() # Range: 10^-10 to 1
#' my_penalty(range = c(-5, 0)) # Range: 10^-5 to 1
#'
#' @export
my_penalty <- function(range = c(-10, 0), trans = scales::transform_log10()) {
dials::new_quant_param(
type = "double",
range = range,
inclusive = c(TRUE, TRUE),
trans = trans,
label = c(my_penalty = "Penalty Amount"),
finalize = NULL
)
}Example 3: Data-Dependent Parameter with Built-in Finalize
A parameter with unknown upper bound (extension pattern):
# R/param_num_features.R
#' Number of features
#'
#' The number of features to select, depends on data.
#'
#' @param range A two-element vector with the lower and upper bounds.
#' @param trans A transformation object (default NULL).
#'
#' @details
#' The upper bound is set to `unknown()` and must be finalized using
#' `finalize()` with training data.
#'
#' @examples
#' num_features()
#'
#' # Finalize with data
#' param <- num_features()
#' finalized <- dials::finalize(param, mtcars[, -1])
#' finalized$range$upper # Will be number of columns
#'
#' @export
num_features <- function(range = c(1L, dials::unknown()), trans = NULL) {
dials::new_quant_param(
type = "integer",
range = range,
inclusive = c(TRUE, TRUE),
trans = trans,
label = c(num_features = "# Features to Select"),
finalize = dials::get_p # Built-in finalize function
)
}Example 4: Custom Finalize Function
A parameter with custom finalization logic (extension pattern):
# R/param_num_initial_terms.R
#' Number of initial MARS terms
#'
#' The number of initial terms for MARS model, depends on data.
#'
#' @param range A two-element vector with the lower and upper bounds.
#' @param trans A transformation object (default NULL).
#'
#' @details
#' The upper bound is set to `unknown()` and is finalized using a custom
#' function based on the earth package formula: min(200, max(20, 2 * ncol(x))) + 1
#'
#' @examples
#' num_initial_terms()
#'
#' # Finalize with data
#' param <- num_initial_terms()
#' finalized <- dials::finalize(param, mtcars[, -1])
#' finalized$range$upper
#'
#' @export
num_initial_terms <- function(range = c(1L, dials::unknown()), trans = NULL) {
dials::new_quant_param(
type = "integer",
range = range,
inclusive = c(TRUE, TRUE),
trans = trans,
label = c(num_initial_terms = "# Initial MARS Terms"),
finalize = get_initial_mars_terms
)
}
# Custom finalize function
get_initial_mars_terms <- function(object, x) {
# Calculate upper bound based on number of predictors
upper_bound <- min(200, max(20, 2 * ncol(x))) + 1
upper_bound <- as.integer(upper_bound)
# Get current range and update upper bound
bounds <- dials::range_get(object)
bounds$upper <- upper_bound
dials::range_set(object, bounds)
}Example 5: Qualitative Parameter
A categorical parameter with options (extension pattern):
# R/param_aggregation.R
#' Aggregation method
#'
#' The method to use for aggregating embeddings.
#'
#' @param values A character vector of possible methods.
#'
#' @details
#' This parameter defines how embeddings are aggregated.
#' By default, no aggregation is performed.
#'
#' @examples
#' values_aggregation
#' aggregation()
#' aggregation(values = c("none", "mean"))
#'
#' # Sample values
#' set.seed(123)
#' aggregation() %>% dials::value_sample(3)
#'
#' @export
aggregation <- function(values = values_aggregation) {
dials::new_qual_param(
type = "character",
values = values,
default = "none",
label = c(aggregation = "Aggregation Method")
)
}
#' @rdname aggregation
#' @export
values_aggregation <- c("none", "min", "max", "mean", "sum")Prerequisites
For Extension Development
Before creating custom parameters in a new package, ensure your package is properly set up:
- R Package Structure: See Extension Prerequisites
- Dependencies: Add
dialsto DESCRIPTION Imports - Roxygen: Configure documentation system
- Testing: Set up testthat framework
For Source Development
To contribute parameters to dials:
Clone the repository:
git clone https://github.com/tidymodels/dials cd dialsInstall dependencies:
pak::pak()Load the package:
devtools::load_all()
See Source Development Guide for complete setup.
Development Workflow
Fast Iteration Cycle
For rapid parameter development:
- Create parameter function in
R/directory - Load with
devtools::load_all() - Test interactively in console
- Document with roxygen comments
- Verify with tests
See Development Workflow for details.
Testing Your Parameters
Essential tests for all parameters:
- Range validation: Parameter accepts valid ranges
- Type checking: Correct type enforcement
- Grid integration: Works with
grid_regular(),grid_random() - Value utilities:
value_sample()andvalue_seq()work correctly - Edge cases: Invalid inputs produce errors
See testing guides: - Extension: Testing Requirements - Source: Testing Patterns (Source)
Package-Specific Patterns
File Naming (Source Development)
dials follows strict naming conventions:
- Parameter files:
R/param_[name].R - Test files:
tests/testthat/test-params.R(shared),test-constructors.R - One parameter per file (usually)
Documentation Patterns
Use roxygen tags consistently:
#' @inheritParams new_quant_param
#' @param range A two-element vector with the lower and upper bounds.
#' @details
#' This parameter is used for...
#' @examples
#' my_param()
#' @exportSee Roxygen Documentation for complete patterns.
Creating Companion Values Vectors
For qualitative parameters, create a values_* vector:
#' @rdname param_name
#' @export
values_param_name <- c("option1", "option2", "option3")This convention is strongly recommended for consistency.
Next Steps
For Extension Developers
- Read Extension Development Guide
- Choose your parameter type: Quantitative or Qualitative
- Implement your parameter following the examples above
- Add tests following Testing Requirements
- Document with roxygen following Documentation Guide
For Source Contributors
- Read Source Development Guide
- Study existing parameters in
repos/dials/R/param_*.R - Understand Parameter System Overview
- Follow Best Practices (Source)
- Add tests to
tests/testthat/test-params.R - Submit PR following Source Guide checklist