随机抽样组,然后在这些抽样组内进行抽样

Randomly sampling groups, followed by sampling within these sampled groups

我的数据集包含几个组,每个组可以有不同数量的独特观察。我按组进行一些计算(在下面的代码中进行了简化),从而得出每个组的汇总值。接下来,为了一个bootstrap,我想:

  1. 对有放回的组进行随机抽样(抽样组数 = 等于原始数据集中不同组的数量)
  2. 在这些抽样组中,随机抽取有放回的观察值(每组抽样观察值的数量 = 等于原始数据集中该组中唯一观察值的数量)

我的数据设置 (data1) 的简化版本:

data1:

id    group  y
1001  1      10
1002  1      15
1003  1      3
3002  2      24
3003  2      15
3005  2      37
3006  2      32
3007  2      11
4001  3      12
4002  3      15
5006  4      7
5007  4      9
5009  4      22
5010  4      19

例如基于上面的数据集示例:原始数据集中有 4 个组,所以我想对 4 个组进行替换采样(例如组采样 = 组 4,3,3,1),然后从中采样 observations/rows 4 组(来自第 4 组的 4 个 ID(例如 5007、5007、5006、5009);来自第 3 组的 2 个 ID(两次,因为第 3 组被采样了两次),以及来自第 1 组的 3 个 ID,均有替换),以及 return 数据帧中的采样行(4+2+2+3 = 11 行)。

对于以上内容,我有一些代码分别用于这些步骤,但我似乎无法将它们组合起来:

# Calculate group value
y.group <- tapply(data1$y,data1$group,mean)

# Step 1. Sample groups, with replacement:
sampled.group <- sample(1:length(unique(data1$group)),replace=T)

# Step 2. Sample within groups, with replacement
data2 <- data.frame(data1 %>%
   group_by(group) %>%   # for each group
   sample_frac(1, replace = TRUE) %>%
   ungroup)

显然,上面的完整代码没有做我想要的,因为在第 2 步中,第 1 步中的采样组被忽略,因为它只使用原始组 var(我知道这个)。我尝试使用第 1 步解决此问题,并尝试生成一个仅包含采样组观察结果的新数据框(如果对一个组进行多次采样,则重复,这很可能会发生),然后将第 2 步应用于新的数据框,但我无法让它工作。

我想我只是走错了路或者想太多了。希望你能给我一些关于如何进行的建议。

编辑: 在等待任何可能的解决方案时,我自己继续研究这个问题,结果是:

total.result <- c()
for (j in 1:length(unique(data1$group))){
     sampled.group <- sample(1:length(unique(data1$group)),size=1,replace=T)
     group.result <- sample_n(data1[data1$group==sampled.group,],
            size=length(unique(data1$id[data1$group==sampled.group])),replace=T)
     total.result <- rbind(total.result,group.result)
     }

(所以基本上使用循环一次对一组进行采样,为每个组创建数据集,然后从中采样单独的行,最后将结果与 rbind 组合)

不过,我认为 Allan Cameron 的解决方案(见下文)更直接,所以我接受了那个作为我问题的答案。

我想这就是您要找的。让我们从可重现格式的数据开始:

data1 <- structure(list(id = structure(1:14, .Label = c("1001", "1002", 
"1003", "3002", "3003", "3005", "3006", "3007", "4001", "4002", 
"5006", "5007", "5009", "5010"), class = "factor"), group = structure(c(1L, 
1L, 1L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 4L, 4L, 4L, 4L), .Label = c("1", 
"2", "3", "4"), class = "factor"), y = structure(c(1L, 4L, 8L, 
7L, 4L, 10L, 9L, 2L, 3L, 4L, 11L, 12L, 6L, 5L), .Label = c("10", 
"11", "12", "15", "19", "22", "24", "3", "32", "37", "7", "9"
), class = "factor")), class = "data.frame", row.names = c(NA, 
-14L))

并且只是为了确保:

data1
#>      id group  y
#> 1  1001     1 10
#> 2  1002     1 15
#> 3  1003     1  3
#> 4  3002     2 24
#> 5  3003     2 15
#> 6  3005     2 37
#> 7  3006     2 32
#> 8  3007     2 11
#> 9  4001     3 12
#> 10 4002     3 15
#> 11 5006     4  7
#> 12 5007     4  9
#> 13 5009     4 22
#> 14 5010     4 19

我们首先使用 split 函数将 group 的数据帧拆分为更小的数据帧。这给了我们一个包含四个数据框的列表,每个数据框都包含其各自组的所有成员。 (set.seed 纯粹是为了让这个例子可以重现)。

set.seed(69)
split_dfs <- split(data1, data1$group)

现在我们可以对这个列表进行采样,为我们提供了一个新的列表,其中包含四个数据框,并从 split_dfs 中进行了替换。每个人都将再次包含其各自组的所有成员,当然有些整个组可能会被多次采样,而其他整个组根本没有被采样。

sampled_group_dfs <- split_dfs[sample(length(split_dfs), replace = TRUE)]

现在我们可以通过从新列表中每个数据框的行中进行替换抽样,在每个组中进行抽样。我们使用 lapply

对列表中的所有数据框执行此操作
all_sampled <- lapply(sampled_group_dfs, function(x) x[sample(nrow(x), replace = TRUE), ])

剩下的就是将此列表中的所有结果数据帧重新组合在一起以获得我们的结果:

result <- do.call(rbind, all_sampled)

正如您从最终结果中看到的那样,恰好四个组中的每个组都被采样了一次(这只是偶然 - 改变 set.seed 以获得不同的结果)。但是,在组内显然存在一些重复绘制。事实上,由于 R 要求数据框中的行名称是唯一的,因此可以很容易地通过附加到重复行名称的 .1 来挑选这些行名称。如果您不喜欢这样,您可以使用 rownames(result) <- seq(nrow(result))

重置行名称
result
#>          id group  y
#> 4.14   5010     4 19
#> 4.14.1 5010     4 19
#> 4.11   5006     4  7
#> 4.13   5009     4 22
#> 1.3    1003     1  3
#> 1.3.1  1003     1  3
#> 1.2    1002     1 15
#> 3.9    4001     3 12
#> 3.9.1  4001     3 12
#> 2.5    3003     2 15
#> 2.5.1  3003     2 15
#> 2.6    3005     2 37
#> 2.7    3006     2 32
#> 2.5.2  3003     2 15

reprex package (v0.3.0)

于 2020-02-15 创建