在R中的data.table中基于另一个因子聚合一个因子

时间:2015-07-22 11:39:16

标签: r data.table aggregate

我有一个R data.table对象DT,如下所示:

library(ggplot2)
library(data.table)

DT <- movies[movies$mpaa %in% c("NC-17", "PG", "PG-13", "R"), c("rating", "title", "mpaa")]
setDT(DT)
setnames(DT, colnames(DT), c("Gp", "ID", "FACTOR"))
DT[, FACTOR := droplevels(FACTOR)]
DT[, Gp := as.numeric(as.factor(Gp))]
setkey(DT, ID)
DT <- unique(DT)

DT
      Gp                       ID FACTOR
   1: 43                  $windle      R
   2: 61             'A' gai waak  PG-13
   3: 62    'A' gai waak juk jaap  PG-13
   4: 39                  'R Xmas      R
   5: 38       'Til There Was You  PG-13
  ---                                   
4899: 57                  Zuotian      R
4900: 27 Zyosyuu syukeininn Maria      R
4901: 57                 eXistenZ      R
4902: 45                      xXx  PG-13
4903: 29  xXx: State of the Union  PG-13

我正在尝试根据列FACTOR中的元素汇总Gp列中的数据。我已经能够实现如下。

k <- vector("list", max(DT$Gp))
for (i in 1:max(DT$Gp)) {
  names(k)[i] <- i
  k[[i]] <- DT[Gp == i, as.vector(table(FACTOR))]
}
k <- lapply(k, function(x) as.data.frame(t(x)))
k <- rbindlist(k)
setnames(k, old = colnames(k), new = c("NC-17", "PG", "PG-13", "R"))
k$Gp <- row.names(k)
setcolorder(k, c("Gp","NC-17", "PG", "PG-13", "R"))

head(k)
   Gp NC-17 PG PG-13 R
1:  1     0  0     0 2
2:  2     0  0     0 1
3:  3     0  0     0 2
4:  4     0  0     0 1
5:  5     0  0     0 2
6:  6     0  0     0 3

对于Gp的每个级别,我想获得每个FACTOR级别的记录数。如何仅使用k更优雅地获得所需的结果data.table

2 个答案:

答案 0 :(得分:4)

我建议您使用dcast

require(data.table) # v1.9.4
dcast.data.table(DT, Gp ~ FACTOR, fun.aggregate = length)

或者从current devel, v1.9.5(及以后的版本),我们可以直接使用dcast()

require(data.table) # v1.9.5+
dcast(DT, Gp ~ FACTOR, fun.aggregate = length)

as.list()是一个S3泛型,并且随着更多组而变得非常慢(由于为每个组分派正确的方法所花费的时间)。 table()是另一个缓慢的功能。

dcast()也会自动按Gp列对结果进行排序。

这是一个足够大的基准来强调差异:

set.seed(1L)
bmark = data.table(Gp = sample(1e5, 1e7, TRUE), 
                   FACTOR = sample(levels(DT$FACTOR), 1e7, TRUE))
print(object.size(bmark), units="Mb")
# 114.4 Mb

system.time(ans1 <- dcast(bmark, Gp ~ FACTOR, fun.aggregate = length))
#    user  system elapsed 
#   0.998   0.026   1.030 

system.time(ans2 <- bmark[, as.list(table(FACTOR)), by=Gp])
#    user  system elapsed 
#  14.666   0.141  15.078 

identical(ans1, setkey(ans2, Gp))
# [1] TRUE

数据大小约为114MB,这并不是很大,速度可达~15倍。

答案 1 :(得分:2)

您可以在每个as.list(table(FACTOR))组中使用Gp

DT[, as.list(table(FACTOR)), by = Gp]

这给出了结果:

    Gp NC-17 PG PG-13  R
 1: 43     1  8    26 79
 2: 61     2  9    22 77
 3: 62     0  7    18 63
 4: 39     0 17    24 52
 5: 38     1 14    13 77
 6: 57     1 11    23 72
 7: 48     0 16    29 78
...

(要按照示例输出中Gp的顺序排序,您可以将其更改为DT[order(Gp), as.list(table(FACTOR)), by = Gp])。