没有重复 ID 的分层随机抽样

Stratified random sampling with no repeated IDs

我有一个数据集,其中每个 id 都有多个样本,可以分层到 group 变量中。我想进行随机抽样,按 group 分层,但不重复 id(即每个 id 只在输出中出现一次)。

我试图修改一些现有的解决方案,但是,所有解决方案似乎都对数据进行了采样,并包括来自单个 id 的多个样本:

我尝试了以下方法,认为 replace = FALSE 可能有助于确保每个 id 中只使用 1 个样本,但这仍然不能满足我的要求。

set.seed(1)
# Data 
data <- data.frame(
  id = c("A", "C", "B", "D", "E", "F", "A", "A", "B", "B", "B", "D", "D", "E", "E", "F"),
  group = c("1", "1", "2", "2", "3", "3", "2", "1", "1", "2", "3", "2", "3", "2", "1", "3"),
  length = c("54", "52", "43", "42", "60", "46", "59", "60", "51", "45", "47", "58", "48", "46", "56", "57"))

# Stratified random sampling by group 
sample <- data %>%
  distinct %>%
  group_by(group) %>%
  sample_n(2, replace = FALSE) %>%
  left_join(data)

sample 输出:

id group length
A   1   60      
C   1   52      
D   2   42      
A   2   59      
B   3   47      
E   3   60      

然而,如上所示,id= Agroup 1和2中重复出现.我想要的理想输出应该看起来像这样,其中每个 id 只出现一次并且样本按 group:

分层
id group length
A   1   54      
C   1   52      
B   2   43      
D   2   42      
E   3   60      
F   3   46

有没有一种方法可以自定义现有的解决方案,以便在对每个 group 进行采样时,如果 id 已经用于另一个 group,它将被排除在外并没有为另一个 group 采样?我知道我可以将 %>% distinct(id) 添加到我的代码中,但我相信这不再是随机的,因为 distinct() 只是选择 id 的第一行。感谢您的帮助!

我有一个候选解决方案,使用 for-loops。当然,该解决方案有点尴尬,并且有一些与您提供的数据相关的警告。但是,该脚本按预期工作。

# Split by group; this provides
# a list with each group.
data_list <- data %>% split(
        f = .$group
)

# shuffle the list to introduce
# randomness
shuffle <- sample(length(data_list))

data_list <- data_list[shuffle]

# Sample from the first indice
# which serves as a baseline for remaining
# samples
sampled_data <- data_list[[1]] %>%
        distinct(id, .keep_all = TRUE) %>%
        sample_n(2)


for (i in 2:length(data_list)) {
        
        # Proceed to next group
        new_data <- data_list[[i]]
        
        
        indicator <- new_data$id %in% sampled_data$id
        
        sampled_data <- bind_rows(
                sampled_data,
                new_data[!indicator,] %>% distinct(id, .keep_all = TRUE) %>% group_by(group) %>% sample_n(2)
        )
        
        
        
}

如果初始 sampled_data 具有特定的 ids,则此算法与您提供的 data 一起工作,否则唯一 ID 的可用性将耗尽。

该算法首先使用 split 将您的数据拆分到各个组中,然后打乱 list 的顺序以在 distinct 函数中引入随机性。

初始采样

我们首先从第一组中取 sample,然后作为其余组的基线。

它首先从基线样本中存在的下一个索引中删除所有 id。然后对其进行采样并将其绑定到列表,并创建一个 data.frame.

下一个样本

新的 data.frame 现在由 id 中不同的前两组组成,并从 data.frame 中存在的剩余索引中删除 id .

最终产品如下;

id group length
1  B     1     51
2  C     1     52
3  D     2     42
4  A     2     59
5  E     3     60
6  F     3     46

如果您提供的数据代表您的实际数据,显然该算法需要一些改进,因为根据 seed,唯一值的可用性会根据您的初始 id 耗尽。

我没有提供 seed 因为我找不到合适的。

这是我最后使用的解决方案。

# Randomise rows
set.seed(x) # play around and set seed accordingly
data_rows <- sample(nrow(data))
data2 <- data[data_rows, ]

# Stratified random sampling 
set.seed(x) # play around and set seed accordingly
randomised <- data2 %>%
              distinct(id, .keep_all = TRUE) %>%
              group_by(group) %>% 
              sample_n(2, replace = FALSE) %>%
              ungroup()