在大型data.table中通过.N子集多个列

时间:2014-09-11 22:05:09

标签: r data.table

我有一个包含数百万行和30列的大data.table。列包含不同数量的分类功能。我想删除任何不到一定比例的功能。

以下是一个例子:

dt <- data.table(id=1:18,col1=c(rep("a",5), rep("b",10), rep("c",3)), col2=c(rep("d",12),rep("e",5),"f"))
dt
    id col1 col2
 1:  1    a    d
 2:  2    a    d
 3:  3    a    d
 4:  4    a    d
 5:  5    a    d
 6:  6    b    d
 7:  7    b    d
 8:  8    b    d
 9:  9    b    d
10: 10    b    d
11: 11    b    d
12: 12    b    d
13: 13    b    e
14: 14    b    e
15: 15    b    e
16: 16    c    e
17: 17    c    e
18: 18    c    f

例如,我只想保留每列发生超过0.5的比例的功能:

> dt[,.N,by=col1][N/sum(N)>0.5]
   col1  N
1:    b 10

> dt[,.N,by=col2][N/sum(N)>0.5]
   col2  N
1:    d 12

我接触这个的方法是循环遍历列并使用%in%

for (i in 1:2) dt[, paste0('newcol',i) :=lapply(dt[[paste0('col',i)]],
 function(y) ifelse(y %in% dt[,.N,by=dt[[paste0('col',i)]]][N/sum(N)>0.5][[1]],y,"") )]

然后我创建一个包含合并值dt[, merge := paste(newcol1,newcol2), by=id]的新列 它在合并列中获得了我想要的输出:

> dt
    id col1 col2 newcol1 newcol2 merge
 1:  1    a    d               d     d
 2:  2    a    d               d     d
 3:  3    a    d               d     d
 4:  4    a    d               d     d
 5:  5    a    d               d     d
 6:  6    b    d       b       d   b d
 7:  7    b    d       b       d   b d
 8:  8    b    d       b       d   b d
 9:  9    b    d       b       d   b d
10: 10    b    d       b       d   b d
11: 11    b    d       b       d   b d
12: 12    b    d       b       d   b d
13: 13    b    e       b            b 
14: 14    b    e       b            b 
15: 15    b    e       b            b 
16: 16    c    e                      
17: 17    c    e                      
18: 18    c    f         

麻烦的是,这对大型数据集来说确实是。我怀疑我没有在&#34; data.table-y&#34;办法。我还必须非常小心不要复制原始数据集,因为它几乎不适合我的RAM,这就是为什么data.table首先如此吸引人的原因。我不在乎是否有任何中间步骤,只要过程更快。

> sessionInfo()
R version 3.0.2 (2013-09-25)
Platform: x86_64-apple-darwin10.8.0 (64-bit)

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] data.table_1.9.2

loaded via a namespace (and not attached):
[1] plyr_1.8.1    Rcpp_0.11.2   reshape2_1.4  stringr_0.6.2 tools_3.0.2 

1 个答案:

答案 0 :(得分:2)

希望这次我做对了。错误的答案浪费了太多时间!

cols = paste("col", 1:2, sep="")
rows = nrow(dt)
for (i in seq_along(cols)) {
    dt[, (cols[i]) := if (.N/rows <= .5) "", by=c(cols[i])]
}
dt[, merge := do.call(paste, c(as.list(dt)[-1L], sep= " "))]

这是1e6 * 30列的基准:

set.seed(1L)
dt = setDT(lapply(1:30, function(x) sample(letters[1:4], 1e6, TRUE)))
system.time({
    cols = paste("V", 1:30, sep="")
    rows = nrow(dt)
    for (i in seq_along(cols)) {
        dt[, (cols[i]) := if (.N/rows <= .5) "", by=c(cols[i])]
    }
    dt[, merge := do.call(paste, c(as.list(dt)[-1L], sep= " "))]
})
#  user  system elapsed 
# 4.880   0.086   5.095 

我会让你接受任何进一步的优化。祝你好运!