diff --git a/NAMESPACE b/NAMESPACE index c1c0b8f..0d0472b 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,5 +1,6 @@ # Generated by roxygen2: do not edit by hand +export("%notin%") export(combine_results) export(combiner_array) export(combiner_c) @@ -7,6 +8,8 @@ export(combiner_factor) export(combiner_rbind) export(cross_validate) export(fold_from_foldvec) +export(fold_from_foldvec_subgroup) +export(fold_from_foldvec_subgroup_stratoutcome) export(fold_index) export(folds2foldvec) export(folds_bootstrap) @@ -17,6 +20,7 @@ export(folds_rolling_origin) export(folds_rolling_origin_pooled) export(folds_rolling_window) export(folds_rolling_window_pooled) +export(folds_subgroup) export(folds_vfold) export(folds_vfold_rolling_origin_pooled) export(folds_vfold_rolling_window_pooled) diff --git a/R/fold_funs.R b/R/fold_funs.R index 67db76c..3cd81e1 100644 --- a/R/fold_funs.R +++ b/R/fold_funs.R @@ -29,6 +29,8 @@ #' subject in the sample. #' @param id An optional vector of unique identifiers corresponding to the time #' vector. These can be used to subset the time vector. +#' @param subgroup Binary indicator vector of membership in the subgroup of interest for subgroup-specific cross-validation (eg data$S). +#' @param strat_outcome Optional binary outcome vector (eg data$Y) for subgroup-specific cross-validation if equal proportion of outcome in training and validation folds desired. #' #' @importFrom assertthat assert_that #' @@ -369,6 +371,50 @@ folds_vfold_rolling_window_pooled <- function(n, t, id = NULL, time = NULL, return(folds) } +######################################################### +#Add option to make subgroup-specific cross-validation folds + +#' @rdname fold_funs +#' @export +folds_subgroup <- function(n, V = 10L, subgroup, strat_outcome = NULL) { + + if(is.null(strat_outcome)==TRUE){ + + subgroup_index <- which(subgroup == 1) + + folds <- rep(seq_len(V), length = length(subgroup_index)) + + # shuffle folds + folds <- sample(folds) + foldsdf <- data.frame(subgroup_index, folds) + + # generate fold vectors + folds <- lapply(seq_len(V), fold_from_foldvec_subgroup, foldsdf, n) + return(folds) + + } + else { + subgroup_index1 <- which(subgroup == 1 & strat_outcome == 1) + subgroup_index2 <- which(subgroup == 1 & strat_outcome == 0) + + #Two sets of folds, one for outcome == 1 and one for outcome == 0 + folds1 <- rep(seq_len(V), length = length(subgroup_index1)) + folds2 <- rep(seq_len(V), length = length(subgroup_index2)) + + # shuffle folds + folds1 <- sample(folds1) + foldsdf1 <- data.frame(subgroup_index1, folds1) + + folds2 <- sample(folds2) + foldsdf2 <- data.frame(subgroup_index2, folds2) + + # generate fold vectors + folds <- lapply(seq_len(V), fold_from_foldvec_subgroup_stratoutcome, foldsdf1, foldsdf2, n) + return(folds) + } +} + + ############################################################################### #' Check ID and Time Compatibility @@ -411,3 +457,4 @@ check_id_and_time <- function(id, time) { ) } } + diff --git a/R/utils.R b/R/utils.R index f69a6b8..fc46d39 100644 --- a/R/utils.R +++ b/R/utils.R @@ -64,3 +64,22 @@ folds2foldvec <- function(folds) { fold_id <- nums[order(fold_index)] return(fold_id) } + +################################################################################ + +#' @export +`%notin%` <- Negate(`%in%`) + +#' @export +fold_from_foldvec_subgroup <- function(v, foldsdf, n) { + validation_set <- foldsdf[,1][which(foldsdf[,2] == v)] + training_set <- which(seq_len(n) %notin% validation_set) + make_fold(v, training_set, validation_set) +} + +#' @export +fold_from_foldvec_subgroup_stratoutcome <- function(v, foldsdf1, foldsdf2, n) { + validation_set <- c(foldsdf1[,1][which(foldsdf1[,2] == v)], foldsdf2[,1][which(foldsdf2[,2] == v)]) + training_set <- which(seq_len(n) %notin% validation_set) + make_fold(v, training_set, validation_set) +} diff --git a/man/fold_funs.Rd b/man/fold_funs.Rd index 11284c5..aab5a85 100644 --- a/man/fold_funs.Rd +++ b/man/fold_funs.Rd @@ -13,6 +13,7 @@ \alias{folds_rolling_window_pooled} \alias{folds_vfold_rolling_origin_pooled} \alias{folds_vfold_rolling_window_pooled} +\alias{folds_subgroup} \title{Cross-Validation Schemes} \usage{ folds_vfold(n, V = 10L) @@ -74,6 +75,8 @@ folds_vfold_rolling_window_pooled( gap = 0L, batch = 1L ) + +folds_subgroup(n, V = 10L, subgroup, strat_outcome = NULL) } \arguments{ \item{n}{An integer indicating the number of observations.} @@ -103,7 +106,9 @@ training sample.} time-series sample.} \item{id}{An optional vector of unique identifiers corresponding to the time -vector. These can be used to subset the time vector.} +vector. These can be used to subset the time vector. +@param subgroup Binary indicator vector of membership in the subgroup of interest for subgroup-specific cross-validation (eg data$S). +@param strat_outcome Optional binary outcome vector (eg data$Y) for subgroup-specific cross-validation if equal proportion of outcome in training and validation folds desired.} \item{time}{An optional vector of integers of time points observed for each subject in the sample.}