Передача переменной для имени столбца?

Например, предположим, что у вас есть функция, которая применяет некоторые функции 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))
Другие вопросы по тегам