3

我有一个data.table类似于这个的对象

library(data.table)

c <- data.table(CO = c(10000,10000,10000,20000,20000,20000,20000),
                SH = c(1427,1333,1333,1000,1000,300,350),
                PRC = c(6.5,6.125,6.2,0.75,0.5,3,3.5),
                DAT = c(0.5,-0.5,0,-0.1,NA_real_,0.2,0.5),
                MM = c("A","A","A","A","A","B","B"))

我正在尝试使用嵌套分组执行计算,将表达式作为参数传递。这是我所拥有的简化版本:

setkey(c,MM)

mycalc <- quote({nobscc <- length(DAT[complete.cases(DAT)]); 
                 list(MKTCAP = tail(SH,n=1)*tail(PRC,n=1),
                      SQSUM = ifelse(nobscc>=2, sum(DAT^2,na.rm=TRUE), NA_real_),
                      COVCOMP = ifelse(nobscc >= 2, head(DAT,n=1), NA_real_),
                      NOBS = nobscc)}) 


myresults <- c[,.SD[,{setkey=CO; eval(mycalc)},by=CO],by=MM]

产生

     MM    CO MKTCAP SQSUM COVCOMP NOBS
[1,]  A 10000 8264.6  0.50     0.5    3
[2,]  A 20000  500.0    NA      NA    1
[3,]  B 20000 1225.0  0.29     0.2    2

在上面的示例中,我有两个使用该ifelse构造的列表元素(在实际代码中有 3 个),都进行相同的测试:如果观察数大于 2,则进行一定的计算(这对于列表的每个元素,每个元素都可以写成一个函数)将被执行,否则我希望这些元素的值为 NA。这些元素的另一个共同点是它们使用我的同一列data.table:称为DAT.

所以我的问题是:有什么方法可以ifelse只做一次测试,如果它是 FALSE,则将值传递NA给列表的各个元素,如果为 TRUE,则为列表的每个元素评估不同的表达式?

注意:我的目标是减少system.time(系统和经过)。如果这种修改不会减少时间和计算,请记住我有 7200 万次观察,这是一个可以接受的答案。我也欢迎更改代码其他部分的建议。

编辑: summaryRprof() 的结果

$by.total
                          total.time total.pct self.time self.pct
"system.time"                  18.94     99.79      0.00     0.00
".Call"                        18.92     99.68      0.10     0.53
"["                            18.92     99.68      0.04     0.21
"[.data.table"                 18.92     99.68      0.02     0.11
"eval"                         18.80     99.05      0.24     1.26
"ifelse"                       18.30     96.42      0.46     2.42
"lm"                           17.70     93.26      0.58     3.06
"sapply"                        8.06     42.47      0.36     1.90
"model.frame"                   7.74     40.78      0.16     0.84
"model.frame.default"           7.58     39.94      0.98     5.16
"lapply"                        6.62     34.88      0.70     3.69
"FUN"                           4.24     22.34      1.10     5.80
"model.matrix"                  4.04     21.29      0.02     0.11
"model.matrix.default"          4.02     21.18      0.26     1.37
"match"                         3.66     19.28      0.86     4.53
".getXlevels"                   3.12     16.44      0.12     0.63
"na.omit"                       2.40     12.64      0.24     1.26
"%in%"                          2.30     12.12      0.34     1.79
"simplify2array"                2.24     11.80      0.12     0.63
"na.omit.data.frame"            2.16     11.38      0.14     0.74
"[.data.frame"                  2.12     11.17      1.18     6.22
"deparse"                       1.80      9.48      0.66     3.48
"unique"                        1.80      9.48      0.54     2.85
"[["                            1.52      8.01      0.12     0.63
"[[.data.frame"                 1.40      7.38      0.54     2.85
".deparseOpts"                  1.34      7.06      0.96     5.06
"paste"                         1.32      6.95      0.16     0.84
"lm.fit"                        1.20      6.32      0.64     3.37
"mode"                          1.14      6.01      0.14     0.74
"unlist"                        1.12      5.90      0.56     2.95
4

1 回答 1

4

而不是像这样形成和操作数据子集:

setkey(c,MM)
myresults <- c[, .SD[,{setkey=CO; eval(mycalc)},by=CO], by=MM]

你可以尝试这样做:

setkeyv(c, c("MM", "CO"))
myresults <- c[, eval(mycalc), by=key(c)]

这应该会加快您的代码速度,因为它避免了 .SD 对象的所有嵌套子集,每个对象都需要自己调用[.data.table.


在您最初的问题上,我怀疑ifelse评估需要花费很多时间,但如果您想避免它们,您可以将它们取出mycalc并使用以下内容:=覆盖所需的值NA

mycalc <- quote(list(MKTCAP = tail(SH,n=1)*tail(PRC,n=1),
                      SQSUM = sum(DAT^2,na.rm=TRUE),
                      COVCOMP = head(DAT,n=1),
                      NOBS = length(DAT[complete.cases(DAT)]))) 
setkeyv(c, c("MM", "CO"))
myresults <- c[, eval(mycalc), by=key(c)]


myresults[NOBS<2, c("SQSUM", "COVCOMP"):=NA_real_]
## Or, alternatively
# myresults[NOBS<2, SQSUM:=NA_real_]
# myresults[NOBS<2, COVCOMP:=NA_real_]
于 2012-06-29T16:50:42.523 回答