利用dplyr中Cross()中的函数处理成对列

利用dplyr中Cross()中的函数处理成对列,r,function,dplyr,across,R,Function,Dplyr,Across,假设我有这样的数据。我希望为每个广告运行一个函数,与带下划线的数字配对,即AD1fun、AD2fun、AD3fun 而不是写作 set.seed(3) library(dplyr) x <- tibble(Measure = c("Height","Weight","Width","Length"), AD1_1= rpois(4,10), AD1_2= rpois(4,9),

假设我有这样的数据。我希望为每个广告运行一个函数,与带下划线的数字配对,即AD1fun、AD2fun、AD3fun

而不是写作

set.seed(3)
library(dplyr)
x <- tibble(Measure = c("Height","Weight","Width","Length"),
        AD1_1= rpois(4,10),
        AD1_2= rpois(4,9),
        AD2_1= rpois(4,10),
        AD2_2= rpois(4,9),
        AD3_1= rpois(4,10),
        AD3_2= rpois(4,9))
表明

fun <- function(x,y){x-y}
dat %>%
mutate(AD1fun = fun(AD1_1,AD1_2),
       AD2fun = fun(AD2_1,AD2_2),
...)
可用于生产

x_minus <- x %>%
  mutate(fun(across(ends_with("_1"), .names = "{col}_minus"), across(ends_with("_2")))) %>%
  rename_with(~ sub("_\\d+", "", .), ends_with("_minus"))
但是,如果我们要进行非操作功能

# A tibble: 4 x 10
  Measure AD1_1 AD1_2 AD2_1 AD2_2 AD3_1 AD3_2 AD1_minus AD2_minus AD3_minus
  <chr>   <int> <int> <int> <int> <int> <int>     <int>     <int>     <int>
1 Height      6    10    10     3    12     8        -4         7         4
2 Weight      8     9    13     6    14     7        -1         7         7
3 Width      10     9    11     5    12     8         1         6         4
4 Length      8     9     8     7     8    13        -1         1        -5
它将产生一个错误,因为引用

这个过程本质上意味着比较两个数据集:一个 变量以_1结尾,一个以_2结尾。因此,情况是一样的 作为dat%>%selectends\u与_1-dat%>%selectends\u与_2。 因为这些都是列表,你不能用这种方式比较它们

如果是这样的话,我们可以做些什么来包含一个使用cross的函数?

我们可以在名称以_1结尾的列之间循环,然后使用cur_column来提取列名,将后缀部分替换为_2,获取值并将其用作当前列和来自_2的对应对的fun的参数

-输出

library(dplyr)
library(stringr)
x %>% 
   mutate(across(ends_with("_1"), ~
     fun(., get(str_replace(cur_column(), "_1$", "_2"))), .names = "{.col}_case"))
library(purrr)
x %>% 
  select(-Measure) %>% 
  split.default(str_remove(names(.), "_\\d+$")) %>%
  map_dfr(reduce, fun) %>% 
  rename_all(~ str_c(., "_case")) %>%
  bind_cols(x, .)
-输出

library(dplyr)
library(stringr)
x %>% 
   mutate(across(ends_with("_1"), ~
     fun(., get(str_replace(cur_column(), "_1$", "_2"))), .names = "{.col}_case"))
library(purrr)
x %>% 
  select(-Measure) %>% 
  split.default(str_remove(names(.), "_\\d+$")) %>%
  map_dfr(reduce, fun) %>% 
  rename_all(~ str_c(., "_case")) %>%
  bind_cols(x, .)

感谢您对三种不同方法的清晰解释。在第三种矢量化方法中,do.calldata.frame的用途是什么。提供我看到这样做会导致维度变得有点不确定,但我不明白为什么它会这样做。@aiorr从fun矢量化的输出是一个单列矩阵。因此,do.call data.frame用于确保列都是数据集中的常规列。i、 它将矩阵列展平为3列
# A tibble: 4 x 10
#  Measure AD1_1 AD1_2 AD2_1 AD2_2 AD3_1 AD3_2 AD1_case AD2_case AD3_case
#  <chr>   <int> <int> <int> <int> <int> <int> <chr>    <chr>    <chr>   
#1 Height      6    10    10     3    12     8 Disagree Disagree Disagree
#2 Weight      8     9    13     6    14     7 Agree    Disagree Disagree
#3 Width      10     9    11     5    12     8 Agree    Disagree Disagree
#4 Length      8     9     8     7     8    13 Agree    Agree    Disagree
x %>%
  mutate(Vectorize(fun)(across(ends_with("_1"), 
         .names = "{col}_minus"), across(ends_with("_2"))))%>%
   do.call(data.frame, .) %>% 
   rename_at(vars(contains('minus')),
         ~ str_extract(., 'AD\\d+_\\d+_minus'))
#  Measure AD1_1 AD1_2 AD2_1 AD2_2 AD3_1 AD3_2 AD1_1_minus AD2_1_minus AD3_1_minus
#1  Height     6    10    10     3    12     8    Disagree    Disagree    Disagree
#2  Weight     8     9    13     6    14     7       Agree    Disagree    Disagree
#3   Width    10     9    11     5    12     8       Agree    Disagree    Disagree
#4  Length     8     9     8     7     8    13       Agree       Agree    Disagree