我很惊讶地看到,第一行的运行速度比第二行慢得多,第二行的性能与矢量化版本的性能相当。如果处理列表比处理numeric(n)
向量快得多,为什么R不自动将其输入转换为列表?
> system.time(lapply(1:10^7, sqrt))
user system elapsed
4.445 0.204 4.692
> system.time(lapply(list(1:10^7), sqrt))
user system elapsed
0.048 0.015 0.062
> system.time(sqrt(1:10^7))
user system elapsed
0.04 0.00 0.04
这是版本信息
$ R --version
R version 4.1.3 (2022-03-10) -- "One Push-Up"
Copyright (C) 2022 The R Foundation for Statistical Computing
Platform: x86_64-apple-darwin21.4.0 (64-bit)
R is free software and comes with ABSOLUTELY NO WARRANTY.
You are welcome to redistribute it under the terms of the
GNU General Public License versions 2 or 3.
For more information about these matters see
https://www.gnu.org/licenses/.
$ sw_vers
ProductName: macOS
ProductVersion: 12.3.1
BuildVersion: 21E258
原因是第二个表达式只是长度为1 的list
> length(list(1:10^7))
[1] 1
这与直接应用CCD_ 3基本相同。相反,如果我们想纯粹对list
的每个元素进行此操作,则需要as.list
而不是list
,即
> length(as.list(1:10^7))
[1] 10000000
如果意图在向量的每个元素上循环,则从vector
转换为list
是不必要的。在vector
中,每个元素都是一个单元(与matrix
相同,仅具有dim
属性(,但在data.frame/tibble/data.table中,每个单元都是一列。因此,lapply
在单元上循环,即数据帧中的列,其中作为vector
中的单个元素。当我们用list
包裹一个向量时,它将整个向量封装为单个list
元素
> list(1:3)
[[1]]
[1] 1 2 3
> as.list(1:3)
[[1]]
[1] 1
[[2]]
[1] 2
[[3]]
[1] 3
由于sqrt
是一个矢量化函数,当我们通过在第一个list
上循环来应用sqrt
时,它只循环一次,但在第二个循环中,它循环多次。
因此,我们得到了类似的定时(当然,额外的定时将是用as.list
将矢量转换为list
(
> system.time(lapply(1:10^7, sqrt))
user system elapsed
4.364 0.220 4.748
> system.time(lapply(as.list(1:10^7), sqrt))
user system elapsed
4.882 0.367 5.518
更快的选择是使用vapply
(如果我们在循环上应用非矢量化函数(
> system.time(vapply(1:10^7, sqrt, numeric(1)))
user system elapsed
2.464 0.172 2.633