快速方式(矢量化?)将函数列表应用于数据帧中的相应列

时间:2016-05-18 07:31:17

标签: r plyr

我有一个可变长度的命名列表,包含函数

mFunc <- list(A = identity, B = exp)

我还有data.frame个名称是mFunc名称的超集:

dat <- data.frame(A = 1:3, B = 1:3, C = 1:3)

我想要做的是将mFunc中的所有功能应用到dat中的相应列。如果我愿意手工做,我会做

dat$A <- mFunc$A(dat$A)
dat$B <- mFunc$B(dat$B)

,预期结果如下:

#   A         B C
# 1 1  2.718282 1
# 2 2  7.389056 2
# 3 3 20.085537 3

我在考虑在mFunc

的名字上使用循环
library(plyr)
dat[, names(mFunc)] <- llply(names(mFunc), function(n) mFunc[[n]](dat[[n]]))

给了我想要的结果。我想知道是否有更快(矢量化)的方法,而不使用隐式循环?

1 个答案:

答案 0 :(得分:0)

<强>基准

继续讨论后,我使用llplylapply解决方案做了一些基准测试:

library(dplyr)
library(tidyr)
library(microbenchmark)

makeTestData <- function(n, m = 10) {
   ret <- matrix(1, m, n)
   as.list(as.data.frame(ret))
}

d1e7 <- makeTestData(1e7)
d1e6 <- makeTestData(1e6)
d1e5 <- makeTestData(1e5)
d1e4 <- makeTestData(1e4)

(mb <- microbenchmark(dplyr_1e7 = llply(d1e7,  sum),
                      base__1e7 = lapply(d1e7, sum),
                      dplyr_1e6 = llply(d1e6,  sum),
                      base__1e6 = lapply(d1e6, sum),
                      dplyr_1e5 = llply(d1e5,  sum),
                      base__1e5 = lapply(d1e5, sum),
                      dplyr_1e4 = llply(d1e4,  sum),
                      base__1e4 = lapply(d1e4, sum),
                      unit = "s"))

#  Unit: seconds
#       expr         min          lq        mean      median          uq        max neval  cld
#  dplyr_1e7 0.516720538 0.589467527 0.684496553 0.626970606 0.713114314 1.50305854   100    d
#  base__1e7 0.510537527 0.568317076 0.650109031 0.593912047 0.654385189 1.65846752   100   cd
#  dplyr_1e6 0.498767583 0.574463177 0.678273933 0.614690247 0.695204388 1.22767911   100    d
#  base__1e6 0.490427644 0.543392591 0.610153445 0.587542713 0.638059997 1.03797757   100   c 
#  dplyr_1e5 0.045505505 0.047664210 0.076620745 0.049840086 0.062213015 0.83327188   100  b  
#  base__1e5 0.043557401 0.046385212 0.079063845 0.050644790 0.079270672 0.54647818   100  b  
#  dplyr_1e4 0.004488338 0.004746704 0.005941600 0.004970133 0.005845892 0.03784612   100 a   
#  base__1e4 0.004290173 0.004527419 0.006759915 0.004698939 0.005140864 0.04752546   100 a

还有一些统计数据:

mb %>% group_by(expr) %>% summarise(mean = mean(time)) %>%
   separate(expr, c("system", "size"), sep = "\\_+") %>%
   spread(system, mean) %>% mutate(ratio = base / dplyr)   

# Source: local data frame [4 x 4]

#    size      base     dplyr     ratio
#   (chr)     (dbl)     (dbl)     (dbl)
# 1   1e4   6759915   5941600 1.1377262
# 2   1e5  79063845  76620745 1.0318856
# 3   1e6 610153445 678273933 0.8995679
# 4   1e7 650109031 684496553 0.9497623

<强>结论

因此,base解决方案对于大数据集快6%,对小数据集慢13%(!)。绝对两者的执行时间具有相同的幅度。因此,我可以接受使用同一个动词族的小延迟(即使存在:对我来说也不明显)。