我有以下data.table:
dt = data.table(year=c(1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2),
quar=c(1, 1, 1, 2, 2, 3, 4, 4, 4, 1, 1, 1),
item=c(1, 2, 3, 1, 2, 1, 1, 2, 3, 1, 2, 3))
某些期间(由年份和季度定义)包含三个项目:
其他时期不:
我如何只获取包含所有三个项目的行?
我到目前为止所管理的是
dt[dt[, "i" := nrow(.SD) == 3, .(year, quar)]$i]
> year | quar | item | i
> -----+------+------+-----
> 1 | 1 | 1 | TRUE
> 1 | 1 | 2 | TRUE
> 1 | 1 | 3 | TRUE
> 1 | 4 | 1 | TRUE
> 1 | 4 | 2 | TRUE
> 1 | 4 | 3 | TRUE
> 2 | 1 | 1 | TRUE
> 2 | 1 | 2 | TRUE
> 2 | 1 | 3 | TRUE
按year
和quar
进行分组,然后设置列i
来说明该组是否有效。该组中的所有行均获得i
的计算值。
哪个工作正常。但是,这样做的副作用是在表中添加实际的i
列。
我尝试使用用.(i =...)
声明的临时列,但是i
列具有较短的分组表的长度,我们得到了
dt[dt[, .(i = nrow(.SD) == 3), .(year, quar)]$i]
> Error in `[.data.table`(dt, dt[, .(i = nrow(.SD) == 3), .(year, quar)]$i) :
> i evaluates to a logical vector length 5 but there are 12 rows. [...]
那么,有没有更优雅的解决方法?还是我应该只使用它然后放下i
?
答案 0 :(得分:3)
如果需要子集,请使用.I
获取行索引和子集
dt[dt[, .I[.N == 3], .(year, quar)]$V1]
# year quar item
#1: 1 1 1
#2: 1 1 2
#3: 1 1 3
#4: 1 4 1
#5: 1 4 2
#6: 1 4 3
#7: 2 1 1
#8: 2 1 2
#9: 2 1 3
或使用.SD
,但速度可能很慢
dt[, .SD[.N == 3], .(year, quar)]
或者另一个选择是if/else
dt[, if(.N == 3) .SD, .(year, quar)]
答案 1 :(得分:2)
使用连接的另一个选项:
.PBIX
编辑: 为了解决akrun注释,速度实际上取决于数据集的特征。以下是样本数据集的时间安排:
dt[dt[, .N, .(year, quar)][N==3], on=.(year, quar)]
时间:
set.seed(0L)
ngrp <- 1e6
x <- sample(1:3, ngrp, TRUE)
dt <- data.table(year=rep(1:ngrp, times=x))[,
quar:=year]
microbenchmark::microbenchmark(
mtd0=dt[dt[, .I[.N == 3], .(year, quar)]$V1],
mtd1=dt[dt[, .N, .(year, quar)][N==3], on=.(year, quar)],
times=3L
)
答案 2 :(得分:1)
当然这是一个data.table
问题,@ akrun的回答涵盖了该问题,但是为了完整起见;
一种dplyr
解决方案:
library(dplyr)
dt %>% group_by(year,quar) %>% filter(n()==3)
## A tibble: 9 x 3
## Groups: year, quar [3]
# year quar item
# <dbl> <dbl> <dbl>
#1 1 1 1
#2 1 1 2
#3 1 1 3
#4 1 4 1
#5 1 4 2
#6 1 4 3
#7 2 1 1
#8 2 1 2
#9 2 1 3
在Base
中:
dt[ave(dt$item, dt[,c("year","quar")], FUN = length) == 3, ]
或
freqt <- as.data.frame(table(dt[,c("year", "quar")]))
subt <- freqt[freqt$Freq == 3,c("year", "quar")]
merge(x = subt, y = dt, by = c("year", "quar") , all.x = TRUE)