簡體   English   中英

在 dplyr 中使用 filter_,其中字段和值都在變量中

[英]Using filter_ in dplyr where both field and value are in variables

我想使用在變量中定義的字段過濾數據框,以選擇也在變量中的值。 說我有

df <- data.frame(V=c(6, 1, 5, 3, 2), Unhappy=c("N", "Y", "Y", "Y", "N"))
fld <- "Unhappy"
sval <- "Y"

我想要的值是df[df$Unhappy == "Y", ]

我讀過的nse小插曲嘗試使用filter_但不能完全理解。 我試過

df %>% filter_(.dots = ~ fld == sval)

什么都沒有返回。 我得到了我想要的

df %>% filter_(.dots = ~ Unhappy == sval)

但顯然這違背了使用變量來存儲字段名稱的目的。 請問有什么線索嗎? 最終我想使用它,其中fld是字段名稱的向量, svalfld每個字段的過濾器值的向量。

您可以嘗試interplazyeval

 library(lazyeval)
 library(dplyr)
 df %>%
     filter_(interp(~v==sval, v=as.name(fld)))
 #   V Unhappy
 #1 1       Y
 #2 5       Y
 #3 3       Y

對於多個鍵/值對,我發現這是可行的,但我認為應該有更好的方法。

  df1 %>% 
    filter_(interp(~v==sval1[1] & y ==sval1[2], 
           .values=list(v=as.name(fld1[1]), y= as.name(fld1[2]))))
 #  V Unhappy Col2
 #1 1       Y    B
 #2 5       Y    B

對於這些情況,我發現base R選項更容易。 例如,如果我們試圖基於'fld1'中的'key'變量和'sval1'中的相應值來filter行,則一種選擇是使用Map 我們對數據集( df1[fld1] )進行子集設置,並將FUN( == )應用於df1[f1d1]每一列,並在'sval1'中使用相應的值,並使用&Reduce來獲取可用於filter的邏輯矢量'df1'的行。

 df1[Reduce(`&`, Map(`==`, df1[fld1],sval1)),]
 #   V Unhappy Col2
 # 2 1       Y    B
  #3 5       Y    B

數據

df1 <- cbind(df, Col2= c("A", "B", "B", "C", "A"))
fld1 <- c(fld, 'Col2')
sval1 <- c(sval, 'B')    

現在,使用rlang 0.4.0,它為這種用例引入了一種新的更直觀的方法:

packageVersion("rlang")
# [1] ‘0.4.0’

df <- data.frame(V=c(6, 1, 5, 3, 2), Unhappy=c("N", "Y", "Y", "Y", "N"))
fld <- "Unhappy"
sval <- "Y"

df %>% filter(.data[[fld]]==sval)

#OR
filter_col_val <- function(df, fld, sval) {
  df %>% filter({{fld}}==sval)
}

filter_col_val(df, Unhappy, "Y")

可以在https://www.tidyverse.org/articles/2019/06/rlang-0-4-0/找到更多信息。

上一個答案

在dplyr 0.6.0及更高版本中,此代碼有效:

packageVersion("dplyr")
# [1] ‘0.7.1’

df <- data.frame(V=c(6, 1, 5, 3, 2), Unhappy=c("N", "Y", "Y", "Y", "N"))
fld <- "Unhappy"
sval <- "Y"

df %>% filter(UQ(rlang::sym(fld))==sval)

#OR
df %>% filter((!!rlang::sym(fld))==sval)

#OR
fld <- quo(Unhappy)
sval <- "Y"
df %>% filter(UQ(fld)==sval)

有關http://dplyr.tidyverse.org/articles/programming.html上可用的dplyr語法的更多信息,以及rlanghttps://cran.r-project.org/web/packages/rlang/index中的quosure用法。 html

如果您發現在dplyr 0.6及更高版本中掌握非標准評估具有挑戰性,那么Alex Hayes可以撰寫有關以下主題的出色文章: https ://www.alexpghayes.com/blog/gentle-tidy-eval-with-examples/

原始答案

在dplyr 0.5.0及更高版本中,可以使用更簡單的語法並更接近最初想要的@Ricky語法,與使用lazyeval::interp相比,我還發現它更具可讀性。

df %>% filter_(.dots = paste0(fld, "=='", sval, "'"))

#  V Unhappy
#1 1       Y
#2 5       Y
#3 3       Y

#OR
df %>% filter_(.dots = glue::glue("{fld}=='{sval}'"))

這是一個以R為底的替代方案,它可能不是很優雅,但它的好處可能是易於理解:

df[df[colnames(df)==fld]==sval,]
#  V Unhappy
#2 1       Y
#3 5       Y
#4 3       Y

從LmW開始; 我個人更喜歡使用dplyr管道,其中在管道之前指定點,以便更容易以編程方式使用,例如在過濾器循環中使用。

dots <-  paste0(fld," == '",sval,"'")
df   %>% filter_(.dots = dots)

LmW的示例是正確的,但是值是硬編碼的

所以我試圖做同樣的事情,現在 dplyr 似乎有一個內置功能來解決這個問題。

在此處檢查最后一個示例: https : //dplyr.tidyverse.org/reference/filter.html

為簡單起見,我也將其粘貼在這里:

# To refer to column names that are stored as strings, use the `.data` pronoun:
vars <- c("mass", "height")
cond <- c(80, 150)
starwars %>%
  filter(
    .data[[vars[[1]]]] > cond[[1]],
    .data[[vars[[2]]]] > cond[[2]]
  )

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM