【发布时间】:2017-10-18 11:55:50
【问题描述】:
我正在尝试创建一个大数据集的子样本,其中每个因子都有不同的 n。我希望能够非常快地做到这一点,因为我正在这样做数十万次。你能帮我使用 data.tables 优化这个过程吗?
我现在要做的是在 data.table 中添加一个“行号”rn,使用各种 n 对其进行采样,然后根据它进行子集。我认为一定有更聪明的方法可以做到这一点,但我似乎无法弄清楚。
# generate data.table
DT <- data.table(rn = 1:100, factor = letters[1:3],
value = rnorm(100, c(1, 5, 10)))
# subset based on "row number" with various numbers per category
subsetrn <- DT[, .(rn = sample(rn,
if (factor == "a") 12
else if (factor == "b") 20
else if (factor == "c") 5
else NULL, replace = TRUE)),
by = factor]
# subset
ss <- DT[rn %in% subsetrn[, rn]]
编辑:我见过这种从 data.table 中快速采样的方法,但它不是按因素来做的:https://stackoverflow.com/a/33201094/5252333 我还看到了如何对等量的每个因素执行此操作的技巧,但不是针对不同数量的每个因素。
EDIT2:我一直在使用@akron 的解决方案,但仍然遇到问题:
如果我有一个为 0 的因子,则说明有问题:
# generate data.table
DT <- data.table(factor = letters[1:4],
value = rnorm(300, c(1, 5, 10)))
# subset based on "row number" with various numbers per category subsetrn
# index data table with numbers
id <- data.table(factor = letters[1:4], val = c(12, 20, 5, 0))
# map our DT onto it, then subsample by the new val
ssid <- DT[id, on = .(factor)][, sample(.I, val[1], replace = TRUE), factor]
# subset
ss <- DT[ssid[, V1]]
count(ss[, factor])
## x freq
## 1 a 10
## 2 b 12
## 3 c 5
## 4 d 10
# this is wrong! It only works if I do it like this
ss <- DT[id, on = .(factor)][ssid[, V1]]
我希望能够获得 ssid,这样我就可以DT[ssid[, V1]](或DT[ssid]),这样我就可以通过引用来做所有事情,而不是制作 DT 的本地副本。在我的应用程序中,这一切都包含在一个函数中,该函数当前复制 DT 的一小部分 50k 次,大约需要 25 分钟。该函数对子集执行一些计算,然后返回输出。这很慢,我想知道是否可以通过某种方式通过引用来做到这一点。
这个问题现在可能变得有点太具体了;-)。
【问题讨论】:
-
试试
DT[data.table(factor = letters[1:3], val = c(12, 20, 5)), on = .(factor)][, sample(DT$rn, val[1], replace = TRUE), factor] -
@akrun: 返回一个带有
factor和采样的rn的data.table,所以在那之后我仍然需要对DT进行子集化。所以它是所有if (else)语句的一个很好的替代品,但我想知道这整个事情是否可以一步完成,所以我根本不需要rn。 -
不需要
rn。您可以使用.I代替rn -
这两个选项之间的差异显然已经很明显了:在获得
rn10k 次的两种方法上使用微基准测试,我的 if/else 方法和您的 @987654337 的平均值为 95.43 纳秒@ 方法 31.47 纳秒。
标签: r data.table row sample