You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何sapply(df, sum)性能优于base::colSums?附基准测试

为什么sapply(df, sum)比base::colSums(df)更快?

我发现使用sapply(df, sum)的速度比base::colSums(df)更快,甚至对矩阵使用base::colSums(M)时也是如此。这是为什么?我是否忽略了什么?一直都是这样吗?

基准测试

在10K×10K数据框上的基准测试结果如下:

$ Rscript --vanilla speed_test.R 
Unit: milliseconds
      expr       min        lq      mean   median       uq       max neval  cld
    sapply 125.76717 125.77749 126.21036 125.7878 126.4320 127.07610     3 a   
   colSums 288.09562 293.57566 298.28873 299.0557 303.3853 307.71486     3  b  
 colSums_M 137.68780 139.08794 141.25548 140.4881 143.0393 145.59055     3   c 
  colSums2  55.49845  55.86153  56.04262  56.2246  56.3147  56.40479     3    d

  # A tibble: 4 × 13
  expression      min   median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time result memory               time           gc              
  <bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm> <list> <list>               <list>         <list>          
1 sapply      124.8ms  124.9ms      8.01   440.8KB     0        5     0      625ms <NULL> <Rprofmem [6 × 3]>   <bench_tm [5]> <tibble [5 × 3]>
2 colSums     285.7ms  329.5ms      3.04   763.4MB     3.04     2     2      659ms <NULL> <Rprofmem [403 × 3]> <bench_tm [2]> <tibble [2 × 3]>
3 colSums_M     131ms    131ms      7.63    78.2KB     0        4     0      524ms <NULL> <Rprofmem [1 × 3]>   <bench_tm [4]> <tibble [4 × 3]>
4 colSums2     55.4ms   55.8ms     17.9     78.2KB     0        9     0      502ms <NULL> <Rprofmem [1 × 3]>   <bench_tm [9]> <tibble [9 × 3]>

测试环境:R版本4.4.2(2024-10-31),AlmaLinux 9.5系统,NETLIB或OPENBLAS-OPENMP(无影响),AMD Ryzen 7 7700X处理器。

补充测试

在旧款AMD FX(tm)-8350处理器上进行相同基准测试,结果如下:

$ Rscript --vanilla speed_test.R 
## col sums:
Unit: milliseconds
      expr      min       lq     mean   median       uq      max neval  cld
    sapply 169.5607 169.7373 169.8201 169.9138 169.9499 169.9859     3 a   
   colSums 573.5435 575.7917 576.6825 578.0399 578.2520 578.4640     3  b  
 colSums_M 130.5275 130.6009 130.6255 130.6744 130.6745 130.6746     3   c 
  colSums2 148.7892 149.0359 149.4866 149.2826 149.8354 150.3881     3    d

# A tibble: 4 × 13
  expression      min   median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time result memory               time           gc              
  <bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm> <list> <list>               <list>         <list>          
1 sapply        170ms    174ms      5.79   440.8KB     0        3     0      518ms <NULL> <Rprofmem [6 × 3]>   <bench_tm [3]> <tibble [3 × 3]>
2 colSums       703ms    703ms      1.42   763.4MB     1.42     1     1      703ms <NULL> <Rprofmem [399 × 3]> <bench_tm [1]> <tibble [1 × 3]>
3 colSums_M     131ms    131ms      7.63    78.2KB     0        4     0      524ms <NULL> <Rprofmem [1 × 3]>   <bench_tm [4]> <tibble [4 × 3]>
4 colSums2      150ms    150ms      6.65    78.2KB     0        4     0      602ms <NULL> <Rprofmem [1 × 3]>   <bench_tm [4]> <tibble [4 × 3]>

或许base::colSums尚未针对新硬件优化?


测试代码

set.seed(42)

m <- 1e4; n <- 1e4
M <- matrix(rnorm(m*n), m, n)
df <- data.frame(M)

options(width=200)

microbenchmark::microbenchmark(
  sapply=sapply(df, sum),
  colSums=colSums(df),
  colSums_M=colSums(M),  ## <-- USING MATRIX INPUT TO AVOID as.matrix() OVERHEAD
  colSums2=matrixStats::colSums2(M),
  times=3L,
  check='equivalent'
  ) |> print()

bench::mark(sapply=sapply(df, sum),
            colSums=colSums(df),
            colSums_M=colSums(M),
            colSums2=matrixStats::colSums2(M), check=FALSE)

内容的提问来源于stack exchange,提问作者jay.sf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 21:08:12