当前位置: 首页 > 知识库问答 >
问题:

重新审视data.table与dplyr内存使用的关系

危裕
2023-03-14

我知道数据。表与dplyr的比较是SO上一直以来的最爱。(完全公开:我喜欢并使用这两个软件包。)

然而,在试图为我教的一门课提供一些比较时,我遇到了一些令人惊讶的W.R.T.内存使用情况。我的预期是,对于需要(隐式)筛选或切片数据的操作,dplyr的性能将特别差。但我发现的不是这个。比较:

第一Dplyr。

library(bench)
library(dplyr, warn.conflicts = FALSE)
library(data.table, warn.conflicts = FALSE)
set.seed(123)

DF = tibble(x = rep(1:10, times = 1e5),
                y = sample(LETTERS[1:10], 10e5, replace = TRUE),
                z = rnorm(1e6))

DF %>% filter(x > 7) %>% group_by(y) %>% summarise(mean(z))
#> # A tibble: 10 x 2
#>    y     `mean(z)`
#>  * <chr>     <dbl>
#>  1 A     -0.00336 
#>  2 B     -0.00702 
#>  3 C      0.00291 
#>  4 D     -0.00430 
#>  5 E     -0.00705 
#>  6 F     -0.00568 
#>  7 G     -0.00344 
#>  8 H      0.000553
#>  9 I     -0.00168 
#> 10 J      0.00661

bench::bench_process_memory()
#> current     max 
#>   585MB   611MB
library(bench)
library(dplyr, warn.conflicts = FALSE)
library(data.table, warn.conflicts = FALSE)
set.seed(123)

DT = data.table(x = rep(1:10, times = 1e5),
                y = sample(LETTERS[1:10], 10e5, replace = TRUE),
                z = rnorm(1e6))

DT[x > 7, mean(z), by = y]
#>     y            V1
#>  1: F -0.0056834238
#>  2: I -0.0016755202
#>  3: J  0.0066061660
#>  4: G -0.0034436348
#>  5: B -0.0070242788
#>  6: E -0.0070462070
#>  7: H  0.0005525803
#>  8: D -0.0043024627
#>  9: A -0.0033609302
#> 10: C  0.0029146372

bench::bench_process_memory()
#>  current      max 
#> 948.47MB   1.17GB

附言。顺便说一句,比较内存使用情况会比最初看起来更复杂,因为R的标准内存分析工具(Rprofmem和Co.)都忽略了发生在R之外的操作(例如对C++堆栈的调用)。幸运的是,bench包现在提供了一个bench_process_memory()函数,该函数也跟踪R的GC堆之外的内存,这就是我在这里使用它的原因。

sessionInfo()
#> R version 3.6.3 (2020-02-29)
#> Platform: x86_64-pc-linux-gnu (64-bit)
#> Running under: Arch Linux
#> 
#> Matrix products: default
#> BLAS/LAPACK: /usr/lib/libopenblas_haswellp-r0.3.9.so
#> 
#> locale:
#>  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
#>  [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
#>  [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
#>  [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
#>  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
#> [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
#> 
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base     
#> 
#> other attached packages:
#> [1] data.table_1.12.8 dplyr_0.8.99.9002 bench_1.1.1.9000 
#> 
#> loaded via a namespace (and not attached):
#>  [1] Rcpp_1.0.4.6      knitr_1.28        magrittr_1.5      tidyselect_1.0.0 
#>  [5] R6_2.4.1          rlang_0.4.5.9000  stringr_1.4.0     highr_0.8        
#>  [9] tools_3.6.3       xfun_0.13         htmltools_0.4.0   ellipsis_0.3.0   
#> [13] yaml_2.2.1        digest_0.6.25     tibble_3.0.1      lifecycle_0.2.0  
#> [17] crayon_1.3.4      purrr_0.3.4       vctrs_0.2.99.9011 glue_1.4.0       
#> [21] evaluate_0.14     rmarkdown_2.1     stringi_1.4.6     compiler_3.6.3   
#> [25] pillar_1.4.3      generics_0.0.2    pkgconfig_2.0.3

