#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