标签: tidyeval

dplyr 延迟调用中意外的整洁 eval 行为

我有一个函数,它需要一个数据框和几个变量,我希望它使用整洁的评估原则生成一组滞后变量。它的简单形式如下所示:

library(dplyr)
cor_lags <- function(df, var1, var2) {
  var1 <- enquo(var1)
  var2 <- enquo(var2)
  df %>% 
    select(!!var1, !!var2) %>% 
    mutate(lag1 = lag(!!var2, 1),
           lag2 = lag(!!var2, 2),
           lag3 = lag(!!var2, 3),
           lag4 = lag(!!var2, 4),
           lag5 = lag(!!var2, 5),
           lag6 = lag(!!var2, 6))
}
Run Code Online (Sandbox Code Playgroud)

但是,这会NA为所有滞后变量生成值。

cor_lags(dts_wide,"P26","P1")
# A tibble: 24 x 8
       P26     P1 lag1  lag2  lag3  lag4  lag5  lag6 
     <dbl>  <dbl> <chr> <chr> <chr> <chr> <chr> <chr>
 1  84332.  2258. NA    NA    NA    NA    NA    NA   
 2 …
Run Code Online (Sandbox Code Playgroud)

r dplyr tidyeval

1
推荐指数
1
解决办法
68
查看次数

Tidyeval Qua vs Enquo

我偶然发现了这种行为,并不太了解。有人可以请问一下吗?

我写了下面的函数,它给出以下错误:

> MyFilter <- function(data, filtersVector) {
    filtersVector <- quo(filtersVector)
    result <- data %>% filter(Species %in% !!filtersVector)
    result
  }

> MyFilter(iris, c("setosa", "virginica"))
Error in filter_impl(.data, quo) : 
Evaluation error: 'match' requires vector arguments.
Run Code Online (Sandbox Code Playgroud)

但是,如果我以以下方式对其进行修改,则它将按预期工作:

> MyFilter <- function(data, filtersVector) {
    otherName <- quo(filtersVector)
    result <- data %>% filter(Species %in% !!otherName)
    result
  }

> MyFilter(iris, c("setosa", "virginica"))
    Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
1            5.1         3.5          1.4         0.2    setosa
2            4.9         3.0          1.4         0.2    setosa
3            4.7         3.2          1.3         0.2 …
Run Code Online (Sandbox Code Playgroud)

r tidyverse tidyeval

1
推荐指数
1
解决办法
539
查看次数

传递字符串进行变异

我已经在SO上寻找此问题的答案,但是没有找到解决我问题的方法。

我有一个包含几列的数据框,每列至少有一个不适用。这些列的名称存储在character vector中vars_na。对于每一个,我想创建一个虚拟变量,如果缺少该观察值,则取值为0,否则取值为1。

下面有一个可重现的玩具示例以及我到目前为止使用的代码:

# creation of toy dataset
iris[1:5, 1] <- rep(NA, 5)
iris[1:10, 4] <- rep(NA, 10)
vars_na <- c("Sepal.Length", "Petal.Width")

for(var in vars_na){
  iris <- iris %>% 
    mutate(dummy = ifelse(is.na(!!var), 0, 1)) %>% 
    rename_at(c("dummy"), list(~paste0("dummyna_", var)))
# 'rename_at' is just to differentiate between the several dummies created, 
# and it works correctly
}
Run Code Online (Sandbox Code Playgroud)

问题在于,新创建的虚拟变量导致矢量充满1,因此它们没有正确考虑缺失值。确实:

head(iris)
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species dummyna_Sepal.Length dummyna_Petal.Width
1           NA         3.5          1.4          NA  setosa                    1                   1
2           NA         3.0          1.4          NA …
Run Code Online (Sandbox Code Playgroud)

r dplyr mutate tidyeval

1
推荐指数
1
解决办法
58
查看次数

重命名后如何使用整洁的 eval 引用函数内的变量?

使用 tidy 评估重命名后是否可以引用变量名称?作为示例,我想编写一个与以下代码执行相同操作但允许在函数参数中指定新变量名称的函数:

