在编程中使用dplyr filter()函数

6

我正在编写函数,并希望使用dplyr的filter()函数来选择满足条件的数据行。这是我的代码:

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()

每次运行此函数时,似乎filter没有选择任何满足条件的行。

我该如何使其正常工作?

更新

出于某种原因,当我不使用`%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()

然而,每个循环的结果都是相同的。为什么会这样?并且为什么我不能使用 %in%

请查看 filter_ - HubertL
1
@HubertL,是的,我知道,filter_也正在逐步淘汰。 - Kay
你在哪里读到这个的? - HubertL
1
在dplyr手册中 @HubertL。输入?filter_,你会看到它已经被弃用了。 - hrbrmstr
并不是真的..只是我有一个想法。由于这些函数是过时版本,它们很可能很快就会被淘汰。我不想使用它们。 - Kay
4个回答

9

我同意 @hrbrmstr 的标准评估解决方案。如 @hadley 建议 今天,这里提供 NSE 解决方案:

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)))

我想提醒大家,UQ现在已经被弃用了。请看一下dplyr中的双括号运算符,这是现代编程的一种方式。我建议观看Lionel Henry最近的任何演讲。 - dmi3kno

8

这似乎能够实现你的需求(但需要你确认):

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))

尽管有大量“官方”的“tidyverse”示例使用df,但它是stats pkg中的一个函数,我尽量避免再使用它了。
既然您正在使用tidyverse,不妨利用purrr中的map_df()

我不理解“plethora of "official" "tidyverse" examples using df, it's a function in the stats pkg”的含义。我没有看到任何stats函数。我猜你是指base::lapply - dpprdan
3
df 函数返回 F 分布的密度,其来自于 stats 包。我同意 @hrbrmstr 的看法,我也停止使用 df 作为命名。 - aurelien
1
如果您使用基本函数as.name()替换rlang::sym(),则可以不加载library(rlang) - dmi3kno
这个答案已经过时了,因为 UQE 已经被弃用。请检查我的答案或其他答案。 - Kay

1
我曾经遇到过类似的问题,而对我有效的简单解决方法是在“filter”动词中使用“.data”代词,特别是在这种情况下:
filter(.data[[drau]] %in% 1:50)

更多信息请查看:https://tinyheero.github.io/2020/03/01/use-data-env-pronouns-tidyverse.html 此外,Lionel Henry 在 Rstudio 的 YouTube 频道上的最新演讲也很有帮助。

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()

希望有人能从中受益。


1
由于现在 UQE 已经被弃用,所以这个问题的接受答案将不再适用。这个答案应该可以使用。这里唯一的变化是 !!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()

如果您不想将函数参数作为字符串传递,请使用!!enquo()
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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接