The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

Cross-validation

library(mintyr)

Repeated, optionally stratified k-fold cross-validation, implemented with base R and data.table. split_cv() works on a list of tables, nest_cv() on a nested table such as the output of w2l_nest(). Folds are returned as row indices and, optionally, as training / validation subsets (data.table or data.frame).

Cross-validation for a list of tables: split_cv()

# Prepare example data: Convert first 3 columns of iris dataset to long format and split
dt_split <- w2l_split(data = iris, cols = 1:3)
# dt_split is now a list containing 3 data tables for Sepal.Length, Sepal.Width, and Petal.Length

# Example 1: Single cross-validation (no repeats)
split_cv(
  data = dt_split,      # Input list of split data
  v = 3,                # Set 3-fold cross-validation
  repeats = 1,          # Perform cross-validation once (no repeats)
  seed = 123            # Reproducible folds
)
#> $Sepal.Length
#>        id                  train_idx              validate_idx
#>    <char>                     <list>                    <list>
#> 1:  Fold1  1, 2, 5, 7, 9,10,...[100]  3, 4, 6, 8,15,19,...[50]
#> 2:  Fold2       3,4,5,6,7,8,...[100]  1, 2, 9,10,11,14,...[50]
#> 3:  Fold3       1,2,3,4,6,8,...[100]  5, 7,12,13,16,17,...[50]
#>                  train           validate
#>                 <list>             <list>
#> 1: <data.table[100x3]> <data.table[50x3]>
#> 2: <data.table[100x3]> <data.table[50x3]>
#> 3: <data.table[100x3]> <data.table[50x3]>
#> 
#> $Sepal.Width
#>        id                  train_idx              validate_idx
#>    <char>                     <list>                    <list>
#> 1:  Fold1  2, 4, 5, 6, 7,13,...[100]  1, 3, 8, 9,10,11,...[50]
#> 2:  Fold2       1,2,3,4,6,8,...[100]  5, 7,13,14,17,21,...[50]
#> 3:  Fold3       1,3,5,7,8,9,...[100]  2, 4, 6,15,18,22,...[50]
#>                  train           validate
#>                 <list>             <list>
#> 1: <data.table[100x3]> <data.table[50x3]>
#> 2: <data.table[100x3]> <data.table[50x3]>
#> 3: <data.table[100x3]> <data.table[50x3]>
#> 
#> $Petal.Length
#>        id                  train_idx              validate_idx
#>    <char>                     <list>                    <list>
#> 1:  Fold1  1, 2, 8, 9,10,11,...[100]  3, 4, 5, 6, 7,12,...[50]
#> 2:  Fold2       2,3,4,5,6,7,...[100]  1,10,11,17,18,19,...[50]
#> 3:  Fold3       1,3,4,5,6,7,...[100]  2, 8, 9,14,15,20,...[50]
#>                  train           validate
#>                 <list>             <list>
#> 1: <data.table[100x3]> <data.table[50x3]>
#> 2: <data.table[100x3]> <data.table[50x3]>
#> 3: <data.table[100x3]> <data.table[50x3]>
# Returns a list where each element contains:
# - id: fold labels (Fold1, Fold2, Fold3)
# - train_idx / validate_idx: row indices of each fold
# - train / validate: training and validation subsets

