【发布时间】:2020-12-04 00:26:36
【问题描述】:
例如,我有以下数据框:
df <- data.frame(a1=1,a2=2,a3=3,b1=1,b2=2,b3=3)
我有一个函数:
fn <- function(x,y,z) x^y+(z-x)^(y-x)
我想要以下:
df <- df %>% mutate(a=fn(a1,a2,a3),b=fn(b1,b2,b3))
问题是,我的数据集中有大量三元组,因此将它们一一写出来并不理想。
【问题讨论】:
例如,我有以下数据框:
df <- data.frame(a1=1,a2=2,a3=3,b1=1,b2=2,b3=3)
我有一个函数:
fn <- function(x,y,z) x^y+(z-x)^(y-x)
我想要以下:
df <- df %>% mutate(a=fn(a1,a2,a3),b=fn(b1,b2,b3))
问题是,我的数据集中有大量三元组,因此将它们一一写出来并不理想。
【问题讨论】:
这里是使用的基本 R 选项:
split.default + lapply + do.call
cbind(
df,
lapply(
split.default(df, gsub("\\d+", "", names(df))),
function(x) do.call(fn, unname(x))
)
)
reshape + lapply + do.call
cbind(
df,
lapply(
subset(
reshape(
setNames(df, gsub("(\\d+)$", "\\.\\1", names(df))),
direction = "long",
varying = 1:length(df)
),
select = -c(time, id)
),
function(x) do.call(fn, as.list(x))
)
)
输出
a1 a2 a3 b1 b2 b3 a b
1 1 2 3 1 2 3 3 3
【讨论】:
我会将df 转换为长格式,然后使用lag 创建3 列,然后在它们上应用fn()
library(tidyverse)
df_long <- df %>%
pivot_longer(everything(),
names_to = c(".value", "set"),
names_pattern = "(.)(.)")
df_longer <- df_long %>%
pivot_longer(-c(set),
names_to = "key",
values_to = "val") %>%
arrange(key)
df_longer
#> # A tibble: 6 x 3
#> set key val
#> <chr> <chr> <dbl>
#> 1 1 a 1
#> 2 2 a 2
#> 3 3 a 3
#> 4 1 b 1
#> 5 2 b 2
#> 6 3 b 3
lag 然后申请fn(),只保留非NA val_fn
df_longer <- df_longer %>%
group_by(key) %>%
mutate(val_lag1 = lag(val, n = 1),
val_lag2 = lag(val, n = 2)) %>%
mutate(val_fn = fn(val_lag2, val_lag1, val)) %>%
filter(!is.na(val_fn))
df_longer
#> # A tibble: 2 x 6
#> # Groups: key [2]
#> set key val val_lag1 val_lag2 val_fn
#> <chr> <chr> <dbl> <dbl> <dbl> <dbl>
#> 1 3 a 3 2 1 3
#> 2 3 b 3 2 1 3
由reprex package (v0.3.0) 于 2020 年 12 月 3 日创建
【讨论】:
我认为将列组合成单独的组并将函数应用于每一列会更容易/更短。
library(dplyr)
library(tidyr)
df %>%
pivot_longer(cols = everything(),
names_to = '.value',
names_pattern = '([a-z]+)') %>%
summarise(across(.fns = ~do.call(fn, as.list(.)))) -> result
result
# a b
# <dbl> <dbl>
#1 3 3
如果需要,您可以将result 绑定到您的原始数据集。
bind_cols(df, result)
# a1 a2 a3 b1 b2 b3 a b
#1 1 2 3 1 2 3 3 3
【讨论】: