Working in R, using the familiar bag of coloured balls analogy. I want to sample without replacement from a bag of balls. In this bag, there are many differently coloured balls. Each colour, c, is represented a random number of times in the bag, k (e.g. k_blue = 3, k_red = 5, k_green = 2, ...). For each c, I want to take a sample without replacement of size k and every ball is taken from the bag at the end of the loop.
I've attempted here:
library(tidyverse)
# Generate data
data <- tibble(Colour = paste0("c", 1:1000),
k = sample(x = c(1:10), size = 1000, replace = T))
# Fill the 'bag' with balls of colour 'C', 'k' times
bag <- unlist(map2(.x = data$Colour,
.y = data$k,
.f = ~rep(x = .x, times = .y)))
data.2 <- data %>%
mutate(Grouped_Colours = map2(.x = Colour, .y = k,
.f = ~{
# Take sample of size k without repeatedly sampling the
# same colour (unique() / replace = F) and without
# including each colour in its own group (bag[bag != .x])
.samp <- sample(unique(bag[bag != .x]), size = .y, replace = F)
### EXCLUDE ALL PREVIOUSLY SAMPLED BALLS (ALSO
### EXCLUDING THOSE FROM PREVIOUS LOOPS)
bag <- bag[-match(.samp, bag)]
# print out the sample and mutate it into the
# new column 'Grouped_Colours'
.samp
})
)
I have indicated in caps where I believe the code is causing the undesired result. Ultimately, I need the entire bag to be sampled (i.e. the bag should be empty and the end).
The problem currently is that the balls are sampled the incorrect number of times in the final dataset and each colour should be sampled exactly k times.
Thank you and please let me know if anything is unclear.
EDIT 2022-06-03
I have tried wrapping this sampling process in an if statement to separate the initial sampling from all subsequent pulls. Now the loop can't find the previously sampled balls to exclude from the bag.
data.2 <- data %>%
mutate(Grouped_Colours = pmap(.l = list(..1 = Colour, ..2 = k, ..3 = seq_along(Colour)),
# On the first iteration, sample from the global variable 'bag'
.f = ~{ if (..3 == 1) {
# Take sample of size k without repeatedly sampling the
# same colour (unique() / replace = F) and without
# including each colour in its own group (bag[bag != .x])
.samp <- sample(unique(bag[bag != ..1]), size = ..2, replace = F)
# On every subsequent iteration, sample from the function
# environment variable 'bag' and overwrite the contents
} else {
### EXCLUDE ALL PREVIOUSLY SAMPLED BALLS (ALSO
### EXCLUDING THOSE FROM PREVIOUS LOOPS)
bag <- bag[-match(.samp, bag)]
.samp <- sample(unique(bag[bag != ..1]), size = ..2, replace = F)
}
})
)