# Example 2: Repeated cross-validation
split_cv(
  data = dt_split,      # Input list of split data
  v = 3,                # Set 3-fold cross-validation
  repeats = 2,          # Perform cross-validation twice
  seed = 123
)
#> $Sepal.Length
#>         id    id2                  train_idx              validate_idx
#>     <char> <char>                     <list>                    <list>
#> 1: Repeat1  Fold1  1, 2, 5, 7, 9,10,...[100]  3, 4, 6, 8,15,19,...[50]
#> 2: Repeat1  Fold2       3,4,5,6,7,8,...[100]  1, 2, 9,10,11,14,...[50]
#> 3: Repeat1  Fold3       1,2,3,4,6,8,...[100]  5, 7,12,13,16,17,...[50]
#> 4: Repeat2  Fold1  2, 4, 5, 6, 7,13,...[100]  1, 3, 8, 9,10,11,...[50]
#> 5: Repeat2  Fold2       1,2,3,4,6,8,...[100]  5, 7,13,14,17,21,...[50]
#> 6: Repeat2  Fold3       1,3,5,7,8,9,...[100]  2, 4, 6,15,18,22,...[50]
#>                  train           validate
#>                 <list>             <list>
#> 1: <data.table[100x3]> <data.table[50x3]>
#> 2: <data.table[100x3]> <data.table[50x3]>
#> 3: <data.table[100x3]> <data.table[50x3]>
#> 4: <data.table[100x3]> <data.table[50x3]>
#> 5: <data.table[100x3]> <data.table[50x3]>
#> 6: <data.table[100x3]> <data.table[50x3]>
#> 
#> $Sepal.Width
#>         id    id2                  train_idx              validate_idx
#>     <char> <char>                     <list>                    <list>
#> 1: Repeat1  Fold1  1, 2, 8, 9,10,11,...[100]  3, 4, 5, 6, 7,12,...[50]
#> 2: Repeat1  Fold2       2,3,4,5,6,7,...[100]  1,10,11,17,18,19,...[50]
#> 3: Repeat1  Fold3       1,3,4,5,6,7,...[100]  2, 8, 9,14,15,20,...[50]
#> 4: Repeat2  Fold1  1, 4, 5, 7, 9,10,...[100]  2, 3, 6, 8,14,20,...[50]
#> 5: Repeat2  Fold2       2,3,6,7,8,9,...[100]  1, 4, 5,12,17,21,...[50]
#> 6: Repeat2  Fold3       1,2,3,4,5,6,...[100]  7, 9,10,11,13,15,...[50]
#>                  train           validate
#>                 <list>             <list>
#> 1: <data.table[100x3]> <data.table[50x3]>
#> 2: <data.table[100x3]> <data.table[50x3]>
#> 3: <data.table[100x3]> <data.table[50x3]>
#> 4: <data.table[100x3]> <data.table[50x3]>
#> 5: <data.table[100x3]> <data.table[50x3]>
#> 6: <data.table[100x3]> <data.table[50x3]>
#> 
#> $Petal.Length
#>         id    id2                  train_idx              validate_idx
#>     <char> <char>                     <list>                    <list>
#> 1: Repeat1  Fold1       1,2,4,5,6,8,...[100]  3, 7, 9,15,22,23,...[50]
#> 2: Repeat1  Fold2       1,2,3,4,5,7,...[100]  6, 8,12,14,16,17,...[50]
#> 3: Repeat1  Fold3  3, 6, 7, 8, 9,12,...[100]  1, 2, 4, 5,10,11,...[50]
#> 4: Repeat2  Fold1  1, 2, 5, 8,10,12,...[100]  3, 4, 6, 7, 9,11,...[50]
#> 5: Repeat2  Fold2       3,4,5,6,7,8,...[100]  1, 2,12,14,20,21,...[50]
#> 6: Repeat2  Fold3       1,2,3,4,6,7,...[100]  5, 8,10,15,16,25,...[50]
#>                  train           validate
#>                 <list>             <list>
#> 1: <data.table[100x3]> <data.table[50x3]>
#> 2: <data.table[100x3]> <data.table[50x3]>
#> 3: <data.table[100x3]> <data.table[50x3]>
#> 4: <data.table[100x3]> <data.table[50x3]>
#> 5: <data.table[100x3]> <data.table[50x3]>
#> 6: <data.table[100x3]> <data.table[50x3]>
# Returns a list where each element contains:
# - id: repeat labels (Repeat1, Repeat2)
# - id2: fold labels (Fold1, Fold2, Fold3)
# - train_idx / validate_idx, train / validate

# Example 3: Stratified CV, indices only (memory friendly)
res <- split_cv(dt_split, v = 5, strata = "Species", seed = 1,
                materialize = FALSE)
# Rebuild the training set of fold 1 of the first dataset when needed
head(dt_split[[1]][res[[1]]$train_idx[[1]], ])
#>    Petal.Width Species value
#>          <num>  <fctr> <num>
#> 1:         0.2  setosa   5.1
#> 2:         0.2  setosa   4.9
#> 3:         0.2  setosa   4.7
#> 4:         0.2  setosa   4.6
#> 5:         0.2  setosa   5.0
#> 6:         0.4  setosa   5.4

