如何从R中的组中快速采样

时间:2014-08-13 07:08:26

标签: r sample dplyr

我有一个包含复制值的大型数据集x, 其中一些在其变量中重复:

set.seed(40)
x <- data.frame(matrix(round(runif(1000)), ncol = 10))
x_unique <- x[!duplicated(x),]

我需要在x给定次数内对每个唯一行的所有实例进行采样,因此我创建了一个新的 变量,它只是每行变量的串联:

# Another way of seeing x is as a single value - will be useful later
x_code <- do.call(paste0, x)
u_code <- x_code[!duplicated(x)]

我们需要从x重复的样本样本,复制每个唯一的行s次。 此信息在向量s:

中提供
s <- rpois(n = nrow(x_unique), lambda = 0.9)

问题是,如何从x中抽取个人来达到配额 由s设置,每个唯一的行?这是一个漫长而不美观的方式,它得到了正确的结果:

for(i in 1:length(s)){
 xs <- which(x_code %in% u_code[i])
 sel <- c(sel, xs[sample(length(xs), size = s[i], replace = T)])
}

x_sampled <- x[sel, ]

运行缓慢,编写起来很麻烦。

有没有办法更快,更简洁地生成相同的结果(上面的x_sampled)?肯定有办法!

2 个答案:

答案 0 :(得分:2)

有效地做到这一点的关键是弄清楚如何使用 索引,以及如何尽可能地矢量化。对于你的问题, 如果你找到每个重复行的索引,事情会变得容易得多:

set.seed(40)
x <- data.frame(matrix(round(runif(1000)), ncol = 10))

index <- 1:nrow(x)
grouped_index <- split(index, x, drop = TRUE)
names(grouped_index) <- NULL

然后你可以使用Map()将索引组合成来自和的样本 每组采取的样本数量。我写了一个包装器 sample()以防止x时出现的令人讨厌的行为 长度1。

sample2 <- function(x, n, ...) {
  if (length(x) == 1) return(rep(x, n))
  sample(x, n, ...)
}

samples <- rpois(n = length(grouped_index), lambda = 0.9)
sel <- unlist(Map(sample2, grouped_index, samples, replace = TRUE))
sel
#>  [1]  66  99  99   2   6  31  90  25  42  57  14  14   8   8  12  77  60
#> [18]  17  17  92  76  76  76  70  95  36  36  36 100  91  41  41  28  69
#> [35]  69  54  54  54  54  81  64  96  35  39  29  11  74  93  82  82  24
#> [52]  46  48  48  48  51  51  73  20  37  71  71  58  16  68  94  94  94
#> [69]  80  80  80  13  13  87  87  67  67  86  49  49  88  88  52  75  47
#> [86]  89   7  79  63  78  72  72  19

如果您想保留原始订单,请使用sort()

sort(sel)
#>  [1]   2   6   7   8   8  11  12  13  13  14  14  16  17  17  19  20  24
#> [18]  25  28  29  31  35  36  36  36  37  39  41  41  42  46  47  48  48
#> [35]  48  49  49  51  51  52  54  54  54  54  57  58  60  63  64  66  67
#> [52]  67  68  69  69  70  71  71  72  72  73  74  75  76  76  76  77  78
#> [69]  79  80  80  80  81  82  82  86  87  87  88  88  89  90  91  92  93
#> [86]  94  94  94  95  96  99  99 100

我认为此代码中的瓶颈是split():基本R不会 有一种有效的散列数据帧的方法,所以依赖于粘贴数据帧 列一起。

答案 1 :(得分:1)

您可以使用rep()创建索引向量,然后使用此索引向量对数据进行子集化。

试试这个:

idx <- rep(1:length(s), times=s)

idx的前几个值。注意第二行如何重复两次,而第4行不存在:

idx
 [1]  1  2  2  3  6  7  8 10 11 13 14 14 ......

然后进行子集化。请注意新副本如何具有指示复制的行名称。

x_unique[idx, ]

     X1 X2 X3 X4 X5 X6 X7 X8 X9 X10
1     1  1  0  0  0  1  0  0  1   0
2     1  0  1  0  0  1  0  0  0   0
2.1   1  0  1  0  0  1  0  0  0   0
3     1  1  0  0  1  0  0  0  1   0
6     0  0  0  0  1  1  0  0  0   0
7     0  1  1  0  1  1  0  1  1   1
8     1  1  0  1  0  0  1  1  0   0
10    0  0  1  0  1  1  1  1  0   0
....