From ca8c2be65c4bde771ababc3307d0bcbe6cb3c697 Mon Sep 17 00:00:00 2001 From: Emil Hvitfeldt Date: Thu, 9 Apr 2026 14:54:46 -0700 Subject: [PATCH 1/5] add ratio vignette --- NEWS.md | 2 + _pkgdown.yml | 6 ++ vignettes/articles/ratio.Rmd | 150 +++++++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+) create mode 100644 vignettes/articles/ratio.Rmd diff --git a/NEWS.md b/NEWS.md index 5a7e0e6..1ddaa84 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,7 @@ # themis (development version) +* Added a new article explaining how `over_ratio` and `under_ratio` work (#141). + * All upsampling steps gain an `indicator_column` argument. When set, a logical column is added to the baked data marking rows added by the step (`TRUE`) vs rows from the original data (`FALSE`). For `step_rose()`, all rows are `TRUE` since ROSE generates a fully synthetic dataset (#58). * `step_rose()` and `rose()` now have improved documentation for `minority_prop`, clarifying that it controls the proportion of synthetic observations from the minority class, and how it differs from `over_ratio` (#144). diff --git a/_pkgdown.yml b/_pkgdown.yml index 49760fa..05a931d 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -17,6 +17,12 @@ template: development: mode: auto +articles: +- title: Getting started + navbar: ~ + contents: + - articles/ratio + reference: - title: Over-sampling desc: > diff --git a/vignettes/articles/ratio.Rmd b/vignettes/articles/ratio.Rmd new file mode 100644 index 0000000..4b4d7e4 --- /dev/null +++ b/vignettes/articles/ratio.Rmd @@ -0,0 +1,150 @@ +--- +title: "How over_ratio and under_ratio work" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{How over_ratio and under_ratio work} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>", + message = FALSE +) +``` + +```{r setup} +library(themis) +library(recipes) +library(dplyr) +``` + +## Introduction + +Many of the sampling steps in themis accept an `over_ratio` or `under_ratio` argument that controls how much sampling is performed. This article explains what these arguments do and how to set them. + +## Setup + +To illustrate, we'll use a small data set with a known class imbalance. In this data set, class `"a"` has 100 observations, `"b"` has 65, and `"c"` has 20. + +```{r} +set.seed(1) +imbalanced_data <- tibble( + x = rnorm(185), + class = factor(c(rep("a", 100), rep("b", 65), rep("c", 20))) +) + +count(imbalanced_data, class) +``` + +## `over_ratio` + +The `over_ratio` argument is used by [over-sampling steps](../reference/index.html#over-sampling). It controls the ratio of the minority-to-majority frequencies after sampling. + +The target number of observations for each class is calculated as: + +$$\text{target} = \lfloor \text{majority\_n} \times \text{over\_ratio} \rfloor$$ + +where $\text{majority\_n}$ is the number of observations in the most common class. + +- **`over_ratio = 1` (default)**: All classes are upsampled to the frequency of the majority class, resulting in a perfectly balanced data set. + +- **`over_ratio < 1`**: Minority classes are upsampled to a fraction of the majority class frequency, resulting in a partially balanced data set. + +- **`over_ratio > 1`**: All classes, including the majority, are upsampled to the same target, resulting in a balanced data set that is larger than the original. + +- If a class already has at least as many observations as the target, it is left unchanged. + +### Examples + +With the default `over_ratio = 1`, all classes are brought up to 100 observations (the size of the majority class): + +```{r} +recipe(class ~ x, data = imbalanced_data) |> + step_upsample(class, over_ratio = 1) |> + prep() |> + bake(new_data = NULL) |> + count(class) +``` + +With `over_ratio = 0.5`, the target is `floor(100 * 0.5) = 50`. Only class `"c"` is upsampled to 50. Classes `"a"` and `"b"` already exceed the target and are left unchanged: + +```{r} +recipe(class ~ x, data = imbalanced_data) |> + step_upsample(class, over_ratio = 0.5) |> + prep() |> + bake(new_data = NULL) |> + count(class) +``` + +With `over_ratio = 0.3`, the target is `floor(100 * 0.3) = 30`. Class `"c"` is upsampled from 20 to 30. Classes `"a"` and `"b"` both exceed the target and are left unchanged: + +```{r} +recipe(class ~ x, data = imbalanced_data) |> + step_upsample(class, over_ratio = 0.3) |> + prep() |> + bake(new_data = NULL) |> + count(class) +``` + +## `under_ratio` + +The `under_ratio` argument is used by [under-sampling steps](../reference/index.html#under-sampling). It controls the ratio of the majority-to-minority frequencies after sampling. + +The target number of observations for each class is calculated as: + +$$\text{target} = \lfloor \text{minority\_n} \times \text{under\_ratio} \rfloor$$ + +where $\text{minority\_n}$ is the number of observations in the least common class. + +- **`under_ratio = 1` (default)**: All classes are downsampled to the frequency of the minority class, resulting in a perfectly balanced data set. + +- **`under_ratio > 1`**: Majority classes are downsampled to a multiple of the minority class frequency, resulting in a partially balanced data set. + +- **`under_ratio < 1`**: All classes, including the minority, are downsampled to the same target, resulting in a balanced data set that is smaller than the original. + +- If a class already has at most as many observations as the target, it is left unchanged. + +### Examples + +With the default `under_ratio = 1`, all classes are brought down to 20 observations (the size of the minority class): + +```{r} +recipe(class ~ x, data = imbalanced_data) |> + step_downsample(class, under_ratio = 1) |> + prep() |> + bake(new_data = NULL) |> + count(class) +``` + +With `under_ratio = 2`, the target is `floor(20 * 2) = 40`. Classes `"a"` and `"b"` are both downsampled to 40. Class `"c"` already has fewer than 40 observations and is left unchanged: + +```{r} +recipe(class ~ x, data = imbalanced_data) |> + step_downsample(class, under_ratio = 2) |> + prep() |> + bake(new_data = NULL) |> + count(class) +``` + +With `under_ratio = 3`, the target is `floor(20 * 3) = 60`. Classes `"a"` and `"b"` are both downsampled to 60. Class `"c"` already has fewer than 60 observations and is left unchanged: + +```{r} +recipe(class ~ x, data = imbalanced_data) |> + step_downsample(class, under_ratio = 3) |> + prep() |> + bake(new_data = NULL) |> + count(class) +``` + +## Choosing a ratio + +Choosing the right ratio depends on your data and the model you are using. The default value of 1 gives a perfectly balanced data set, which is the most common choice. However, there are cases where a partial balance is preferable: + +- **Preserving more majority class data**: A perfectly balanced data set from under-sampling discards most of the majority class data. Using `under_ratio > 1` retains more data at the cost of a less balanced class distribution. + +- **Limiting over-sampling**: With a very large majority class, upsampling to perfect balance can generate a very large amount of synthetic data. Using `over_ratio < 1` limits the amount of synthetic data generated. + +In practice, `over_ratio` and `under_ratio` are often treated as tunable hyperparameters and selected by cross-validation. See the [`dials`](https://dials.tidymodels.org/) package for the `over_ratio()` and `under_ratio()` parameter objects used in tuning. From c9a213f8ff64a6a6ed753b4ea492b18aa1ce0fea Mon Sep 17 00:00:00 2001 From: Emil Hvitfeldt Date: Thu, 9 Apr 2026 15:02:31 -0700 Subject: [PATCH 2/5] link to vignette --- R/downsample.R | 3 ++- R/upsample.R | 3 ++- man/adasyn.Rd | 3 ++- man/bsmote.Rd | 3 ++- man/nearmiss.Rd | 3 ++- man/rose.Rd | 3 ++- man/smote.Rd | 3 ++- man/smotenc.Rd | 3 ++- man/step_adasyn.Rd | 3 ++- man/step_bsmote.Rd | 3 ++- man/step_downsample.Rd | 3 ++- man/step_nearmiss.Rd | 3 ++- man/step_rose.Rd | 3 ++- man/step_smote.Rd | 3 ++- man/step_smotenc.Rd | 3 ++- man/step_upsample.Rd | 3 ++- 16 files changed, 32 insertions(+), 16 deletions(-) diff --git a/R/downsample.R b/R/downsample.R index f572f29..718c6f0 100644 --- a/R/downsample.R +++ b/R/downsample.R @@ -19,7 +19,8 @@ #' that all other levels are sampled down to have the same #' frequency as the least occurring level. A value of 2 would mean #' that the majority levels will have (at most) (approximately) -#' twice as many rows than the minority level. +#' twice as many rows than the minority level. See +#' `vignette("ratio", package = "themis")` for more details. #' @param ratio Deprecated argument; same as `under_ratio` #' @param target An integer that will be used to subsample. This #' should not be set by the user and will be populated by `prep`. diff --git a/R/upsample.R b/R/upsample.R index fab0d67..3ea3f2e 100644 --- a/R/upsample.R +++ b/R/upsample.R @@ -19,7 +19,8 @@ #' that all other levels are sampled up to have the same #' frequency as the most occurring level. A value of 0.5 would mean #' that the minority levels will have (at most) (approximately) -#' half as many rows as the majority level. +#' half as many rows as the majority level. See +#' `vignette("ratio", package = "themis")` for more details. #' @param ratio Deprecated argument; same as `over_ratio`. #' @param target An integer that will be used to subsample. This #' should not be set by the user and will be populated by `prep`. diff --git a/man/adasyn.Rd b/man/adasyn.Rd index 0530980..262af61 100644 --- a/man/adasyn.Rd +++ b/man/adasyn.Rd @@ -20,7 +20,8 @@ minority-to-majority frequencies. The default value (1) means that all other levels are sampled up to have the same frequency as the most occurring level. A value of 0.5 would mean that the minority levels will have (at most) (approximately) -half as many rows as the majority level.} +half as many rows as the majority level. See +\code{vignette("ratio", package = "themis")} for more details.} } \value{ A data.frame or tibble, depending on type of \code{df}. diff --git a/man/bsmote.Rd b/man/bsmote.Rd index eef2b9a..8508833 100644 --- a/man/bsmote.Rd +++ b/man/bsmote.Rd @@ -20,7 +20,8 @@ minority-to-majority frequencies. The default value (1) means that all other levels are sampled up to have the same frequency as the most occurring level. A value of 0.5 would mean that the minority levels will have (at most) (approximately) -half as many rows as the majority level.} +half as many rows as the majority level. See +\code{vignette("ratio", package = "themis")} for more details.} \item{all_neighbors}{Type of two borderline-SMOTE method. Defaults to FALSE. See details.} diff --git a/man/nearmiss.Rd b/man/nearmiss.Rd index a2e34ab..dda265a 100644 --- a/man/nearmiss.Rd +++ b/man/nearmiss.Rd @@ -20,7 +20,8 @@ majority-to-minority frequencies. The default value (1) means that all other levels are sampled down to have the same frequency as the least occurring level. A value of 2 would mean that the majority levels will have (at most) (approximately) -twice as many rows than the minority level.} +twice as many rows than the minority level. See +\code{vignette("ratio", package = "themis")} for more details.} } \value{ A data.frame or tibble, depending on type of \code{df}. diff --git a/man/rose.Rd b/man/rose.Rd index 6da299a..eb1dded 100644 --- a/man/rose.Rd +++ b/man/rose.Rd @@ -25,7 +25,8 @@ minority-to-majority frequencies. The default value (1) means that all other levels are sampled up to have the same frequency as the most occurring level. A value of 0.5 would mean that the minority levels will have (at most) (approximately) -half as many rows as the majority level.} +half as many rows as the majority level. See +\code{vignette("ratio", package = "themis")} for more details.} \item{minority_prop}{A numeric value between 0 and 1 for the proportion of synthetic observations from the minority class. Defaults to 0.5, which diff --git a/man/smote.Rd b/man/smote.Rd index a0dda42..efda1d9 100644 --- a/man/smote.Rd +++ b/man/smote.Rd @@ -20,7 +20,8 @@ minority-to-majority frequencies. The default value (1) means that all other levels are sampled up to have the same frequency as the most occurring level. A value of 0.5 would mean that the minority levels will have (at most) (approximately) -half as many rows as the majority level.} +half as many rows as the majority level. See +\code{vignette("ratio", package = "themis")} for more details.} } \value{ A data.frame or tibble, depending on type of \code{df}. diff --git a/man/smotenc.Rd b/man/smotenc.Rd index 458eca8..11e191e 100644 --- a/man/smotenc.Rd +++ b/man/smotenc.Rd @@ -20,7 +20,8 @@ minority-to-majority frequencies. The default value (1) means that all other levels are sampled up to have the same frequency as the most occurring level. A value of 0.5 would mean that the minority levels will have (at most) (approximately) -half as many rows as the majority level.} +half as many rows as the majority level. See +\code{vignette("ratio", package = "themis")} for more details.} } \value{ A data.frame or tibble, depending on type of \code{df}. diff --git a/man/step_adasyn.Rd b/man/step_adasyn.Rd index 6914876..e129a1c 100644 --- a/man/step_adasyn.Rd +++ b/man/step_adasyn.Rd @@ -42,7 +42,8 @@ minority-to-majority frequencies. The default value (1) means that all other levels are sampled up to have the same frequency as the most occurring level. A value of 0.5 would mean that the minority levels will have (at most) (approximately) -half as many rows as the majority level.} +half as many rows as the majority level. See +\code{vignette("ratio", package = "themis")} for more details.} \item{neighbors}{An integer. Number of nearest neighbor that are used to generate the new examples of the minority class.} diff --git a/man/step_bsmote.Rd b/man/step_bsmote.Rd index 9847e6c..a8e68a7 100644 --- a/man/step_bsmote.Rd +++ b/man/step_bsmote.Rd @@ -43,7 +43,8 @@ minority-to-majority frequencies. The default value (1) means that all other levels are sampled up to have the same frequency as the most occurring level. A value of 0.5 would mean that the minority levels will have (at most) (approximately) -half as many rows as the majority level.} +half as many rows as the majority level. See +\code{vignette("ratio", package = "themis")} for more details.} \item{neighbors}{An integer. Number of nearest neighbor that are used to generate the new examples of the minority class.} diff --git a/man/step_downsample.Rd b/man/step_downsample.Rd index b79ba84..80b92d8 100644 --- a/man/step_downsample.Rd +++ b/man/step_downsample.Rd @@ -34,7 +34,8 @@ majority-to-minority frequencies. The default value (1) means that all other levels are sampled down to have the same frequency as the least occurring level. A value of 2 would mean that the majority levels will have (at most) (approximately) -twice as many rows than the minority level.} +twice as many rows than the minority level. See +\code{vignette("ratio", package = "themis")} for more details.} \item{ratio}{Deprecated argument; same as \code{under_ratio}} diff --git a/man/step_nearmiss.Rd b/man/step_nearmiss.Rd index 6a1378b..9878e8d 100644 --- a/man/step_nearmiss.Rd +++ b/man/step_nearmiss.Rd @@ -43,7 +43,8 @@ majority-to-minority frequencies. The default value (1) means that all other levels are sampled down to have the same frequency as the least occurring level. A value of 2 would mean that the majority levels will have (at most) (approximately) -twice as many rows than the minority level.} +twice as many rows than the minority level. See +\code{vignette("ratio", package = "themis")} for more details.} \item{neighbors}{An integer. Number of nearest neighbor that are used to generate the new examples of the minority class.} diff --git a/man/step_rose.Rd b/man/step_rose.Rd index aa7a47d..9e4251a 100644 --- a/man/step_rose.Rd +++ b/man/step_rose.Rd @@ -44,7 +44,8 @@ minority-to-majority frequencies. The default value (1) means that all other levels are sampled up to have the same frequency as the most occurring level. A value of 0.5 would mean that the minority levels will have (at most) (approximately) -half as many rows as the majority level.} +half as many rows as the majority level. See +\code{vignette("ratio", package = "themis")} for more details.} \item{minority_prop}{A numeric value between 0 and 1 for the proportion of synthetic observations from the minority class. Defaults to 0.5, which diff --git a/man/step_smote.Rd b/man/step_smote.Rd index 6c2696a..267f31f 100644 --- a/man/step_smote.Rd +++ b/man/step_smote.Rd @@ -42,7 +42,8 @@ minority-to-majority frequencies. The default value (1) means that all other levels are sampled up to have the same frequency as the most occurring level. A value of 0.5 would mean that the minority levels will have (at most) (approximately) -half as many rows as the majority level.} +half as many rows as the majority level. See +\code{vignette("ratio", package = "themis")} for more details.} \item{neighbors}{An integer. Number of nearest neighbor that are used to generate the new examples of the minority class.} diff --git a/man/step_smotenc.Rd b/man/step_smotenc.Rd index 0049eac..7b69479 100644 --- a/man/step_smotenc.Rd +++ b/man/step_smotenc.Rd @@ -42,7 +42,8 @@ minority-to-majority frequencies. The default value (1) means that all other levels are sampled up to have the same frequency as the most occurring level. A value of 0.5 would mean that the minority levels will have (at most) (approximately) -half as many rows as the majority level.} +half as many rows as the majority level. See +\code{vignette("ratio", package = "themis")} for more details.} \item{neighbors}{An integer. Number of nearest neighbor that are used to generate the new examples of the minority class.} diff --git a/man/step_upsample.Rd b/man/step_upsample.Rd index 3f0f154..068d026 100644 --- a/man/step_upsample.Rd +++ b/man/step_upsample.Rd @@ -35,7 +35,8 @@ minority-to-majority frequencies. The default value (1) means that all other levels are sampled up to have the same frequency as the most occurring level. A value of 0.5 would mean that the minority levels will have (at most) (approximately) -half as many rows as the majority level.} +half as many rows as the majority level. See +\code{vignette("ratio", package = "themis")} for more details.} \item{ratio}{Deprecated argument; same as \code{over_ratio}.} From 6606ec78d3fffa53c8af88ec75399f100aecc6fa Mon Sep 17 00:00:00 2001 From: Emil Hvitfeldt Date: Thu, 9 Apr 2026 15:06:38 -0700 Subject: [PATCH 3/5] add stuff --- .Rbuildignore | 1 + DESCRIPTION | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.Rbuildignore b/.Rbuildignore index c37c109..ebbf44c 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -21,3 +21,4 @@ ^[\.]?air\.toml$ ^\.vscode$ ^\.claude$ +^vignettes/articles$ diff --git a/DESCRIPTION b/DESCRIPTION index a4b03e8..301921e 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -38,7 +38,7 @@ Imports: tibble, vctrs, withr -Suggests: +Suggests: covr, dials (>= 1.2.0), ggplot2, From f69165197992b956ed229f321859a4b39e0bbcf8 Mon Sep 17 00:00:00 2001 From: Emil Hvitfeldt Date: Thu, 9 Apr 2026 15:20:11 -0700 Subject: [PATCH 4/5] add descriptions to adasyn and tomek --- R/adasyn.R | 9 +++++++++ R/tomek.R | 14 ++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/R/adasyn.R b/R/adasyn.R index 0bd85ea..afc609f 100644 --- a/R/adasyn.R +++ b/R/adasyn.R @@ -22,6 +22,15 @@ #' the variable used to sample. #' #' @details +#' ADASYN is an extension of SMOTE that adaptively generates synthetic minority +#' class examples based on the local distribution of each minority instance. +#' Instead of generating the same number of synthetic examples for every +#' minority instance, ADASYN generates more synthetic examples for instances +#' that are harder to learn — specifically those surrounded by more majority +#' class neighbors. This focuses synthetic data generation on the difficult +#' boundary regions of the minority class, resulting in a more informative +#' augmentation than standard SMOTE. +#' #' All columns in the data are sampled and returned by [recipes::juice()] #' and [recipes::bake()]. #' diff --git a/R/tomek.R b/R/tomek.R index e2edc6d..11c36e6 100644 --- a/R/tomek.R +++ b/R/tomek.R @@ -22,12 +22,18 @@ #' the variable used to sample. #' #' @details +#' A Tomek link is a pair of points from different classes that are each +#' other's nearest neighbors. Such pairs sit on or very near the decision +#' boundary and are considered noise or borderline cases. `step_tomek()` +#' identifies all Tomek links and removes the majority class instance from +#' each pair, cleaning the class boundary without discarding +#' non-boundary majority examples. Because only boundary points are removed, +#' this step typically discards far fewer observations than other +#' under-sampling methods. +#' #' All variables selected by `distance_with` must be numeric with no missing #' data. #' -#' A tomek link is defined as a pair of points from different classes and are -#' each others nearest neighbors. -#' #' All columns in the data are sampled and returned by [recipes::juice()] #' and [recipes::bake()]. #' @@ -50,7 +56,7 @@ #' @references Tomek. Two modifications of cnn. IEEE Trans. Syst. Man Cybern., #' 6:769-772, 1976. #' -#'@seealso [tomek()] for direct implementation +#' @seealso [tomek()] for direct implementation #' @family Steps for under-sampling #' #' @export From 642103d001693a1903ee3d086200075e859937fc Mon Sep 17 00:00:00 2001 From: Emil Hvitfeldt Date: Thu, 9 Apr 2026 15:20:18 -0700 Subject: [PATCH 5/5] nitpicks --- R/nearmiss.R | 2 +- R/rose.R | 19 +++++++++---------- R/smote.R | 2 +- R/smotenc.R | 10 ++++++++-- man/rose.Rd | 2 +- man/step_adasyn.Rd | 9 +++++++++ man/step_nearmiss.Rd | 2 +- man/step_rose.Rd | 17 ++++++++--------- man/step_smote.Rd | 2 +- man/step_smotenc.Rd | 10 ++++++++-- man/step_tomek.Rd | 12 +++++++++--- 11 files changed, 56 insertions(+), 31 deletions(-) diff --git a/R/nearmiss.R b/R/nearmiss.R index 147b208..5604dfd 100644 --- a/R/nearmiss.R +++ b/R/nearmiss.R @@ -2,7 +2,7 @@ #' #' `step_nearmiss()` creates a *specification* of a recipe step that removes #' majority class instances by undersampling points in the majority class based -#' on their distance to other points in the same class. +#' on their distance to points in the minority class. #' #' @inheritParams recipes::step_center #' @inheritParams step_downsample diff --git a/R/rose.R b/R/rose.R index 219d71a..e3ffff7 100644 --- a/R/rose.R +++ b/R/rose.R @@ -1,8 +1,8 @@ #' Apply ROSE Algorithm #' #' `step_rose()` creates a *specification* of a recipe step that generates -#' sample of synthetic data by enlarging the features space of minority and -#' majority class example. Using [ROSE::ROSE()]. +#' samples of synthetic data by enlarging the feature space of minority and +#' majority class examples. Using [ROSE::ROSE()]. #' #' @inheritParams recipes::step_center #' @inheritParams step_upsample @@ -39,12 +39,11 @@ #' The factor variable used to balance around must only have 2 levels. #' #' The ROSE algorithm works by selecting an observation belonging to class k -#' and generates new examples in its neighborhood is determined by some matrix -#' H_k. Smaller values of these arguments have the effect of shrinking the -#' entries of the corresponding smoothing matrix H_k, Shrinking would be a -#' cautious choice if there is a concern that excessively large neighborhoods -#' could lead to blur the boundaries between the regions of the feature space -#' associated with each class. +#' and generating new examples in its neighborhood, which is determined by a +#' smoothing matrix H_k. Smaller values of `minority_smoothness` and +#' `majority_smoothness` shrink the entries of H_k, producing tighter +#' neighborhoods. This is a cautious choice when there is a concern that +#' excessively large neighborhoods could blur the boundaries between classes. #' #' All columns in the data are sampled and returned by [recipes::juice()] #' and [recipes::bake()]. @@ -72,7 +71,7 @@ #' @template case-weights-not-supported #' #' @references Lunardon, N., Menardi, G., and Torelli, N. (2014). ROSE: a -#' Package for Binary Imbalanced Learning. R Jorunal, 6:82–92. +#' Package for Binary Imbalanced Learning. R Journal, 6:82–92. #' @references Menardi, G. and Torelli, N. (2014). Training and assessing #' classification rules with imbalanced data. Data Mining and Knowledge #' Discovery, 28:92–122. @@ -358,7 +357,7 @@ required_pkgs.step_rose <- function(x, ...) { #' between the regions of the feature space associated with each class. #' #' @references Lunardon, N., Menardi, G., and Torelli, N. (2014). ROSE: a -#' Package for Binary Imbalanced Learning. R Jorunal, 6:82–92. +#' Package for Binary Imbalanced Learning. R Journal, 6:82–92. #' @references Menardi, G. and Torelli, N. (2014). Training and assessing #' classification rules with imbalanced data. Data Mining and Knowledge #' Discovery, 28:92–122. diff --git a/R/smote.R b/R/smote.R index 85fa633..a08a05e 100644 --- a/R/smote.R +++ b/R/smote.R @@ -1,7 +1,7 @@ #' Apply SMOTE Algorithm #' #' `step_smote()` creates a *specification* of a recipe step that generate new -#' examples of the minority class using nearest neighbors of these cases. +#' examples of the minority class using nearest neighbors of these cases. #' #' @inheritParams recipes::step_center #' @inheritParams step_upsample diff --git a/R/smotenc.R b/R/smotenc.R index 17c896d..2d855de 100644 --- a/R/smotenc.R +++ b/R/smotenc.R @@ -1,7 +1,7 @@ #' Apply SMOTENC algorithm #' #' `step_smotenc()` creates a *specification* of a recipe step that generate new -#' examples of the minority class using nearest neighbors of these cases. +#' examples of the minority class using nearest neighbors of these cases. #' Gower's distance is used to handle mixed data types. For categorical #' variables, the most common category along neighbors is chosen. #' @@ -24,12 +24,18 @@ #' the variable used to sample. #' #' @details +#' SMOTENC extends SMOTE to handle data sets with a mix of numeric and +#' categorical predictors. For each minority class example, new synthetic +#' examples are generated by interpolating between the example and its nearest +#' neighbors using Gower's distance. Numeric features are interpolated +#' continuously; categorical features take the most common value among the +#' neighbors. +#' #' The parameter `neighbors` controls the way the new examples are created. #' For each currently existing minority class example X new examples will be #' created (this is controlled by the parameter `over_ratio` as mentioned #' above). These examples will be generated by using the information from the #' `neighbors` nearest neighbor of each example of the minority class. -#' The parameter `neighbors` controls how many of these neighbor are used. #' #' All columns in the data are sampled and returned by [recipes::juice()] #' and [recipes::bake()]. diff --git a/man/rose.Rd b/man/rose.Rd index eb1dded..ec68858 100644 --- a/man/rose.Rd +++ b/man/rose.Rd @@ -71,7 +71,7 @@ rose(circle_example[, c("x", "y", "class")], var = "class", over_ratio = 0.8) } \references{ Lunardon, N., Menardi, G., and Torelli, N. (2014). ROSE: a -Package for Binary Imbalanced Learning. R Jorunal, 6:82–92. +Package for Binary Imbalanced Learning. R Journal, 6:82–92. Menardi, G. and Torelli, N. (2014). Training and assessing classification rules with imbalanced data. Data Mining and Knowledge diff --git a/man/step_adasyn.Rd b/man/step_adasyn.Rd index e129a1c..1dcb651 100644 --- a/man/step_adasyn.Rd +++ b/man/step_adasyn.Rd @@ -75,6 +75,15 @@ the variable used to sample. synthetic positive instances using ADASYN algorithm. } \details{ +ADASYN is an extension of SMOTE that adaptively generates synthetic minority +class examples based on the local distribution of each minority instance. +Instead of generating the same number of synthetic examples for every +minority instance, ADASYN generates more synthetic examples for instances +that are harder to learn — specifically those surrounded by more majority +class neighbors. This focuses synthetic data generation on the difficult +boundary regions of the minority class, resulting in a more informative +augmentation than standard SMOTE. + All columns in the data are sampled and returned by \code{\link[recipes:juice]{recipes::juice()}} and \code{\link[recipes:bake]{recipes::bake()}}. diff --git a/man/step_nearmiss.Rd b/man/step_nearmiss.Rd index 9878e8d..4fc3173 100644 --- a/man/step_nearmiss.Rd +++ b/man/step_nearmiss.Rd @@ -74,7 +74,7 @@ the variable used to sample. \description{ \code{step_nearmiss()} creates a \emph{specification} of a recipe step that removes majority class instances by undersampling points in the majority class based -on their distance to other points in the same class. +on their distance to points in the minority class. } \details{ This step implements the NearMiss-1 algorithm. It retains the points from diff --git a/man/step_rose.Rd b/man/step_rose.Rd index 9e4251a..0ffae9e 100644 --- a/man/step_rose.Rd +++ b/man/step_rose.Rd @@ -85,19 +85,18 @@ the variable used to sample. } \description{ \code{step_rose()} creates a \emph{specification} of a recipe step that generates -sample of synthetic data by enlarging the features space of minority and -majority class example. Using \code{\link[ROSE:ROSE]{ROSE::ROSE()}}. +samples of synthetic data by enlarging the feature space of minority and +majority class examples. Using \code{\link[ROSE:ROSE]{ROSE::ROSE()}}. } \details{ The factor variable used to balance around must only have 2 levels. The ROSE algorithm works by selecting an observation belonging to class k -and generates new examples in its neighborhood is determined by some matrix -H_k. Smaller values of these arguments have the effect of shrinking the -entries of the corresponding smoothing matrix H_k, Shrinking would be a -cautious choice if there is a concern that excessively large neighborhoods -could lead to blur the boundaries between the regions of the feature space -associated with each class. +and generating new examples in its neighborhood, which is determined by a +smoothing matrix H_k. Smaller values of \code{minority_smoothness} and +\code{majority_smoothness} shrink the entries of H_k, producing tighter +neighborhoods. This is a cautious choice when there is a concern that +excessively large neighborhoods could blur the boundaries between classes. All columns in the data are sampled and returned by \code{\link[recipes:juice]{recipes::juice()}} and \code{\link[recipes:bake]{recipes::bake()}}. @@ -178,7 +177,7 @@ recipe(class ~ x + y, data = circle_example) |> } \references{ Lunardon, N., Menardi, G., and Torelli, N. (2014). ROSE: a -Package for Binary Imbalanced Learning. R Jorunal, 6:82–92. +Package for Binary Imbalanced Learning. R Journal, 6:82–92. Menardi, G. and Torelli, N. (2014). Training and assessing classification rules with imbalanced data. Data Mining and Knowledge diff --git a/man/step_smote.Rd b/man/step_smote.Rd index 267f31f..45c39e5 100644 --- a/man/step_smote.Rd +++ b/man/step_smote.Rd @@ -72,7 +72,7 @@ the variable used to sample. } \description{ \code{step_smote()} creates a \emph{specification} of a recipe step that generate new -examples of the minority class using nearest neighbors of these cases. +examples of the minority class using nearest neighbors of these cases. } \details{ The parameter \code{neighbors} controls the way the new examples are created. diff --git a/man/step_smotenc.Rd b/man/step_smotenc.Rd index 7b69479..a004d86 100644 --- a/man/step_smotenc.Rd +++ b/man/step_smotenc.Rd @@ -72,17 +72,23 @@ the variable used to sample. } \description{ \code{step_smotenc()} creates a \emph{specification} of a recipe step that generate new -examples of the minority class using nearest neighbors of these cases. +examples of the minority class using nearest neighbors of these cases. Gower's distance is used to handle mixed data types. For categorical variables, the most common category along neighbors is chosen. } \details{ +SMOTENC extends SMOTE to handle data sets with a mix of numeric and +categorical predictors. For each minority class example, new synthetic +examples are generated by interpolating between the example and its nearest +neighbors using Gower's distance. Numeric features are interpolated +continuously; categorical features take the most common value among the +neighbors. + The parameter \code{neighbors} controls the way the new examples are created. For each currently existing minority class example X new examples will be created (this is controlled by the parameter \code{over_ratio} as mentioned above). These examples will be generated by using the information from the \code{neighbors} nearest neighbor of each example of the minority class. -The parameter \code{neighbors} controls how many of these neighbor are used. All columns in the data are sampled and returned by \code{\link[recipes:juice]{recipes::juice()}} and \code{\link[recipes:bake]{recipes::bake()}}. diff --git a/man/step_tomek.Rd b/man/step_tomek.Rd index 2e87d57..3cefc5a 100644 --- a/man/step_tomek.Rd +++ b/man/step_tomek.Rd @@ -63,12 +63,18 @@ the variable used to sample. majority class instances of tomek links. } \details{ +A Tomek link is a pair of points from different classes that are each +other's nearest neighbors. Such pairs sit on or very near the decision +boundary and are considered noise or borderline cases. \code{step_tomek()} +identifies all Tomek links and removes the majority class instance from +each pair, cleaning the class boundary without discarding +non-boundary majority examples. Because only boundary points are removed, +this step typically discards far fewer observations than other +under-sampling methods. + All variables selected by \code{distance_with} must be numeric with no missing data. -A tomek link is defined as a pair of points from different classes and are -each others nearest neighbors. - All columns in the data are sampled and returned by \code{\link[recipes:juice]{recipes::juice()}} and \code{\link[recipes:bake]{recipes::bake()}}.