R函数:使用参数作为字符变量和列名

R function: using argument as a character variable and column name

我有一些这种格式的数据:

#> # A tibble: 3 × 5
#>    item  cost  blue  pink black
#>   <int> <int> <int> <int> <int>
#> 1     1     4     1     0     1
#> 2     2    10     1     0     1
#> 3     3     3     0     1     1

我想要的输出是颜色列的相对频率。项目可以有不止一种颜色,因此相对频率总和不必为 1。

#>    color  rel_freq  
#>   <int> <int> 
#> 1  blue  0.66  
#> 2  pink  0.33  
#> 2  black 1.00  

我可以为一种颜色手动完成,比如蓝色:

library(tidyverse)
df <- tibble::tribble(
  ~item, ~cost, ~blue, ~pink, ~black,
     1L,    4L,    1L,    0L,     1L,
     2L,   10L,    1L,    0L,     1L,
     3L,    3L,    0L,    1L,     1L
  )

df %>% 
  group_by(blue) %>% 
  summarise(count = n()) %>% 
  mutate(rel_freq = (count/sum(count)*100) ) %>%
  filter(blue==1) %>% 
  mutate(color = deparse(substitute(blue))) %>% 
  select(-blue, -count) %>% 
  select(color, everything())
  

这给出了

#>   color rel_freq
#>   <chr>    <dbl>
#> 1 blue      66.7

但是当我把它放入一个函数中时,我不知道如何传入一个参数,以便它可以被视为一个列(使用“curly-curly”表示法)和一个字符变量(这就是我所坚持的)。

calc_rel_freq <- function(input_color){
df %>% 
  group_by({{input_color}}) %>% 
  summarise(count = n()) %>% 
  mutate(rel_freq = (count/sum(count)*100) ) %>%
  filter({{input_color}}==1) %>% 
  mutate(color = deparse(substitute({{input_color}}))) %>% # This is where I'm stuck.
  select(-{{input_color}}, -count) %>% 
  select(color, everything())
}
calc_rel_freq(blue)

我的最终目标是能够使用这样的函数:

input_colors <- c("blue", "pink", "black")
map(input_colors, calc_relative_freq)

数据输入代码如下:

library(tidyverse)
df <- tibble::tribble(
  ~item, ~cost, ~blue, ~pink, ~black,
     1L,    4L,    1L,    0L,     1L,
     2L,   10L,    1L,    0L,     1L,
     3L,    3L,    0L,    1L,     1L
  )

df

由于您想要的输出是相对频率,您可以更直接地使用

df %>% 
  select(-cost) %>% 
  pivot_longer(blue:black) %>% 
  group_by(name) %>% 
  summarize(rel_freq=mean(value))
#   name  rel_freq
#   <chr>    <dbl>
# 1 black    1    
# 2 blue     0.667
# 3 pink     0.333

如果你真的只想要一个,你可以在最后 filter()

我们可以将 dplyr 与 across 一起使用。对于所有答案,如果需要,我们可以轻松 pivot_longer 输出。

library(dplyr)
df %>% summarise(across(blue:black, mean))

# A tibble: 1 × 3
   blue  pink black
  <dbl> <dbl> <dbl>
1 0.667 0.333     1

all_of

across 也可以通过 all_of 选择助手处理所选列的名称向量:

library(dplyr)

input_colors <- c("blue", "pink", "black")

df %>% summarise(across(all_of(input_colors), mean))

sym和双刘海(!!)

如果我们真的想使用非标准评估将字符元素用作dplyr函数内的列选择,我们可以转换为符号(sym)并评估(!!),用rlang 包:

library(dplyr)
library(purrr)
library(rlang)

map_dfc(input_colors, ~df %>% summarise(across(!!(sym(.x)), mean)))

# A tibble: 1 × 3
   blue  pink black
  <dbl> <dbl> <dbl>
1 0.667 0.333     1

作为替代方案,我们可以先创建一个符号列表

my_symbols<-input_colors %>% map(sym)

然后使用循环 across:

map_dfc(my_symbols, ~ df %>% summarise(across(.x, mean)))

在用户自定义函数中使用双大括号({{}})

尽管有警告消息,但它工作得很好:

calc_rel_freq<-function(df, variable){
    df %>% summarise(across({{variable}}, mean))
}

rel_freq(df, input_colors)

Note: Using an external vector in selections is ambiguous.
ℹ Use `all_of(input_colors)` instead of `input_colors` to silence this message.
ℹ See <https://tidyselect.r-lib.org/reference/faq-external-vector.html>.
This message is displayed once per session.

# A tibble: 1 × 3
   blue  pink black
  <dbl> <dbl> <dbl>
1 0.667 0.333     1