Отфильтруйте фрейм данных с помощью «состояния», которое может принимать как символы, так и цифры в качестве входных данных для столбцов

#r #dplyr #tidyverse

Вопрос:

У меня есть фрейм данных, подобный этому

         id <- c(5738180,51845,167774,517814,1344920,517833,51844)
        state_code <- c("AZ","CA","AZ","WA","MO","CA","AZ")
        state_rank <- c(1,2,1,3,4,2,1)
        df.sample <- data.frame(id,state_code,state_rank, stringsAsFactors=FALSE) 
    
 

df.образец

        id state_code state_rank
  5738180         AZ          1
    51845         CA          2
   167774         AZ          1
   517814         WA          3
  1344920         MO          4
   517833         CA          2
    51844         AZ          1
 

Я пытаюсь создать функцию, которая принимает a df и state в качестве входных данных и возвращает a df на основе отфильтрованных state

state Переменная должна иметь возможность принимать и state_code то, и state_rank другое в качестве входных данных

Желаемые результаты

Если я пройду в

состояние = «AZ», возвращаемые строки отфильтрованы для state_code = "AZ"

        id state_code state_rank
  5738180         AZ          1
   167774         AZ          1
    51844         AZ          1
 

состояние = «WA,MO», возвращаемые строки отфильтрованы для state_code = c("WA","MO")

        id state_code state_rank
   517814         WA          3
  1344920         MO          4
 

состояние = 2, верните 2 лучших ранжированных состояния state_rank <= 2

        id state_code state_rank
  5738180         AZ          1
    51845         CA          2
   167774         AZ          1
   517833         CA          2
    51844         AZ          1
 

Я пытаюсь сделать это таким образом, но не получаю того, чего хотел

 func <- function(df, state){
    df %>% filter(state_code == state)
}

func(df.sample,state = c("AZ"))
 

Я был бы очень признателен, если бы кто — нибудь мог указать мне правильное направление.

Комментарии:

1. Пожалуйста, будьте более осторожны с вашими образцами данных, они пытаются получить доступ state туда, где, по моему мнению, они должны быть state_code .

2. @r2evans спасибо, что указали на это. отредактированный.

Ответ №1:

Я нахожу полиморфные аргументы временами крутыми, но они слишком часто кусали меня, чтобы быть действительно полезными, особенно когда два типа/переменные не имеют реальной связи. Я предлагаю быть откровенным в отношении переменных,

 func <- function(x, codes, rank) {
  if (!missing(codes)) {
    codes <- unlist(strsplit(codes, ",", fixed = TRUE), use.names = FALSE)
    x <- subset(x, state_code %in% codes)
  }
  if (!missing(rank)) {
    x <- subset(x, state_rank <= rank)
  }
  x
}

func(df.sample, codes="WA,MO")   # since your example included the literal "WA,MO"
#        id state_code state_rank
# 4  517814         WA          3
# 5 1344920         MO          4
func(df.sample, codes=c("WA","MO"))
#        id state_code state_rank
# 4  517814         WA          3
# 5 1344920         MO          4

func(df.sample, rank=2)
#        id state_code state_rank
# 1 5738180         AZ          1
# 2   51845         CA          2
# 3  167774         AZ          1
# 6  517833         CA          2
# 7   51844         AZ          1

 

Ответ №2:

Вы можете просто туннелировать свое состояние фильтра непосредственно к dplyr::filter использованию {{}} :

 library(dplyr)

f <- function(df, cond){
  df %>% 
    filter({{ cond }})
}
 

Выход

 f(df.sample, state_rank <= 2)
       id state_code state_rank
1 5738180         AZ          1
2   51845         CA          2
3  167774         AZ          1
4  517833         CA          2
5   51844         AZ          1
 
 f(df.sample, state_code %in% c("WA", "MO"))
       id state_code state_rank
1  517814         WA          3
2 1344920         MO          4
 

Ответ №3:

У вас может быть два разных входных аргумента, один для state и другой для state_rank , но если вы хотите сохранить его в качестве одного аргумента, вам понадобится оператор if, чтобы различать, выполняете ли вы фильтрацию по state или state_rank .

 func <- function(df, state){
    if(is.numeric(state) {
        df %>% filter(state_rank >= state)
    } else {
        df %>% filter(state_code %in% state)
    }
}
 

Возможно, вы захотите справиться с такими вещами, как «что, если вы пройдете state=NA «, но, надеюсь, это поможет вам начать.

Ответ №4:

С помощью subset

  f1 <- function(dat, state_codes) {
      subset(dat, state_code %in% state_codes)
}
 

-тестирование

 > f1(df.sample, c("AZ"))
       id state_code state_rank
1 5738180         AZ          1
3  167774         AZ          1
7   51844         AZ          1
> f1(df.sample, c("WA", "MO"))
       id state_code state_rank
4  517814         WA          3
5 1344920         MO          4