使用lapply对R中的数据表进行基准测试,会更慢吗?

时间:2019-06-19 01:14:57

标签: r data.table lapply

我有很多数据集,最终将彼此进行比较。我已经阅读了data.table,使用lapply是分析数据的最快方法,并在帖子中看到了一些基准比较。我注意到它滞后于数据集变得更大并进行了一些基准测试,并且比仅仅使用“汇总”要慢得多。包括一个非常基本的表和代码,以防万一我不知道如何优化data.table速度。

ARM <- rep(seq(1:10), 10000)
TEST <- rep(seq(1:100), 1000)
TIME <- rep(seq(1:5), 20000)
SEX <- rep(1:2, 50000)
RESULTS <- rnorm(100000, mean = 50, sd = 10)

tst <- as.data.frame(cbind(ARM, TEST, TIME, SEX, RESULTS))
tstdt <- as.data.table(tst)
setDT(tstdt)

microbenchmark(tstdt[,.(n = .N), by = list(ARM, TEST, TIME, SEX)],
               tst %>% group_by(ARM, TEST, TIME, SEX) %>% summarize(mean = mean(TEST),n = n()),
               tstdt[,(lapply(.SD, mean)), by = .(ARM, TEST, TIME, SEX), .SDcols = "TEST"])

使用summary方法的结果是最快的。

       min        lq     mean    median        uq      max neval
1 19.65800 21.841651 23.75156 22.585946 23.572930 43.24424   100
2  8.01111  8.487736  9.36991  8.852225  9.451928 19.27691   100
3 22.43461 23.452590 25.07495 24.179198 25.047663 85.74855   100

任何有关如何优化data.tables或帮助我解决问题的信息,将不胜感激。


建议使用更大的数据和代码进行基准测试,包括可配置地更大的数据,更少的运行,不使用.SDcols并取RESULTS列的平均值。

library(dplyr)
library(data.table)

n = 5e6
ARM <- rep(seq(1:10), n / 10)
TEST <- rep(seq(1:100), n / 100)
TIME <- rep(seq(1:5), n / 5)
SEX <- rep(1:2, n / 2)
RESULTS <- rnorm(n, mean = 50, sd = 10)

tst <- data.frame(ARM, TEST, TIME, SEX, RESULTS)
tstdt <- as.data.table(tst)
setDT(tstdt)

microbenchmark::microbenchmark(
  dplyr = tst %>% group_by(ARM, TEST, TIME, SEX) %>% summarize(mean = mean(RESULTS),n = n()),
  dt = tstdt[, .(mean = mean(RESULTS), n = .N), by = .(ARM, TEST, TIME, SEX)],
  times = 10
)

1 个答案:

答案 0 :(得分:6)

在这种情况下,as.data.frame(cbind())导致速度变慢。 cbind()创建一个矩阵,一个矩阵只能有一个类。由于RESULTS为双精度字,这导致所有内容,甚至ID也都变为双精度字:

> tst <- as.data.frame(cbind(ARM, TEST, TIME, SEX, RESULTS))
> str(tst)
'data.frame':   100000 obs. of  5 variables:
 $ ARM    : num  1 2 3 4 5 6 7 8 9 10 ...
 $ TEST   : num  1 2 3 4 5 6 7 8 9 10 ...
 $ TIME   : num  1 2 3 4 5 1 2 3 4 5 ...
 $ SEX    : num  1 2 1 2 1 2 1 2 1 2 ...
 $ RESULTS: num  39.6 43.7 55.2 56.4 57.3 ...

如果我们改为查看data.frame()直接调用,则分组ID现在是整数。

> tst <- data.frame(ARM, TEST, TIME, SEX, RESULTS)
> str(tst)
'data.frame':   100000 obs. of  5 variables:
 $ ARM    : int  1 2 3 4 5 6 7 8 9 10 ...
 $ TEST   : int  1 2 3 4 5 6 7 8 9 10 ...
 $ TIME   : int  1 2 3 4 5 1 2 3 4 5 ...
 $ SEX    : int  1 2 1 2 1 2 1 2 1 2 ...
 $ RESULTS: num  39.6 43.7 55.2 56.4 57.3 ...

具有100,000行的时间:

Unit: milliseconds
         expr       min        lq      mean    median        uq       max neval
  dplyr_cbind 12.731302 12.986901 13.194071 13.089201 13.274701 14.319901    10
 dtplyr_cbind 21.231401 21.414101 24.898921 21.887852 23.049401 50.377402    10
     dt_cbind 18.195001 18.594502 22.280561 19.014401 27.485001 31.494400    10
    dplyr_tib  8.678001  8.720201  8.847401  8.808801  8.967401  9.092001    10
    dtplyr_dt  7.426001  7.518801  8.073871  7.964500  8.181101  9.204701    10
        dt_df  4.875301  5.064301  5.314011  5.235101  5.514301  6.148501    10

使用500万行的时间:

Unit: milliseconds
         expr       min        lq      mean    median        uq       max neval
  dplyr_cbind  811.6987  818.4339  832.8765  830.2082  837.1726  889.3064    10
 dtplyr_cbind 1259.2805 1270.3635 1353.1941 1314.1047 1387.2763 1525.5491    10
     dt_cbind 1150.1462 1266.2028 1308.9606 1309.3525 1345.1788 1446.7356    10
    dplyr_tib  576.7411  582.4006  596.1008  587.3667  596.0505  650.3751    10
    dtplyr_dt  200.4274  211.2533  238.1208  221.9134  247.0926  334.4624    10
        dt_df  170.8695  175.2081  181.6870  177.9083  179.1992  227.1371    10

摘要:一种提高data.table性能的方法是将所有可能为浮点的ID列转换为整数。在这里,较低数据集的性能会有小幅提高,而较大数据集的性能会有较大的提高。