为什么使用list()对.dots = setNames()在dplyr中使用是否重要?

时间:2016-03-17 17:20:23

标签: r dplyr

我使用动态变量名称调用mutate。一个主要有效的例子是:

df <- data.frame(a = 1:5, b = 1:5)
func <- function(a,b){
  return(a+b)
}
var1 = 'a'
var2 = 'b'
expr <- interp(~func(x, y), x = as.name(var1), y = as.name(var2))
new_name <- "dynamically_created_name"
temp <- df %>% mutate_(.dots = setNames(expr, nm = new_name))

哪个产生

temp
  a b func(a, b)
1 1 1          2
2 2 2          4
3 3 3          6
4 4 4          8
5 5 5         10

除了集合名称忽略了nm键之外,这很好。这可以通过将我的函数包装在list()中来解决:

temp <- df %>% mutate_(.dots = setNames(list(expr), nm = new_name))
temp
  a b dynamically_created_name
1 1 1                        2
2 2 2                        4
3 3 3                        6
4 4 4                        8
5 5 5                       10

我的问题是为什么setNames首先忽略它的关键,list()如何解决这个问题?

2 个答案:

答案 0 :(得分:10)

other answer所述,假设.dots参数是一个列表,而setNames是重命名列表中元素的便捷方式。

什么是.dots参数在做什么?让我们首先考虑实际的点...参数。这是一系列要评估的表达式。点...下面是两个命名的表达式c = ~ a * scale1d = ~ a * scale2

scale1 <- -1
scale2 <- -2

df %>% 
  mutate_(c = ~ a * scale1, d = ~ a * scale2)
#>   a b  c   d
#> 1 1 1 -1  -2
#> 2 2 2 -2  -4
#> 3 3 3 -3  -6
#> 4 4 4 -4  -8
#> 5 5 5 -5 -10

我们可以事先将这些表达式捆绑在一个列表中。这就是.dots的用武之地。该参数让我们告诉mutate_评估列表中的表达式。

bundled <- list(
  c2 = ~ a * scale1, 
  d2 = ~ a * scale2
)

df %>% 
  mutate_(.dots = bundled)
#>   a b c2  d2
#> 1 1 1 -1  -2
#> 2 2 2 -2  -4
#> 3 3 3 -3  -6
#> 4 4 4 -4  -8
#> 5 5 5 -5 -10

如果我们想以编程方式更新列表中表达式的名称,那么setNames是一种方便的方法。如果我们想在编写表达式时以编程方式混合和匹配常量和变量名,那么lazyeval包提供了方便的方法。下面我将同时创建一个表达式列表,命名它们,并使用mutate_

对它们进行评估
# Imagine some dropdown boxes in a Shiny app, and this is what user requested
selected_func1 <- "min"
selected_func2 <- "max"
selected_var1 <- "a"
selected_var2 <- "b"

# Assemble expressions from those choices
bundled2 <- list(
  interp(~fun(x), fun = as.name(selected_func1), x = as.name(selected_var1)),
  interp(~fun(x), fun = as.name(selected_func2), x = as.name(selected_var2))
)
bundled2
#> [[1]]
#> ~min(a)
#> 
#> [[2]]
#> ~max(b)

# Create variable names
exp_name1 <- paste0(selected_func1, "_", selected_var1)
exp_name2 <- paste0(selected_func2, "_", selected_var2)

bundled2 <- setNames(bundled2, c(exp_name1, exp_name2))
bundled2
#> $min_a
#> ~min(a)
#> 
#> $max_b
#> ~max(b)

# Evaluate the expressions
df %>% 
  mutate_(.dots = bundled2)
#>   a b min_a max_b
#> 1 1 1     1     5
#> 2 2 2     1     5
#> 3 3 3     1     5
#> 4 4 4     1     5
#> 5 5 5     1     5

答案 1 :(得分:2)

来自vignettes("nse")

  

如果您还想输出要变化的变量,则需要将引用对象列表传递给.dots参数

所以也许是

的原因
temp <- df %>% mutate_(.dots = setNames(expr, nm = new_name))

如果您在此处成功设置了name属性,那么expr仍然是公式,而不是列表:

foo <- setNames(expr, nm = new_name)
names(foo) #"dynamically_created_name" "" 
class(foo) #"formula"

因此,如果您将其列为一个列表,它将按预期工作:

expr <- interp(~func(x, y), x = as.name(var1),
               y = as.name(var2))
df %>% mutate_(.dots = list(new_name = expr))
  a b new_name
1 1 1        2
2 2 2        4
3 3 3        6
4 4 4        8
5 5 5       10