我有一个包含复制值的大型数据集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
)?肯定有办法!
答案 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
....