library(tidyverse)

mtcars %>% 
  rename(cylinder = cyl) %>% 
  group_by(cylinder) %>% 
  summarize(mean_mpg = mean(mpg))
Run Code Online (Sandbox Code Playgroud)

但是,我被困在行中group_by(在下面的代码中),因为既不能替代!!varname问号{{ varname }},也不能替代问号。我认为这!!varname不起作用,因为它会扩展为字符串;这{{ varname }}不起作用,因为调用该函数时不存在具有新名称的列。我也没有看到使用该语法的方法,glue因为该行中没有分配任何内容。

my_rename <- function(df, varname) {
  df %>% 
    rename("{varname}" := cyl) %>% 
    group_by(???) %>%
    summarize(mean_mpg = mean(mpg))
}
Run Code Online (Sandbox Code Playgroud)

r tidyverse tidyeval

1
推荐指数
1
解决办法
839
查看次数

对多个任意过滤条件使用 tidy eval

我想使用整洁的评估来编写多个、完全灵活的过滤条件。一个相关但不太复杂的问题已在 Stackoverflow Question 中得到解决。以下代码(改编自上述其他问题)正在运行。它将两个过滤条件应用于gapminder数据集,并返回过滤后的数据。

library(tidyverse)
library(gapminder)

my_filter <- function(df, cols, vals){    
  paste_filter <- function(x, y) quo(!!sym(x) %in% {{y}})
  fp <- pmap(list(cols, vals), paste_filter)
  filter(df, !!!fp)
}

cols <- list("country", "year")
vals = list(c("Albania", "France"), c(2002, 2007))
gapminder %>% my_filter(cols, vals) 
Run Code Online (Sandbox Code Playgroud)

问题:到目前为止,该解决方案仅限于一种类型的过滤运算符 ( %in%)。我想扩展这种方法以接受任意类型的运算符(==, %in%, >, ...)。预期的函数my_filter应该处理以下内容:

cols <- list("country", "year")
ops <- list("%in%", ">=")
vals = list(c("Albania", "France"), 2007))
gapminder %>% my_filter(cols, ops, vals)
Run Code Online (Sandbox Code Playgroud)

我脑海中浮现的用例是闪亮的应用程序。使用这样的功能,我们可以更轻松地让用户对数据集的变量设置任意过滤条件。

r shiny tidyverse tidyeval

1
推荐指数
1
解决办法
230
查看次数

使用 tidyeval 的具有非标量字符向量的 group_by

使用R 3.2.2dplyr 0.7.2我试图弄清楚如何有效地使用group_by作为字符向量提供的字段。

选择很容易我可以通过这样的字符串选择一个字段

(function(field) { 
  mpg %>% dplyr::select(field) 
})("cyl")
Run Code Online (Sandbox Code Playgroud)

通过像这样的多个字符串的多个字段

(function(...) { 
  mpg %>% dplyr::select(!!!quos(...)) 
})("cyl", "hwy")
Run Code Online (Sandbox Code Playgroud)

和多个字段,通过一个长度 > 1 的字符向量,像这样

(function(fields) {  
  mpg %>% dplyr::select(fields)  
})(c("cyl", "hwy"))
Run Code Online (Sandbox Code Playgroud)

随着group_by我真的不能找到一种方法,因为如果我设法得到一个输出它结束了由字符串我供应分组为多个字符串做到这一点。

我设法按这样的一个字符串分组

(function(field) {  
  mpg %>% group_by(!!field := .data[[field]]) %>% tally() 
})("cyl")
Run Code Online (Sandbox Code Playgroud)

这已经很丑了。

有谁知道我必须写什么,以便我可以运行

(function(field) {...})("cyl", "hwy")
Run Code Online (Sandbox Code Playgroud)

(function(field) {...})(c("cyl", "hwy"))
Run Code Online (Sandbox Code Playgroud)

分别?我试过各种组合!!!!!UQenquoquosunlist,等...,并将其保存在中间变量,因为,有时似乎有所作为,但它不能去工作。