由reprex包(v0.3.0)在2020-04-22创建

共有1个答案

商柏
2023-03-14

更新:根据@jangorecki的建议,我使用cgmemtime shell实用程序重做了分析。即使启用了多线程,data.table的数字也要接近得多,而且dplyr w.r.t现在已经超过了。高水位的RSS+缓存内存使用量。

德普莱尔

$ ./cgmemtime Rscript ~/mem-comp-dplyr.R
Child user:    0.526 s
Child sys :    0.033 s
Child wall:    0.455 s
Child high-water RSS                    :     128952 KiB
Recursive and acc. high-water RSS+CACHE :     118516 KiB

数据表

$ ./cgmemtime Rscript ~/mem-comp-dt.R
Child user:    0.510 s
Child sys :    0.056 s
Child wall:    0.464 s
Child high-water RSS                    :     129032 KiB
Recursive and acc. high-water RSS+CACHE :     118320 KiB
library(bench)
library(dplyr, warn.conflicts = FALSE)
library(data.table, warn.conflicts = FALSE)
set.seed(123)
setDTthreads(1) ## TURN OFF MULTITHREADING

DT = data.table(x = rep(1:10, times = 1e5),
                y = sample(LETTERS[1:10], 10e5, replace = TRUE),
                z = rnorm(1e6))

DT[x > 7, mean(z), by = y]
#>     y            V1
#>  1: F -0.0056834238
#>  2: I -0.0016755202
#>  3: J  0.0066061660
#>  4: G -0.0034436348
#>  5: B -0.0070242788
#>  6: E -0.0070462070
#>  7: H  0.0005525803
#>  8: D -0.0043024627
#>  9: A -0.0033609302
#> 10: C  0.0029146372

bench::bench_process_memory()
#> current     max 
#>   589MB   612MB
 类似资料:
  • 如果您以前用过 Subversion, Mercurial 会让你感觉很困惑. 这篇教程将介绍 Mercurial 工作方式最大的区别. 如果你从没接触过 Subversion, 可以直接跳过本章. 重新审视 Subversion 我们公司的程序员们决定用 Mercurial 替换掉 Subversion, 老兄, 你把我搞糊涂了. 最初, 我提出了各种愚蠢的观点来反对迁移. “我们应当把版本库放

  • 在上一篇文章中,已经了解基本编辑,了解Vim的其他一些编辑功能。 在本节中,将讨论以下主体内容 - 缓冲 交换文件 剪切,复制,删除,粘贴操作 撤消和重做操作 缓冲 缓冲区是Vim使用的临时内存。 当在编辑器中打开文件时,Vim从磁盘驱动器加载其内容。 每当编辑文件时,这些内容都存储在内存(RAM)中,实际上是从缓冲区编辑文件。 当完成编辑并保存文件,那时只将缓冲区内容传输到适当的文件。 交换 交

  • 我很难理解这个问题背后的逻辑,这是经典的动态规划问题 我知道递归是如何工作的,比如拿不拿mth硬币。但我不明白这两个州之间的关系。 例如 这个问题可能很愚蠢,但我还是想知道,这样我才能更好地理解。谢谢

  • 简单地说,我需要将一系列列中的值与一个“基线”列进行比较。当列中的值高于基线时,我需要使用基线值。当列中的值低于或等于基线时,我需要保留该值。下面是一个示例数据集(我的实际数据集要大得多): 我当前的代码使用mutate_at()并且运行良好: 但是当我试图更新它以反映DPLYR1.0中的跨()时,我总是得到一个错误。以下是我的尝试: 你知道我做错了什么吗?case_when()是否适用于交叉?

  • 我正在运行Flink 1.8版。 主要配置如下: 声明的堆大小是12GB,为什么在概述部分显示为7.33GB。 根据文档,堆大小=声明的堆大小-网络缓冲区内存(默认值:声明的堆的0.1倍,但最大为1gb)。所以正确的值是JVM(堆/非堆)部分中显示的值,即11GB :我假设,由于现在使用1GB作为网络缓冲内存,因此32768段基本上是指32KiB大小的内存段的计数。这些用于在任务之间传输数据的TC