按组生成可重复的随机数

3
我有一个相对较大的数据集(> 500k行),由两个分组变量定义的421个组。示例数据如下:
df<-data.frame(group_one=rep((0:9),26), group_two=rep((letters),10))

head(df)

  group_one group_two
1         0         a
2         1         b
3         2         c
4         3         d
5         4         e
6         5         f

...等等。
我想要的是一些分层样本,根据(group_one x group_two)的成员身份有一定数量(目前为k = 12,但该数字可能会变化)。每个组的成员资格应由一个新列sample_membership指示,其值为1到k(再次为12)。我应该能够按sample_membership子集,并获得多达12个不同的样本,每个样本在考虑group_one和group_two时都是代表性的。
因此,最终数据集可能如下所示:
  group_one group_two sample_membership
1         0         a                 1  
2         0         a                12
3         0         a                 5
4         1         a                 5
5         1         a                 7
6         1         a                 9

想法?非常感谢!

1
你的标题说“不重复”,但是你的问题没有提到它。你想要无重复抽样(并且你保证每组<=12行)吗? - Gregor Thomas
这是一个错误。一定应该使用替换。对于造成的混淆,我深表歉意。 - seehuus
请随意编辑您的问题标题以更正错误。 - Gregor Thomas
4个回答

8
也许是这样的吗?
library(dplyr)
  df %>% 
    group_by(group_one, group_two) %>% 
    mutate(sample_membership = sample(1:12, n(), replace = FALSE))

4
这里有一个只有一行的data.table方法,如果你有一个很长的data.frame,你应该考虑使用它。
library(data.table)

setDT(df)

df[, sample_membership := sample.int(12, .N, replace=TRUE), keyby = .(group_one, group_two)]

df
#    group_one group_two sample_membership
#   1:         0         a                 9
#   2:         0         a                 8
#   3:         0         c                10
#   4:         0         c                 4
#   5:         0         e                 9
# ---                                      
# 256:         9         v                 4
# 257:         9         x                 7
# 258:         9         x                11
# 259:         9         z                 3
# 260:         9         z                 8

如果需要进行不放回的抽样,请使用 replace=FALSE,但是请注意,在每组中确保元素小于k个。 或者:

如果您想要使用“无需必要替换的抽样”(这是一个虚构的术语-不确定在这里什么是正确的术语),因为每组成员超过k,但仍希望尽可能保持各组大小相等,则可以执行以下操作:

# example with bigger groups
k <- 12L
big_df <- data.frame(group_one=rep((0:9),260), group_two=rep((letters),100))
setDT(big_df)

big_df[, sample_round := rep(1:.N, each=k, length.out=.N), keyby = .(group_one, group_two)]
big_df[, sample_membership := sample.int(k, .N, replace=FALSE), keyby = .(group_one, group_two, sample_round)]
head(big_df, 15) # you can see first repeat does not occur until row k+1 

在每一“抽样轮次”(组内前k个观察值,组内第二个k个观察值等)中,都是无放回的随机抽样。如果需要,下一个抽样轮次会使所有k个分配再次可用。

这种方法可以很好地分层样本(但只有当每个组内成员数是k的倍数时才能完全均匀地进行抽样)。


2

以下是一个基于R语言的方法,假设你的数据框已按照组别排序:

# get number of observations for each group
groupCnt <- with(df, aggregate(group_one, list(group_one, group_two), FUN=length))$x

# for reproducibility, set the seed
set.seed(1234)    
# get sample by group
df$sample <- c(sapply(groupCnt, function(i) sample(12, i, replace=TRUE)))

这很棒,但似乎有一些(group_one x group_two)组合中成员为零,因此groupCnt最终会出现一些NAs。如果我将这些NAs替换为零,则df$sample的行数比df少得多,因此失败了。你有什么想法? - seehuus
它在你的示例中似乎可以工作。您能提供一个出现此问题的数据框吗?aggregate创建一个仅包含存在的组1和组2组合的数据框。由于groupCnt使用length函数构建,因此不应产生NAs。 - lmo
一种可能性是您的原始数据中每个组有超过12个观测值。如果是这种情况,您将不得不将样本限制为前12个(或随机选择12个),在每个组内进行替换抽样,或将k增加到每个组的最大数量以上。 - lmo
每个组中都有超过12个,我需要进行有放回的抽样 - 我的错误在于标题。请原谅我的疏忽。 - seehuus
@seehuus,我已经编辑了我的答案以反映替换取样。请考虑按照 gregor 的建议编辑您的问题。 - lmo

0

以下是使用dplyr的未经测试示例,如果它不起作用,可能会指引您正确的方向。

library( dplyr )
set.seed(123)
df <- data.frame(
  group_one = as.integer( runif( 1000, 1, 6) ),
  group_two = sample( LETTERS[1:6], 1000, TRUE)
) %>%
  group_by( group_one, group_two ) %>%
  mutate(
    sample_membership = sample( seq(1, length(group_one) ), length(group_one), FALSE)
  )

祝你好运!


请注意,您可以使用 dplyr :: n() 代替 length(group_one),这样可以节省一些打字。 - Shorpy
谢谢,虽然这会从1到(group_one x group_two)中进行随机分配,但并不会在12处达到峰值。我想知道是否可以将每个组中的项目数除以12并四舍五入/截断。我会考虑的。再次感谢! - seehuus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接