Reputation: 2332
I am writing my function and want to use dplyr's filter() function to select rows of my data frame that satisfy a condition. This is my code:
library(tidyverse)
df <-data.frame(x = sample(1:100, 50), y = rnorm(50), z = sample(1:100,50), w = sample(1:100, 50),
p = sample(1:100,50))
new <- function(ang,brad,drau){
df%>%filter(!!drau %in% 1:50)%>%select(ang,brad) -> A
return(A)
}
brand <- c("z","w","p")
lapply(1:3, function(i) new(ang = "x", brad = "y", drau = brand[i]))%>%bind_rows()
Anytime I run this function, it looks like filter
doesn't select any rows that satisfy the condition.
How can I make this work?
Update
For some reason, this works when I don't use `%in%, as in;
new <- function(ang,brad,drau){
df%>%filter(!!drau > 50)%>%select(ang,brad) -> A
return(A)
}
lapply(1:3, function(i) new(ang = "x", brad = "y", drau = brand[i]))%>%bind_rows()
However, the results are the same for every loop. Why is this so? and also why can't I use %in%
.
Upvotes: 6
Views: 2042
Reputation: 11
I had a similar issue, and the simple fix that worked for me was to use the ".data" pronoun within the "filter" verb, specifically in this context:
filter(.data[[drau]] %in% 1:50)
More info here: https://tinyheero.github.io/2020/03/01/use-data-env-pronouns-tidyverse.html Also recent talks by Lionel Henry on Rstudio's youtube channel are helpful too.
library(tidyverse)
df <-data.frame(x = sample(1:100, 50), y = rnorm(50), z = sample(1:100,50), w = sample(1:100, 50),
p = sample(1:100,50))
new <- function(ang,brad,drau){
df%>%filter(.data[[drau]] %in% 1:50)%>%select(ang,brad) -> A
return(A)
}
brand <- c("z","w","p")
lapply(1:3, function(i) new(ang = "x", brad = "y", drau = brand[i]))%>%bind_rows()
Hope someone finds some use in this.
Upvotes: 1
Reputation: 2332
With UQE
now deprecated, the accepted answer for this question will not work. This answer should work. The only change here is !!sym()
library(rlang)
library(tidyverse)
df <-data.frame(x = sample(1:100, 50), y = rnorm(50), z = sample(1:100,50), w = sample(1:100, 50),
p = sample(1:100,50))
new <- function(ang,brad,drau){
df%>%filter(!!sym(drau) %in% 1:50)%>%select(!!sym(ang), !!sym(brad)) -> A
return(A)
}
brand <- c("z","w","p")
lapply(1:3, function(i) new(ang = "x", brad = "y", drau = brand[i]))%>%bind_rows()
If you want do not want to pass your function arguments as strings, use !!enquo()
instead.
new <- function(ang,brad,drau){
df%>%filter(!!enquo(drau) %in% 1:50)%>%select(!!enquo(ang), !!enquo(brad)) -> A
return(A)
}
> head(new(ang = x, brad = y, drau = z))
x y
1 44 0.47702540
2 84 -1.09670409
3 59 -0.20556334
4 81 -0.46306635
5 93 1.36845485
6 8 0.37392587
Upvotes: 1
Reputation: 3045
I agree with @hrbrmstr's standard evaluation solution. As suggested by @hadley today here's NSE solution:
library(tidyverse)
df <-data.frame(x = sample(1:100, 50),
y = rnorm(50),
z = sample(1:100,50),
w = sample(1:100, 50),
p = sample(1:100,50))
new <- function(ang, brad, drau){
ang <- enquo(ang)
brad <- enquo(brad)
drau <- enquo(drau)
df %>% filter(UQ(drau) %in% 1:50) %>%
select(UQ(ang),UQ(brad))
}
brand <- c("z","w","p")
brand <- rlang::syms(brand)
map_df(brand, ~new(ang = x, brad = y, drau = UQ(.x)))
Upvotes: 8
Reputation: 78792
This appears to do what you want (but it needs confirmation by you):
library(tidyverse)
library(rlang)
set.seed(1492)
xdf <- data_frame(
x = sample(1:100, 50),
y = rnorm(50),
z = sample(1:100,50),
w = sample(1:100, 50),
p = sample(1:100,50)
)
new_df <- function(ang, brad, drau) {
drau <- sym(drau)
filter(xdf, UQE(drau) %in% 1:50) %>%
select(ang, brad)
}
brand <- c("z", "w", "p")
map_df(brand, ~new_df(ang = "x", brad = "y", drau = .x))
Despite there being a plethora of "official" "tidyverse" examples using df
, it's a function in the stats
pkg and I try to avoid using it anymore.
Since you're using the tidyverse, might as well take advantage of map_df()
from purrr
.
Upvotes: 8