我想对多列执行多个操作,可以使用 dplyr::across()
来实现:
library(tidyverse)
df = tibble(x=1:5, p1=x*2, p2=x*4, p3=x*5)
r1 = df %>%
mutate(across(starts_with("p"), c(inf=~.x-1, sup=~.x+1)))
r1
#> # A tibble: 5 x 10
#> x p1 p2 p3 p1_inf p1_sup p2_inf p2_sup p3_inf p3_sup
#> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1 2 4 5 1 3 3 5 4 6
#> 2 2 4 8 10 3 5 7 9 9 11
#> 3 3 6 12 15 5 7 11 13 14 16
#> 4 4 8 16 20 7 9 15 17 19 21
#> 5 5 10 20 25 9 11 19 21 24 26
names(r1)
#> [1] "x" "p1" "p2" "p3" "p1_inf" "p1_sup" "p2_inf" "p2_sup"
#> [9] "p3_inf" "p3_sup"
然而,如果函数计算很多东西,这种方法并不是非常可扩展的,因为它会被评估两次。
相反,如果我能够使用一个计算需要计算的事物的函数,并返回2个(或更多)结果的列表,那就太好了。
例如,考虑以下示例:
#perform heavy calculation on x2 and return 2 flavours of it
f = function(x) {
x2=x #wow, such heavy, very calculate
Sys.sleep(1)
data.frame(inf=x2-10, sup=x2+10)
}
r2 = df %>%
mutate(across(starts_with("p"), f, .names="{.col}_{.fn}"))
r2
#> # A tibble: 5 x 7
#> x p1 p2 p3 p1_1$inf $sup p2_1$inf $sup p3_1$inf $sup
#> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1 2 4 5 -8 12 -6 14 -5 15
#> 2 2 4 8 10 -6 14 -2 18 0 20
#> 3 3 6 12 15 -4 16 2 22 5 25
#> 4 4 8 16 20 -2 18 6 26 10 30
#> 5 5 10 20 25 0 20 10 30 15 35
names(r2)
#> [1] "x" "p1" "p2" "p3" "p1_1" "p2_1" "p3_1"
map_chr(r2, class)
#> x p1 p2 p3 p1_1 p2_1
#> "integer" "numeric" "numeric" "numeric" "data.frame" "data.frame"
#> p3_1
#> "data.frame"
此文档由reprex包(v2.0.1)于2021-10-25创建。
使用rbind()
代替data.frame()
将得到相同的结果,只是变量名略有不同(p1_1$inf
变成了p1_1[,"inf"]
),并且返回的对象类型也不同(data.frame
变成了c("matrix", "array")
)。
此外,在使用单个函数时,{.fn}
是函数的位置,因此可能存在命名问题。
我也尝试过使用unnest()
,但没有成功。
是否有一种方法可以使用across()
中的函数得到第一个输出的确切结果?
x2
存储到一个新的列/数据框中,然后使用mutate
将下一步(inf
/sup
)应用在其中?如果你正在使用一个新的数据框,请将其与原始数据框联接起来。 - Martin Gal