Передача переменной для имени столбца?
Например, предположим, что у вас есть функция, которая применяет некоторые функции DPLYR, но вы не можете ожидать, что наборы данных, передаваемые этой функции, будут иметь одинаковые имена столбцов.
Для упрощенного примера того, что я имею в виду, скажем, у вас был фрейм данных, arizona.trees
:
arizona.trees
group arizona.redwoods arizona.oaks
A 23 11
A 24 12
B 9 8
B 10 7
C 88 22
и еще один очень похожий кадр данных, california.trees
:
california.trees
group california.redwoods california.oaks
A 25 50
A 11 33
B 90 5
B 77 3
C 90 35
И вы хотели реализовать функцию, которая возвращает среднее для заданных групп (A, B, ... Z) для данного типа дерева, которое будет работать для обоих этих фреймов данных.
foo <- function(dataset, group1, group2, tree.type) {
column.name <- colnames(dataset[2])
result <- filter(dataset, group %in% c(group1, group2) %>%
select(group, contains(tree.type)) %>%
group_by(group) %>%
summarize("mean" = mean(column.name))
return(result)
}
Желаемый выход для вызова foo(california.trees, A, B, redwoods)
было бы:
result
mean
A 18
B 83.5
По какой-то причине делать что-то вроде реализации foo()
просто не похоже на работу. Вероятно, это связано с некоторой ошибкой индексации фрейма данных - функция, кажется, думает, что я пытаюсь получить среднее значение column.name
строка, а не извлечение столбца и передача столбца mean()
, Я не уверен, как этого избежать. Существует проблема неявной передачи измененного фрейма данных, на который нельзя напрямую ссылаться с оператором канала, который может быть причиной проблемы.
Почему это? Есть ли альтернативная реализация, которая будет работать?
1 ответ
Мы можем использовать quosure
решение на основе версии devel dplyr
(скоро будет выпущен 0.6.0
)
foo <- function(dataset, group1, group2, tree.type){
group1 <- quo_name(enquo(group1))
group2 <- quo_name(enquo(group2))
colN <- rlang::parse_quosure(names(dataset)[2])
tree.type <- quo_name(enquo(tree.type))
dataset %>%
filter(group %in% c(group1, group2)) %>%
select(group, contains(tree.type)) %>%
group_by(group) %>%
summarise(mean = mean(UQ(colN)))
}
foo(california.trees, A, B, redwoods)
# A tibble: 2 × 2
# group mean
# <chr> <dbl>
#1 A 18.0
#2 B 83.5
foo(arizona.trees, A, B, redwoods)
# A tibble: 2 × 2
# group mean
# <chr> <dbl>
#1 A 23.5
#2 B 9.5
enquo
принимает входные аргументы и преобразует его в quosure
, с quo_name
, он преобразуется в строку для использования с %in%
имя второго столбца преобразуется в quosure
из строки, используя parse_quosure
и тогда это без кавычек (UQ
или же !!
) для оценки в summarise
ПРИМЕЧАНИЕ: это основано на функции OP о выборе второго столбца
Вышеупомянутое решение было основано на выборе столбца на основе позиции (согласно коду OP), и оно может не работать для других столбцов. Таким образом, мы можем сопоставить "tree.type" и получить "среднее" столбцов на основе этого
foo1 <- function(dataset, group1, group2, tree.type){
group1 <- quo_name(enquo(group1))
group2 <- quo_name(enquo(group2))
tree.type <- quo_name(enquo(tree.type))
dataset %>%
filter(group %in% c(group1, group2)) %>%
select(group, contains(tree.type)) %>%
group_by(group) %>%
summarise_at(vars(contains(tree.type)), funs(mean = mean(.)))
}
Функцию можно протестировать для разных столбцов в двух наборах данных.
foo1(arizona.trees, A, B, oaks)
# A tibble: 2 × 2
# group mean
# <chr> <dbl>
#1 A 11.5
#2 B 7.5
foo1(arizona.trees, A, B, redwood)
# A tibble: 2 × 2
# group mean
# <chr> <dbl>
#1 A 23.5
#2 B 9.5
foo1(california.trees, A, B, redwood)
# A tibble: 2 × 2
# group mean
# <chr> <dbl>
#1 A 18.0
#2 B 83.5
foo1(california.trees, A, B, oaks)
# A tibble: 2 × 2
# group mean
# <chr> <dbl>
#1 A 41.5
#2 B 4.0
данные
arizona.trees <- structure(list(group = c("A", "A", "B", "B", "C"),
arizona.redwoods = c(23L,
24L, 9L, 10L, 88L), arizona.oaks = c(11L, 12L, 8L, 7L, 22L)),
.Names = c("group",
"arizona.redwoods", "arizona.oaks"), class = "data.frame",
row.names = c(NA, -5L))
california.trees <- structure(list(group = c("A", "A", "B", "B", "C"),
california.redwoods = c(25L,
11L, 90L, 77L, 90L), california.oaks = c(50L, 33L, 5L, 3L, 35L
)), .Names = c("group", "california.redwoods", "california.oaks"
), class = "data.frame", row.names = c(NA, -5L))