2017-06-20 27 views
3

我想要的.SD功能与by =在非球菌结合加入:如何选择指定列中每个组的前n行(加入后)?

data.table - select first n rows within group

.EACHI in data.table

示例数据:

tmp_dt1<- data.table(grp = c(1,2), time = c(0.2, 0.6, 0.4, 0.8, 0.25, 0.65)) 
tmp_dt2 <- data.table(grp = c(1,2), time_from = c(0.1, 0.5)) 
tmp_dt2 <- tmp_dt2[, time_to := time_from + 0.2] 

> tmp_dt1 
    grp time 
1: 1 0.20 
2: 2 0.60 
3: 1 0.40 
4: 2 0.80 
5: 1 0.25 
6: 2 0.65 
> tmp_dt2 
    grp time_from time_to 
1: 1  0.1  0.3 
2: 2  0.5  0.7 

现在,我需要的输出是每个组中的第一次位于tmp_dt2中定义的范围之间。我可以得到所有这样的时代:

> tmp_dt1[tmp_dt2, .(grp, time = x.time, time_from, time_to), on = .(grp, time >= time_from, time <= time_to)] 
    grp time time_from time_to 
1: 1 0.20  0.1  0.3 
2: 1 0.25  0.1  0.3 
3: 2 0.60  0.5  0.7 
4: 2 0.65  0.5  0.7 

不过,我有一些麻烦,使用by提取每个grp第n行,没有链接。举个例子,当n = 1,所需的输出是:

tmp_dt1[tmp_dt2, .(grp, time = x.time, time_from, time_to), 
     on = .(grp, time >= time_from, time <= time_to)][, .SD[1], by = grp] 

     grp time time_from time_to 
1: 1 0.2  0.1  0.3 
2: 2 0.6  0.5  0.7 

但是,这样的:

> tmp_dt1[tmp_dt2, .(time = x.time[1], time_from[1], time_to[1]), on = .(grp, time >= time_from, time <= time_to), by = grp] 
Error in `[.data.table`(tmp_dt1, tmp_dt2, .(time = x.time[1], time_from[1], : 
    object 'time_from' not found 

不起作用。

使用,.SD接近,但给我结果的混乱结束在选择的列的条款:

tmp_dt1[tmp_dt2, .SD[1], on = .(grp, time >= time_from, time <= time_to), by = grp] 
    grp time 
1: 1 0.2 
2: 2 0.6 

为什么我不想做一个链的原因是因为memory issues。请注意,我只对data.table软件包解决这个问题感兴趣。

回答

2

你试过

tmp_dt1[tmp_dt2, on=.(grp, time>=time_from, time<=time_to), 
    x.time, by=.EACHI] # or head(x.time, 2L) to get first 2 rows etc. 

您需要自己重命名重复列,直到内部处理完成为止,如here所述。

+1

谢谢你的回答,也是非常有用的链接,解释'x.'符号 – Alex

2

一个选项是指定mult= first

tmp_dt1[tmp_dt2, .(grp, time = x.time, time_from, time_to), mult = "first", 
      on = .(grp, time >= time_from, time <= time_to)] 
# grp time time_from time_to 
#1: 1 0.2  0.1  0.3 
#2: 2 0.6  0.5  0.7 
+0

谢谢,“first n”呢? (编辑问题以消除第一行的重点) – Alex

+0

@Alex'mult'只有'first','last'和'all'选项。你可以查看[这里](https://cran.r-project.org/web/packages/data.table/vignettes/datatable-keys-fast-subset.html)对于一般情况,你已经有了答案 – akrun

+0

谢谢,所以没有办法避免创建第一个大数据表,然后对它进行子集化? – Alex

1

如果你想减少内存使用另一种解决方案可能是更多的内存,即使它看起来很奇怪存储临时原来的链接方法有效导致一个变量(但它只包含两列,每个组只包含前n行)并仍使用链接(但是在原始数据的较小子集上):

n = 1  # parameter: first "n" rows per group 
selected.rows <- tmp_dt1[tmp_dt2, .(rownum = .I[1:n]), on = .(grp, time >= time_from, time <= time_to), by = grp] 
tmp_dt1[selected.rows$rownum][tmp_dt2, .(grp, time = x.time, time_from, time_to), on = .(grp, time >= time_from, time <= time_to)] 

不是很优雅,也许慢(它复制的连接逻辑,并要求加入两倍 - 即使在第二种情况下设置减少子)......

临时结果集包含每个行号“匹配”,在原始数据表(使用data.table.I符号):

selected.rows 

    grp rownum 
1: 1  1 
2: 2  2 

这将是巨大的,该解决方案使用一个真正的大数据表链比较...(如果我有更多的时间我会简介这个)