使用 dplyr 跨多个列的元素差异
Elementwise differences across multiple columns with dplyr
我的目标是创建由差异组成的新变量,但遍历多个列。在基地,这非常简单:
iris[, 6:7] <- iris[, 1:2] - iris[, 3:4]
有没有办法在 dplyr 中实现这一点,或许使用 mutate?
以下代码从第一列和第二列中减去第三列:
iris2 <- iris %>%
mutate_at(1:2, funs(diffs = . - Petal.Length))
但是如果我想用第一个减去第三个,用第四个减去第二个怎么办?
我正在处理相当大的数据应用程序,所以为什么不假设我在 table 的 1000 列中尝试这样做——手动破解是不可取的...
这是使用 dplyr::bind_cols
和 purrr::map2
的一种方法,在大量列时似乎比 base 快得多。我对分析的了解还不够多,无法猜测原因,因为它感觉比其他选项更复杂一些。我不确定使用 mutate_
动词是否容易做到这一点,尽管有待更正。
编辑:添加了一个带有 dplyr::do
的选项,这是 "intended" 进行计算的方式,不适合 mutate
函数。 mutate
的问题在于它希望只创建一列。我认为除了使用 map 构造单个 mutate 调用之外,我无法想象它会更快,这是最好的选择。
library(tidyverse)
set.seed(4321)
df <- matrix(rnorm(1000000), ncol = 1000) %>%
as_tibble()
microbenchmark::microbenchmark(
base = df[, 1001:1500] <- df[, 1:500] - df[, 501:1000],
base2 = df %>% magrittr::inset(, 1001:1500, .[, 1:500] - .[, 501:1000]),
map = df %>% bind_cols(map2(.x = .[, 1:500], .y = .[, 501:1000], .f = ~.x - .y)),
nomap = df %>% bind_cols(.[, 1:500] - .[, 501:1000]),
do = df %>% do(.[, 1:500] - .[, 501:1000])
)
#> Unit: milliseconds
#> expr min lq mean median uq max neval
#> base 32.928171 36.394238 39.362308 37.361149 39.454822 112.76356 100
#> base2 33.302556 35.500491 38.888530 37.433863 40.207799 84.08674 100
#> map 4.693637 5.139985 5.967655 5.468398 6.264793 12.20658 100
#> nomap 23.061348 25.016053 28.598282 26.973913 29.574478 79.97451 100
#> do 21.906042 23.460822 27.049262 25.135640 26.596373 80.01928 100
#> cld
#> c
#> c
#> a
#> b
#> b
由 reprex package (v0.2.0) 创建于 2018-05-11。
我的目标是创建由差异组成的新变量,但遍历多个列。在基地,这非常简单:
iris[, 6:7] <- iris[, 1:2] - iris[, 3:4]
有没有办法在 dplyr 中实现这一点,或许使用 mutate?
以下代码从第一列和第二列中减去第三列:
iris2 <- iris %>%
mutate_at(1:2, funs(diffs = . - Petal.Length))
但是如果我想用第一个减去第三个,用第四个减去第二个怎么办?
我正在处理相当大的数据应用程序,所以为什么不假设我在 table 的 1000 列中尝试这样做——手动破解是不可取的...
这是使用 dplyr::bind_cols
和 purrr::map2
的一种方法,在大量列时似乎比 base 快得多。我对分析的了解还不够多,无法猜测原因,因为它感觉比其他选项更复杂一些。我不确定使用 mutate_
动词是否容易做到这一点,尽管有待更正。
编辑:添加了一个带有 dplyr::do
的选项,这是 "intended" 进行计算的方式,不适合 mutate
函数。 mutate
的问题在于它希望只创建一列。我认为除了使用 map 构造单个 mutate 调用之外,我无法想象它会更快,这是最好的选择。
library(tidyverse)
set.seed(4321)
df <- matrix(rnorm(1000000), ncol = 1000) %>%
as_tibble()
microbenchmark::microbenchmark(
base = df[, 1001:1500] <- df[, 1:500] - df[, 501:1000],
base2 = df %>% magrittr::inset(, 1001:1500, .[, 1:500] - .[, 501:1000]),
map = df %>% bind_cols(map2(.x = .[, 1:500], .y = .[, 501:1000], .f = ~.x - .y)),
nomap = df %>% bind_cols(.[, 1:500] - .[, 501:1000]),
do = df %>% do(.[, 1:500] - .[, 501:1000])
)
#> Unit: milliseconds
#> expr min lq mean median uq max neval
#> base 32.928171 36.394238 39.362308 37.361149 39.454822 112.76356 100
#> base2 33.302556 35.500491 38.888530 37.433863 40.207799 84.08674 100
#> map 4.693637 5.139985 5.967655 5.468398 6.264793 12.20658 100
#> nomap 23.061348 25.016053 28.598282 26.973913 29.574478 79.97451 100
#> do 21.906042 23.460822 27.049262 25.135640 26.596373 80.01928 100
#> cld
#> c
#> c
#> a
#> b
#> b
由 reprex package (v0.2.0) 创建于 2018-05-11。