**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. ----------------------------------------------------------------------------...
Scanned 5/27/2026
Install via CLI
openskills install tidymodels/skills# 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](references/extension-guide.md)
**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](references/source-guide.md)
**Package detection:** DESCRIPTION file has `Package: dials`
--------------------------------------------------------------------------------
## Getting Started
**Before you begin**, verify your development context:
```r
# 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: dials
```
**INSTRUCTIONS FOR CLAUDE:**
**Detect development context by checking:**
1. **DESCRIPTION file check** (most reliable):
- If `Package: dials` → Source development
- If `Package: [anything else]` → Extension development
2. **Prompt signals** (when DESCRIPTION not available):
**Extension indicators:**
- "for my package"
- "I'm building/creating [package name]"
- "new package called [name]"
- "my [package] package"
- No mention of cloning or PR
**Source indicators:**
- "contributing to dials"
- "PR to tidymodels/dials"
- "I'm in the dials repo"
- "forked tidymodels/dials"
- "working on a feature branch"
- "clone of tidymodels/dials"
3. **When uncertain:**
- Ask explicitly: "Are you creating a new package or contributing to dials
itself?"
- Default to extension development (most common use case)
**Apply appropriate patterns:**
- Extension: Use dials:: prefix, link to extension-guide.md, create DESCRIPTION
if needed
- Source: No prefix, link to source-guide.md, assume dials repo structure exists
--------------------------------------------------------------------------------
## Overview
**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
1. **Parameter Types**: Quantitative (numeric) vs Qualitative (categorical)
2. **Range Specification**: Fixed ranges, unknown bounds, transformations
3. **Finalization**: Resolving data-dependent parameters with training data
4. **Grid Integration**: How parameters work with grid generation functions
--------------------------------------------------------------------------------
## Repository Access (Optional but Recommended)
**INSTRUCTIONS FOR CLAUDE:** Check if `repos/dials/` exists in the current
working directory. Use this to guide development:
**If `repos/dials/` exists:**
- ✅ Use it as a reference throughout development
- Read source files (e.g., `repos/dials/R/param_mtry.R`) to study implementation
patterns
- Read test files (e.g., `repos/dials/tests/testthat/test-param_mtry.R`) for
testing patterns
- Reference these files when answering complex questions or solving problems
- Look at actual code structure, validation patterns, and edge case handling
**If `repos/dials/` does NOT exist:**
- Suggest cloning the repository using the scripts in [Repository Access
Guide](references/package-repository-access.md)
- This is **optional but strongly recommended** for high-quality development
- If the user declines, reference files using GitHub URLs:
- Format: `https://github.com/tidymodels/dials/blob/main/R/[file-name].R`
- Example: https://github.com/tidymodels/dials/blob/main/R/param_mtry.R
- This allows users to click through to see implementations
**When to use repository references:**
- Complex implementation questions (e.g., "How does dials handle finalization?")
- Debugging issues (compare user's code to working implementation)
- Understanding patterns (study similar parameters)
- Test design (see how dials tests edge cases)
- Architecture decisions (understand internal structure)
See [Repository Access Guide](references/package-repository-access.md) for setup
instructions.
--------------------------------------------------------------------------------
## 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](references/quantitative-parameters.md)
- **Quantitative, transformed**: Log scale or other transformation →
[Quantitative Parameters](references/quantitative-parameters.md) +
[Transformations](references/transformations.md)
- **Quantitative, data-dependent**: Upper bound depends on dataset →
[Quantitative Parameters](references/quantitative-parameters.md) +
[Data-Dependent Parameters](references/data-dependent-parameters.md)
- **Qualitative**: Discrete categorical options → [Qualitative
Parameters](references/qualitative-parameters.md)
--------------------------------------------------------------------------------
## Complete Examples
### Example 1: Simple Quantitative Parameter
A threshold parameter with fixed range (extension pattern):
```r
# 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
# 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
# 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
# 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
# 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")
```
--------------------------------------------------------------------------------
## Quick Navigation
### Core Guides
- [Extension Development Guide](references/extension-guide.md) - Creating new
packages with custom parameters
- [Source Development Guide](references/source-guide.md) - Contributing to dials
package
### Parameter Types
- [Parameter System Overview](references/parameter-system.md) - Architecture and
parameter classes
- [Quantitative Parameters](references/quantitative-parameters.md) - Creating
numeric parameters
- [Qualitative Parameters](references/qualitative-parameters.md) - Creating
categorical parameters
- [Transformations](references/transformations.md) - Using log scale and custom
transformations
- [Data-Dependent Parameters](references/data-dependent-parameters.md) - Using
unknown() and finalization
- [Grid Integration](references/grid-integration.md) - How parameters work with
grids
### Source Development
- [Testing Patterns (Source)](references/testing-patterns-source.md) -
dials-specific testing
- [Best Practices (Source)](references/best-practices-source.md) - dials
conventions and patterns
- [Troubleshooting (Source)](references/troubleshooting-source.md) - Common
issues in dials
--------------------------------------------------------------------------------
## 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](references/package-extension-prerequisites.md)
- **Dependencies**: Add `dials` to DESCRIPTION Imports
- **Roxygen**: Configure documentation system
- **Testing**: Set up testthat framework
### For Source Development
To contribute parameters to dials:
1. Clone the repository:
```bash
git clone https://github.com/tidymodels/dials
cd dials
```
2. Install dependencies:
```r
pak::pak()
```
3. Load the package:
```r
devtools::load_all()
```
See [Source Development Guide](references/source-guide.md) for complete setup.
--------------------------------------------------------------------------------
## Development Workflow
### Fast Iteration Cycle
For rapid parameter development:
1. **Create** parameter function in `R/` directory
2. **Load** with `devtools::load_all()`
3. **Test** interactively in console
4. **Document** with roxygen comments
5. **Verify** with tests
See [Development Workflow](references/package-development-workflow.md) 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()` and `value_seq()` work correctly
- **Edge cases**: Invalid inputs produce errors
See testing guides:
- Extension: [Testing
Requirements](references/package-extension-requirements.md#testing-requirements)
- Source: [Testing Patterns (Source)](references/testing-patterns-source.md)
--------------------------------------------------------------------------------
## 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:
```r
#' @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()
#' @export
```
See [Roxygen Documentation](references/package-roxygen-documentation.md) for
complete patterns.
### Creating Companion Values Vectors
For qualitative parameters, create a `values_*` vector:
```r
#' @rdname param_name
#' @export
values_param_name <- c("option1", "option2", "option3")
```
This convention is strongly recommended for consistency.
--------------------------------------------------------------------------------
## Next Steps
### For Extension Developers
1. Read [Extension Development Guide](references/extension-guide.md)
2. Choose your parameter type:
[Quantitative](references/quantitative-parameters.md) or
[Qualitative](references/qualitative-parameters.md)
3. Implement your parameter following the examples above
4. Add tests following [Testing
Requirements](references/package-extension-requirements.md#testing-requirements)
5. Document with roxygen following [Documentation
Guide](references/package-roxygen-documentation.md)
### For Source Contributors
1. Read [Source Development Guide](references/source-guide.md)
2. Study existing parameters in `repos/dials/R/param_*.R`
3. Understand [Parameter System Overview](references/parameter-system.md)
4. Follow [Best Practices (Source)](references/best-practices-source.md)
5. Add tests to `tests/testthat/test-params.R`
6. Submit PR following [Source Guide](references/source-guide.md) checklist
### Related Skills
- [add-yardstick-metric](../add-yardstick-metric/SKILL.md) - Custom metrics may
need custom tuning parameters
- [add-recipe-step](../add-recipe-step/SKILL.md) - Recipe steps often have
tunable parameters
- [add-parsnip-model](../add-parsnip-model/SKILL.md) - Model specifications have
tunable main arguments
- [add-parsnip-engine](../add-parsnip-engine/SKILL.md) - Model engines have
tunable parameters
--------------------------------------------------------------------------------
## File Creation Guidelines
**Extension development:**
- R/param\_[name].R (with complete roxygen docs and examples)
- tests/testthat/test-param\_[name].R (comprehensive tests)
- README.md (only if package has no README)
- Expected total: 2-3 files (aim for these targets; acceptable to exceed by 2-3
files if implementation requires it)
**Source development:**
- R/param\_[name].R (with complete roxygen docs and examples)
- tests/testthat/test-param\_[name].R (or additions to existing test file)
- Expected total: 2 files (aim for these targets; acceptable to exceed by 2-3
files if implementation requires it)
**Files to avoid creating:**
Documentation files (content belongs in roxygen comments):
- IMPLEMENTATION_SUMMARY.md, IMPLEMENTATION_NOTES.md, QUICKSTART.md,
QUICK_REFERENCE.md
- INDEX.md, FILE_GUIDE.md, SUMMARY.md, OVERVIEW.md, INTEGRATION_GUIDE.md
- example_usage.R, USAGE_EXAMPLE.R
PR-related files (content belongs in conversation):
- PR_CHECKLIST.md, PR_DESCRIPTION.md, PR_SUMMARY.md
- NEWS_entry.md, pkgdown_update.txt
- WORKFLOW_COMMANDS.sh, setup.sh
For PRs to dials:
- README.md (dials already has one)
- test-params-addition.R (tell user in conversation what to add)
**Where content belongs:**
- Examples → roxygen @examples in R file
- Implementation notes → roxygen @details in R file
- PR description → conversation with user
- NEWS entry → conversation (maintainer adds it)
- Test additions → conversation (tell user what to add)
Creating extra documentation files clutters the codebase. All documentation
should be in roxygen comments (for code) or in conversation (for PR
descriptions).
See extension-guide.md Step 5 and source-guide.md "File Creation Guidelines for
PRs" for detailed enforcement rules.
--------------------------------------------------------------------------------
**Last Updated:** 2026-03-31
No comments yet. Be the first to comment!