map_dbl returns 一个数值矩阵
map_dbl returns a numeric matrix
这是我遇到的示例代码。
我定义了一个函数。输入一个数字x
,输出一个向量vec
fct <- function(x){
vec = vector("numeric",3)
vec = c(1, x, x^2)
return(vec)
}
我有一个序列 a = 1:10
,然后我想在 a
上应用 fct
。理想情况下,它应该 return 一个数字矩阵。我知道使用 sapply(a,fct)
可以达到目的。但我很好奇如何使用 map_*
.
我试过了map(a,fct)
。它 return 是一个列表。
我试过了map_dbl(a,fct)
。它 return 出错了
Error: Result 1 must be a single double, not a double vector of length 3
Run `rlang::last_error()` to see where the error occurred.
那么 map_*
如何做到这一点?
之所以 sapply
return 是一个矩阵,是因为它有一个参数 simplify
,默认情况下是 TRUE
。 simplify
参数试图将结果简化为 vector/matrix。如果将参数更改为 FALSE
,您将获得与 lapply
或 map
.
相同的输出
sapply(a,fct, simplify = FALSE)
#[[1]]
#[1] 1 1 1
#[[2]]
#[1] 1 2 4
#[[3]]
#[1] 1 3 9
#[[4]]
#[1] 1 4 16
#...
#...
map
将始终 return 一个列表,而 map_dbl
期望从函数中 return 编辑一个数字,在您的情况下,函数 returns 3 个数字。因此,一种选择是根据 map
.
的输出构造一个矩阵
library(purrr)
map(a, fct) %>%
flatten_dbl() %>%
matrix(ncol = length(a))
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
#[1,] 1 1 1 1 1 1 1 1 1 1
#[2,] 1 2 3 4 5 6 7 8 9 10
#[3,] 1 4 9 16 25 36 49 64 81 100
map_*
函数不容易做到这一点。我建议使用最有效的工具并进入已知 format/structure.
如果您使用 map_dbl
的动机是类型安全(purrr::map*
函数的优势),那么您可以使用基本 R:
实现相同的安全性
vapply(a, fct, numeric(3))
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
# [1,] 1 1 1 1 1 1 1 1 1 1
# [2,] 1 2 3 4 5 6 7 8 9 10
# [3,] 1 4 9 16 25 36 49 64 81 100
诚然,vapply
要求您事先知道 class 和 return 值的长度,但如果这不是问题,那么您就很好。此外,它通常非常快:
a <- 1:10
bench::mark(vapply(a, fct, numeric(3)), lapply(a, fct), sapply(a, fct), map(a, fct), check = FALSE)
# # A tibble: 4 x 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 vapply(a, fct, numeric(3)) 12.3us 18.1us 44793. 288B 0 10000 0 223ms <NULL> <Rprofmem[,3] [1 x 3]> <bch:tm [10,000]> <tibble [10,000 x 3]>
# 2 lapply(a, fct) 11.6us 16.2us 52398. 0B 5.24 9999 1 191ms <NULL> <Rprofmem[,3] [0 x 3]> <bch:tm [10,000]> <tibble [10,000 x 3]>
# 3 sapply(a, fct) 24.8us 36us 22943. 576B 2.29 9999 1 436ms <NULL> <Rprofmem[,3] [2 x 3]> <bch:tm [10,000]> <tibble [10,000 x 3]>
# 4 map(a, fct) 24.2us 32.4us 24356. 0B 2.44 9999 1 411ms <NULL> <Rprofmem[,3] [0 x 3]> <bch:tm [10,000]> <tibble [10,000 x 3]>
(请注意,随着 a
的长度增加,性能差异几乎消失。)
但是回到 map*
,你 可以 使用 purrr
只有一个小的外部函数,
invoke(cbind, map(a, fct))
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
# [1,] 1 1 1 1 1 1 1 1 1 1
# [2,] 1 2 3 4 5 6 7 8 9 10
# [3,] 1 4 9 16 25 36 49 64 81 100
它的性能虽然较慢,但并没有慢很多,而且数据越大,差异就越小。
a <- 1:10
bench::mark(vapply(a, fct, numeric(3)), sapply(a, fct), do.call(cbind, lapply(a, fct)), do.call(cbind, map(a, fct)), invoke(cbind, map(a, fct)), matrix(flatten_dbl(map(a, fct)), ncol = length(a)))
# # A tibble: 6 x 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 vapply(a, fct, numeric(3)) 12.3us 17us 51210. 288B 5.12 9999 1 195ms <dbl[,10] [3 x 10~ <Rprofmem[,3] [1 x~ <bch:tm [10,00~ <tibble [10,000 x~
# 2 sapply(a, fct) 25.2us 36.4us 22276. 576B 2.23 9999 1 449ms <dbl[,10] [3 x 10~ <Rprofmem[,3] [2 x~ <bch:tm [10,00~ <tibble [10,000 x~
# 3 do.call(cbind, lapply(a, fct)) 16.2us 22.7us 37430. 288B 3.74 9999 1 267ms <dbl[,10] [3 x 10~ <Rprofmem[,3] [1 x~ <bch:tm [10,00~ <tibble [10,000 x~
# 4 do.call(cbind, map(a, fct)) 31.8us 43.6us 19856. 288B 4.40 9026 2 455ms <dbl[,10] [3 x 10~ <Rprofmem[,3] [1 x~ <bch:tm [9,028~ <tibble [9,028 x ~
# 5 invoke(cbind, map(a, fct)) 35.8us 49.6us 17440. 288B 2.07 8408 1 482ms <dbl[,10] [3 x 10~ <Rprofmem[,3] [1 x~ <bch:tm [8,409~ <tibble [8,409 x ~
# 6 matrix(flatten_dbl(map(a, fct)), ncol = length(a)) 29.6us 45.2us 19309. 864B 2.08 9292 1 481ms <dbl[,10] [3 x 10~ <Rprofmem[,3] [3 x~ <bch:tm [9,293~ <tibble [9,293 x ~
a <- 1:1000
bench::mark(vapply(a, fct, numeric(3)), sapply(a, fct), do.call(cbind, lapply(a, fct)), do.call(cbind, map(a, fct)), invoke(cbind, map(a, fct)), matrix(flatten_dbl(map(a, fct)), ncol = length(a)))
# # A tibble: 6 x 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 vapply(a, fct, numeric(3)) 1.05ms 1.35ms 714. 23.5KB 4.33 330 2 461.9ms <dbl[,1000] [3 x 1,00~ <Rprofmem[,3] [1 x ~ <bch:tm [33~ <tibble [332 x ~
# 2 sapply(a, fct) 1.13ms 1.41ms 655. 70.8KB 4.31 304 2 464ms <dbl[,1000] [3 x 1,00~ <Rprofmem[,3] [6 x ~ <bch:tm [30~ <tibble [306 x ~
# 3 do.call(cbind, lapply(a, fct)) 1.4ms 1.7ms 543. 31.3KB 4.33 251 2 462.1ms <dbl[,1000] [3 x 1,00~ <Rprofmem[,3] [2 x ~ <bch:tm [25~ <tibble [253 x ~
# 4 do.call(cbind, map(a, fct)) 1.66ms 1.78ms 479. 31.3KB 10.2 47 1 98.1ms <dbl[,1000] [3 x 1,00~ <Rprofmem[,3] [2 x ~ <bch:tm [48~ <tibble [48 x 3~
# 5 invoke(cbind, map(a, fct)) 1.3ms 1.73ms 546. 39.2KB 4.30 254 2 464.8ms <dbl[,1000] [3 x 1,00~ <Rprofmem[,3] [3 x ~ <bch:tm [25~ <tibble [256 x ~
# 6 matrix(flatten_dbl(map(a, fct)), ncol = length(a)) 1.13ms 1.49ms 551. 78.3KB 2.07 266 1 482.8ms <dbl[,1000] [3 x 1,00~ <Rprofmem[,3] [4 x ~ <bch:tm [26~ <tibble [267 x ~
(六个命令的输出完全相同。)
这是我遇到的示例代码。
我定义了一个函数。输入一个数字x
,输出一个向量vec
fct <- function(x){
vec = vector("numeric",3)
vec = c(1, x, x^2)
return(vec)
}
我有一个序列 a = 1:10
,然后我想在 a
上应用 fct
。理想情况下,它应该 return 一个数字矩阵。我知道使用 sapply(a,fct)
可以达到目的。但我很好奇如何使用 map_*
.
我试过了map(a,fct)
。它 return 是一个列表。
我试过了map_dbl(a,fct)
。它 return 出错了
Error: Result 1 must be a single double, not a double vector of length 3
Run `rlang::last_error()` to see where the error occurred.
那么 map_*
如何做到这一点?
之所以 sapply
return 是一个矩阵,是因为它有一个参数 simplify
,默认情况下是 TRUE
。 simplify
参数试图将结果简化为 vector/matrix。如果将参数更改为 FALSE
,您将获得与 lapply
或 map
.
sapply(a,fct, simplify = FALSE)
#[[1]]
#[1] 1 1 1
#[[2]]
#[1] 1 2 4
#[[3]]
#[1] 1 3 9
#[[4]]
#[1] 1 4 16
#...
#...
map
将始终 return 一个列表,而 map_dbl
期望从函数中 return 编辑一个数字,在您的情况下,函数 returns 3 个数字。因此,一种选择是根据 map
.
library(purrr)
map(a, fct) %>%
flatten_dbl() %>%
matrix(ncol = length(a))
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
#[1,] 1 1 1 1 1 1 1 1 1 1
#[2,] 1 2 3 4 5 6 7 8 9 10
#[3,] 1 4 9 16 25 36 49 64 81 100
map_*
函数不容易做到这一点。我建议使用最有效的工具并进入已知 format/structure.
如果您使用 map_dbl
的动机是类型安全(purrr::map*
函数的优势),那么您可以使用基本 R:
vapply(a, fct, numeric(3))
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
# [1,] 1 1 1 1 1 1 1 1 1 1
# [2,] 1 2 3 4 5 6 7 8 9 10
# [3,] 1 4 9 16 25 36 49 64 81 100
诚然,vapply
要求您事先知道 class 和 return 值的长度,但如果这不是问题,那么您就很好。此外,它通常非常快:
a <- 1:10
bench::mark(vapply(a, fct, numeric(3)), lapply(a, fct), sapply(a, fct), map(a, fct), check = FALSE)
# # A tibble: 4 x 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 vapply(a, fct, numeric(3)) 12.3us 18.1us 44793. 288B 0 10000 0 223ms <NULL> <Rprofmem[,3] [1 x 3]> <bch:tm [10,000]> <tibble [10,000 x 3]>
# 2 lapply(a, fct) 11.6us 16.2us 52398. 0B 5.24 9999 1 191ms <NULL> <Rprofmem[,3] [0 x 3]> <bch:tm [10,000]> <tibble [10,000 x 3]>
# 3 sapply(a, fct) 24.8us 36us 22943. 576B 2.29 9999 1 436ms <NULL> <Rprofmem[,3] [2 x 3]> <bch:tm [10,000]> <tibble [10,000 x 3]>
# 4 map(a, fct) 24.2us 32.4us 24356. 0B 2.44 9999 1 411ms <NULL> <Rprofmem[,3] [0 x 3]> <bch:tm [10,000]> <tibble [10,000 x 3]>
(请注意,随着 a
的长度增加,性能差异几乎消失。)
但是回到 map*
,你 可以 使用 purrr
只有一个小的外部函数,
invoke(cbind, map(a, fct))
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
# [1,] 1 1 1 1 1 1 1 1 1 1
# [2,] 1 2 3 4 5 6 7 8 9 10
# [3,] 1 4 9 16 25 36 49 64 81 100
它的性能虽然较慢,但并没有慢很多,而且数据越大,差异就越小。
a <- 1:10
bench::mark(vapply(a, fct, numeric(3)), sapply(a, fct), do.call(cbind, lapply(a, fct)), do.call(cbind, map(a, fct)), invoke(cbind, map(a, fct)), matrix(flatten_dbl(map(a, fct)), ncol = length(a)))
# # A tibble: 6 x 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 vapply(a, fct, numeric(3)) 12.3us 17us 51210. 288B 5.12 9999 1 195ms <dbl[,10] [3 x 10~ <Rprofmem[,3] [1 x~ <bch:tm [10,00~ <tibble [10,000 x~
# 2 sapply(a, fct) 25.2us 36.4us 22276. 576B 2.23 9999 1 449ms <dbl[,10] [3 x 10~ <Rprofmem[,3] [2 x~ <bch:tm [10,00~ <tibble [10,000 x~
# 3 do.call(cbind, lapply(a, fct)) 16.2us 22.7us 37430. 288B 3.74 9999 1 267ms <dbl[,10] [3 x 10~ <Rprofmem[,3] [1 x~ <bch:tm [10,00~ <tibble [10,000 x~
# 4 do.call(cbind, map(a, fct)) 31.8us 43.6us 19856. 288B 4.40 9026 2 455ms <dbl[,10] [3 x 10~ <Rprofmem[,3] [1 x~ <bch:tm [9,028~ <tibble [9,028 x ~
# 5 invoke(cbind, map(a, fct)) 35.8us 49.6us 17440. 288B 2.07 8408 1 482ms <dbl[,10] [3 x 10~ <Rprofmem[,3] [1 x~ <bch:tm [8,409~ <tibble [8,409 x ~
# 6 matrix(flatten_dbl(map(a, fct)), ncol = length(a)) 29.6us 45.2us 19309. 864B 2.08 9292 1 481ms <dbl[,10] [3 x 10~ <Rprofmem[,3] [3 x~ <bch:tm [9,293~ <tibble [9,293 x ~
a <- 1:1000
bench::mark(vapply(a, fct, numeric(3)), sapply(a, fct), do.call(cbind, lapply(a, fct)), do.call(cbind, map(a, fct)), invoke(cbind, map(a, fct)), matrix(flatten_dbl(map(a, fct)), ncol = length(a)))
# # A tibble: 6 x 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 vapply(a, fct, numeric(3)) 1.05ms 1.35ms 714. 23.5KB 4.33 330 2 461.9ms <dbl[,1000] [3 x 1,00~ <Rprofmem[,3] [1 x ~ <bch:tm [33~ <tibble [332 x ~
# 2 sapply(a, fct) 1.13ms 1.41ms 655. 70.8KB 4.31 304 2 464ms <dbl[,1000] [3 x 1,00~ <Rprofmem[,3] [6 x ~ <bch:tm [30~ <tibble [306 x ~
# 3 do.call(cbind, lapply(a, fct)) 1.4ms 1.7ms 543. 31.3KB 4.33 251 2 462.1ms <dbl[,1000] [3 x 1,00~ <Rprofmem[,3] [2 x ~ <bch:tm [25~ <tibble [253 x ~
# 4 do.call(cbind, map(a, fct)) 1.66ms 1.78ms 479. 31.3KB 10.2 47 1 98.1ms <dbl[,1000] [3 x 1,00~ <Rprofmem[,3] [2 x ~ <bch:tm [48~ <tibble [48 x 3~
# 5 invoke(cbind, map(a, fct)) 1.3ms 1.73ms 546. 39.2KB 4.30 254 2 464.8ms <dbl[,1000] [3 x 1,00~ <Rprofmem[,3] [3 x ~ <bch:tm [25~ <tibble [256 x ~
# 6 matrix(flatten_dbl(map(a, fct)), ncol = length(a)) 1.13ms 1.49ms 551. 78.3KB 2.07 266 1 482.8ms <dbl[,1000] [3 x 1,00~ <Rprofmem[,3] [4 x ~ <bch:tm [26~ <tibble [267 x ~
(六个命令的输出完全相同。)