r dplyr tidyeval rlang

0
推荐指数
1
解决办法
201
查看次数

功能问题.Tidyeval过滤

这有什么不对?这有效:

iris %>% 
  filter(Species == "setosa") %>% 
  summarise(msl = mean(Sepal.Length), msw = mean(Petal.Width))
Run Code Online (Sandbox Code Playgroud)

并生产:

    msl   msw
1 5.006 0.246
Run Code Online (Sandbox Code Playgroud)

但是这个功能不起作用:

means <- function(data, value){
  data <- enquo(data)
  value <- enquo(value)
  data %>% 
    filter(Species == !!value) %>% 
    summarise(msl = mean(Sepal.Length), msw = mean(Petal.Width))
}
Run Code Online (Sandbox Code Playgroud)

means(iris, "setosa")产生此错误:

UseMethod("filter_")中的错误:"filter_"的适用方法没有应用于类"c"(quosure','formula')的对象"来自:filter _(.data,.dots = compat_as_lazy_dots(...) ))

r function dplyr nse tidyeval

0
推荐指数
1
解决办法
153
查看次数

使用 tidyeval 编写自定义 case_when 函数以在 dplyr mutate 中使用

我正在尝试编写一个自定义 case_when 函数以在 dplyr 内部使用。我一直在阅读其他问题中发布的 tidyeval 示例,但仍然不知道如何使其工作。这是一个代表:

\n\n
df1 <- data.frame(animal_1 = c("Horse", "Pig", "Chicken", "Cow", "Sheep"),\n           animal_2 = c(NA, NA, "Horse", "Sheep", "Chicken"))\n\n\ntranslate_title <- function(data, input_col, output_col) {\n  mutate(data, \n    !!output_col := case_when(\n    input_col == "Horse" ~ "Cheval",\n    input_col == "Pig" ~ "\xd0\xa0orc",\n    input_col == "Chicken" ~ "Poulet",\n    TRUE ~ NA)\n  )\n}\n\n\ndf1 %>% \n  translate_title("animal_1", "animaux_1") %>% \n  translate_title("animal_2", "animaux_2")\n
Run Code Online (Sandbox Code Playgroud)\n\n

当我尝试运行它时,我得到\nError in mutate_impl(.data, dots) : Evaluation error: must be type string, not logical.

\n\n

另外,我实际上想重写该函数,以便可以像这样使用它:

\n\n
df1 …
Run Code Online (Sandbox Code Playgroud)

r dplyr tidyverse tidyeval

0
推荐指数
1
解决办法
582
查看次数

将 enquo 表达式传递给子函数

这个问题与将变量传递给使用 `enquo()` 的函数有关。

我有一个更高的函数,其参数为 tibble ( dat) 和 dat ( ) 中感兴趣的列variables_of_interest_in_dat。在该函数中,有一个对我想要传递给的另一个函数的调用variables_of_interest_in_dat

higher_function <- function(dat, variables_of_interest_in_dat){
    variables_of_interest_in_dat <- enquos(variables_of_interest_in_dat)

    lower_function(dat, ???variables_of_interest_in_dat???)
    }
    
lower_function <- function(dat, variables_of_interest_in_dat){
    variables_of_interest_in_dat <- enquos(variables_of_interest_in_dat)
       
    dat %>%
         select(!!!variables_of_interest_in_dat)
    }
Run Code Online (Sandbox Code Playgroud)

传递给 lower_function 的推荐方法是什么variables_of_interest_in_dat

我已经尝试过lower_function(dat, !!!variables_of_interest_in_dat),但是当我运行时higher_function(mtcars, cyl)返回“错误:无法!!!在顶层使用。”

在相关帖子中,higher_function 在将变量传递给 lower 函数之前并未对变量进行 enquo。

谢谢

r tidyeval quasiquotes

0
推荐指数
1
解决办法
130
查看次数

标签 统计

r ×9

tidyeval ×9

dplyr ×5

tidyverse ×4

function ×1

mutate ×1

nse ×1

quasiquotes ×1

rlang ×1

shiny ×1