抱歉,如果之前有人问过这个问题 - 我确实使用了搜索功能。
变量 X 有 1-100 个类别,每个类别的行数可变(均超过 10)。变量 Y 具有与每个 X 相关联的值。如何提取 Y 的随机子样本,每个 X 有 10 个 Y?目标是减少文件中的数据总量(现在它有 11000 行,理想情况下使用二进制编码列 Z 的输出来包含/排除案例(其中 Z 分配给每个类别 X 的随机 10 个 Y。
我猜这应该很容易?
问候, KCW
sample
使用和ave
函数的组合很容易做到这一点:
dfrm$Z <- ave(dfrm$X, dfrm$X, FUN=
function(x) sample(c( rep(TRUE,10), rep(FALSE, length(x)-10))) )
dfrm[dfrm$Z , "Y"]
在 X 的每个类别中,sample 将返回一个逻辑向量,其中包含 10 个 TRUE 和已置换的其余 FALSE,因为这是sample
没有给出第二个长度参数时的行为。这留下了 Z 列,因此您可以对FALSE
-Z 进行其他测试。的第一个参数ave
基本上被忽略并丢弃。它唯一真正的目的是提供一个向量,其长度用于构造逻辑返回值。
在构建函数时ave
,想象应该返回的内容将具有相同的长度并以正确的顺序与单个分组变量类别中的一个 X 选择中的项目对齐,这很有用。因为分组变量是作为三点项目输入的,所以您总是需要指定“FUN=”,否则您会收到难以理解的错误消息。
由于 R 的工作方式,这可能是一个非常快速的选择。
首先,一些示例数据:
set.seed(1)
dat <- data.frame(x = rep(1:10, times = sample(10:30, 10)))
dat$y <- rnorm(nrow(dat))
然后,创建一个z
包含所有值的变量FALSE
。
dat$z <- FALSE
使用rle
和cumsum
找出您的样本,对它们进行子集化,并将它们标记为TRUE
.
RLE = c(1, cumsum(rle(dat$x)$lengths))
dat$z[c(sapply(1:(length(RLE)-1),
function(x) sample(RLE[x]:RLE[x+1], 10)))] <- TRUE
使用本文中的示例数据,这里比较了 DWin 的解决方案、themel 的解决方案、这个基本的子集解决方案,以及来自 base R 的其他两个选项:
library(rbenchmark)
benchmark(BY = do.call(rbind,
by(dat, dat$x,
FUN = function(i) {
i$z <- FALSE;
i[sample(nrow(i), 10), "z"] <- TRUE;
i })),
LAPPLY = do.call(rbind,
lapply(split(dat, dat$x),
FUN = function(i) {
i$z <- FALSE;
i[sample(nrow(i), 10), "z"] <- TRUE;
i })),
SUBSET = {
RLE = c(1, cumsum(rle(dat$x)$lengths));
dat$z <- FALSE;
dat$z[c(sapply(1:(length(RLE)-1),
function(x)
sample(RLE[x]:RLE[x+1], 10)))] <- TRUE },
DDPLY = ddply(df, "x" , function(df) {
pick <- rep(FALSE,nrow(df));
pick[sample(nrow(df),10)] = TRUE;
cbind(df, "z"=pick)
}),
AVE = { dat$z <- FALSE;
ave(dat$x, dat$x,
FUN=function(x)
sample(c(rep(TRUE, 10), rep(FALSE, length(x)-10))))},
columns = c("test", "replications", "elapsed",
"relative", "user.self"),
order = "relative")
# test replications elapsed relative user.self
# 3 SUBSET 100 0.044 1.000000 0.044
# 5 AVE 100 0.078 1.772727 0.080
# 2 LAPPLY 100 0.601 13.659091 0.600
# 1 BY 100 0.675 15.340909 0.680
# 4 DDPLY 100 6.016 136.727273 6.008
使用plyr
,它是单行的:
df <- data.frame(x=rep(1:10, times=1000),y=1:10000)
ddply(df, "x" , function(df) df[sample(nrow(df), 10),])
遵循与我相同的原则,您的逻辑向量可能会更复杂一些
ddply(df, "x" , function(df) {
pick <- rep(FALSE,nrow(df));
pick[sample(nrow(df),10)] = TRUE;
cbind(df, "z"=pick)
})
可以肯定的是,可以改进。