我今天必须写一个这样的函数
data1 %>%
summarise(
ab1 = fn(a1, b1),
ab2 = fn(a2, b2),
ab3 = fn(a3, b3)
)
# imagine if there are 100 of them
如果
fn
是一个单参数函数我可以做到
data1 %>%
summarise(across(starts_with("a", fn)))
但不幸的是,我的函数需要两列作为输入。有没有一种方法可以做到这一点,而无需为每组参数编写新行?
您可以使用
map2*
函数来传递两组列。
library(dplyr)
library(purrr)
data1 %>%
summarise(map2_df(pick(starts_with("a")), pick(starts_with("b")), fn))
# a1 a2 a3
#1 21 57 93
使用来自@ThomasIsCoding的数据,但使用不同的函数,因为您的代码使用
summarise
,这意味着它将在末尾有一行。
fn <- function(a, b) {
sum(a, b)
}
另一种使用重塑数据的方法。如果你能克服从更长的形式来回重塑的障碍,计算就会变得微不足道。
这种方法的一个好处是它对列顺序具有鲁棒性,并且您不需要预先指定列前缀,前提是您可以使用正则表达式指定一些常规模式。
library(tidyverse)
data1 |>
# reshape long, in this case assuming the columns are all (letters)(numbers).
mutate(row = row_number()) |>
pivot_longer(cols = -row,
names_to = c(".value", "Pair"),
names_pattern = "(\\D+)(\\d+)") |>
# do the calculation with the two or more involved columns
mutate(ab = a*b, .by = c(row, Pair)) |>
# reshape wider again
pivot_wider(names_from = Pair, names_glue = "{.value}{Pair}", names_vary = "slowest",
values_from = a:ab)
使用来自 @ThomasIsCoding 的数据进行输出:
row a1 b1 ab1 a2 b2 ab2 a3 b3 ab3
<int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1 1 4 4 7 10 70 13 16 208
2 2 2 5 10 8 11 88 14 17 238
3 3 3 6 18 9 12 108 15 18 270
也许您可以尝试
split.default
按名称将列分成组,例如,
data1 %>%
split.default(sub("\\D+", "ab", names(.))) %>%
map_dfr(\(...) do.call(fn, unname(...)))
这给出了
# A tibble: 3 × 3
ab1 ab2 ab3
<dbl> <dbl> <dbl>
1 4 70 208
2 10 88 238
3 18 108 270
data1 <- data.frame(
a1 = c(1, 2, 3),
b1 = c(4, 5, 6),
a2 = c(7, 8, 9),
b2 = c(10, 11, 12),
a3 = c(13, 14, 15),
b3 = c(16, 17, 18)
)
fn <- function(a, b) {
a * b
}