Cross-validation inside a nested table: nest_cv()

# Example: Cross-validation for nested data.table demonstrations

# Setup test data
dt_nest <- w2l_nest(
  data = iris,                   # Input dataset
  cols = 1:2                     # Nest first 2 columns
)

# Example 1: Basic 2-fold cross-validation (reproducible)
nest_cv(
  data = dt_nest,                # Input nested data.table
  v = 2,                         # Number of folds (2-fold CV)
  seed = 123                     # Reproducible folds
)
#>            name     id                 train_idx              validate_idx
#>          <char> <char>                    <list>                    <list>
#> 1: Sepal.Length  Fold1       1,2,3,5,6,7,...[75]  4, 8, 9,11,12,15,...[75]
#> 2: Sepal.Length  Fold2  4, 8, 9,11,12,15,...[75]       1,2,3,5,6,7,...[75]
#> 3:  Sepal.Width  Fold1       1,2,3,4,6,9,...[75]  5, 7, 8,11,12,13,...[75]
#> 4:  Sepal.Width  Fold2  5, 7, 8,11,12,13,...[75]       1,2,3,4,6,9,...[75]
#>                 train           validate
#>                <list>             <list>
#> 1: <data.table[75x4]> <data.table[75x4]>
#> 2: <data.table[75x4]> <data.table[75x4]>
#> 3: <data.table[75x4]> <data.table[75x4]>
#> 4: <data.table[75x4]> <data.table[75x4]>

# Example 2: Repeated 2-fold CV, keeping only the split objects
nest_cv(
  data = dt_nest,                # Input nested data.table
  v = 2,                         # Number of folds (2-fold CV)
  repeats = 2,                   # Number of repetitions
  seed = 123,
  materialize = FALSE            # No train/validate copies (saves memory)
)
#>            name      id    id2                 train_idx
#>          <char>  <char> <char>                    <list>
#> 1: Sepal.Length Repeat1  Fold1       1,2,3,5,6,7,...[75]
#> 2: Sepal.Length Repeat1  Fold2  4, 8, 9,11,12,15,...[75]
#> 3: Sepal.Length Repeat2  Fold1       1,2,3,4,6,9,...[75]
#> 4: Sepal.Length Repeat2  Fold2  5, 7, 8,11,12,13,...[75]
#> 5:  Sepal.Width Repeat1  Fold1  2, 3, 7, 8, 9,11,...[75]
#> 6:  Sepal.Width Repeat1  Fold2  1, 4, 5, 6,10,14,...[75]
#> 7:  Sepal.Width Repeat2  Fold1  3, 9,10,14,15,16,...[75]
#> 8:  Sepal.Width Repeat2  Fold2       1,2,4,5,6,7,...[75]
#>                 validate_idx
#>                       <list>
#> 1:  4, 8, 9,11,12,15,...[75]
#> 2:       1,2,3,5,6,7,...[75]
#> 3:  5, 7, 8,11,12,13,...[75]
#> 4:       1,2,3,4,6,9,...[75]
#> 5:  1, 4, 5, 6,10,14,...[75]
#> 6:  2, 3, 7, 8, 9,11,...[75]
#> 7:       1,2,4,5,6,7,...[75]
#> 8:  3, 9,10,14,15,16,...[75]

# Example 3: data.frame subsets, ready for ASReml-R / lm() / glm()
cv_df <- nest_cv(dt_nest, v = 2, seed = 123, out_type = "df")
class(cv_df$train[[1]])        # "data.frame"
#> [1] "data.frame"

# Example 4: masking-style CV (keep all rows, hide validation phenotypes)
cv_idx <- nest_cv(dt_nest, v = 2, seed = 123, materialize = FALSE)
cv_idx[dt_nest, on = "name", full := i.data]   # attach the full nested table
masked <- as.data.frame(cv_idx$full[[1]])      # a copy: dt_nest stays intact
masked$value[cv_idx$validate_idx[[1]]] <- NA
sum(is.na(masked$value))       # validation records to be predicted
#> [1] 75

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.