【问题标题】:Randomly sampling groups, followed by sampling within these sampled groups随机抽样组,然后在这些抽样组内抽样
【发布时间】:2020-05-31 05:15:52
【问题描述】:

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

  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),然后从这 4 个组中采样观察/行(来自第 4 组的 4 个 id(例如 5007、5007、5006、5009);来自第 3 组的 2 个 id(两次,因为第 3 组被采样了两次),来自第 1 组的 3 个 id,全部替换),并返回采样的行一起在一个数据框中(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 的解决方案(见下文)更直接,因此我接受了它作为我问题的答案。

【问题讨论】:

  • 不清楚预期的输出。第 1 步中的 sampled.group 与第 2 步没有任何参考。如果您需要filter 基于sampled.group data1 %&gt;% filter(!group %in% sampled.group)。还有,y.group有什么用
  • 如果是生成只有采样组的数据集data1 %&gt;% filter(group %in% sampled.group) %&gt;% group_by(group) %&gt;% sample_frac(1, replace = TRUE) %&gt;% ungroup
  • 预期输出应该是一个数据框,其中包含来自随机抽样(有替换)的组的抽样观察。例如。基于上面的数据集示例:原始数据集中有 4 个组,所以我想对 4 个组进行替换采样(例如,采样组 = 组 4、3、3、1),然后从这 4 个组中采样观察/行(来自第 4 组的 4 个 id(例如 5007、5007、5006、5009);来自第 3 组的 2 个 id(两次,因为第 3 组被采样了两次),来自第 1 组的 3 个 id,全部替换),并返回采样的行一起放在一个数据框中(4+2+2+3 = 11 行)。
  • @akrun 查看我上面的评论(也添加到帖子中)。我尝试了您的建议,这有助于过滤采样组,但作为下一步,我想在这些组中随机采样,替换的行数等于组的大小,但还要考虑到某些组可能会被多次采样次(所以我想多次重复这些组的采样过程,例如,一个有 3 行的组被采样两次,输出中应该有 2*3=6 个采样行)。 y.group 用于之后的计算,可以忽略(为混淆道歉)。

标签: r random grouping sampling resampling


【解决方案1】:

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

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)]

现在我们可以通过从新列表中每个数据帧的行中进行替换抽样来对每个组进行抽样within。我们使用 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) &lt;- 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 创建

【讨论】:

  • 太好了,这行得通!发布问题后,我自己继续提出问题并得出了一个替代方案(我将其添加到开篇帖子中),但您的问题似乎更直接,所以我会接受它作为答案!
  • @CJPW1987 太好了 - 很高兴我能帮上忙。
猜你喜欢
  • 2016-09-06
  • 2013-08-17
  • 1970-01-01
  • 2018-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多