#r #dplyr #tidyverse
Вопрос:
Я написал функцию, которая принимает символ в качестве входных данных, а затем преобразуется в quosure, а enquo()
затем оценивается !!
оператором в функциях tidyverse. Упрощенная версия функции выглядит следующим образом (полная функция возвращает фрейм данных и делает больше вместо простого вычисления числа, но только для иллюстрации этого должно быть достаточно).:
query <- function(test){
#colnames are different tests, obtain quosure of the test name
test = enquo(test)
avg_test_score = scores %>%
group_by(student) %>% summarise(mean.score = mean(!!test))
}
Функция отлично работает, если я query(english.test)
, например, это сделаю. Однако теперь я хочу поместить его в цикл for для всех различных столбцов, получить их имена и запустить его через функцию, а затем сохранить выходные данные в списке
output_list = list()
for (i in length(test.name)){
this.test = test.name[i] #test.name is a vector of strings
output_list[[i]] = query(test = this.test)
}
Но я получаю эту ошибку:
In mean.default(~this.test) :
argument is not numeric or logical: returning NA
Поэтому я вроде как понял, что мне нужно преобразовать символьную строку в символ, прежде чем вводить ее в функцию, но я пробовал разные способы преобразования, например, test.name[i] %>% as.symbol()
или test.name[i] %>% rlang::sym()
все же они все еще не совсем работают. Есть ли какой-либо способ правильно обработать эти преобразования, чтобы цикл for мог запускать мою функцию? Спасибо!
Комментарии:
1. Вы согласны с использованием
query("english.test")
вместоquery(english.test)
?2. да, функция может быть изменена для приема строк, а также до тех пор, пока все это работает либо в цикле, либо если я вручную ввожу аргументы, если хочу глубже изучить отдельные столбцы
Ответ №1:
Вот воспроизводимый подход для вычисления среднего значения нескольких столбцов в фрейме данных/tibble:
library(tidyverse)
library(rlang)
#>
#> Attaching package: 'rlang'
#> The following objects are masked from 'package:purrr':
#>
#> %@%, as_function, flatten, flatten_chr, flatten_dbl, flatten_int,
#> flatten_lgl, flatten_raw, invoke, list_along, modify, prepend,
#> splice
nms <- c('cyl', 'hwy', 'cty')
nms %>%
map(~ mpg %>%
group_by(manufacturer) %>%
summarise('mean_{.x}' := mean(eval_tidy(sym(.x)))) )
#> [[1]]
#> # A tibble: 15 x 2
#> manufacturer mean_cyl
#> <chr> <dbl>
#> 1 audi 5.22
#> 2 chevrolet 7.26
#> 3 dodge 7.08
#> 4 ford 7.2
#> 5 honda 4
#> 6 hyundai 4.86
#> 7 jeep 7.25
#> 8 land rover 8
#> 9 lincoln 8
#> 10 mercury 7
#> 11 nissan 5.54
#> 12 pontiac 6.4
#> 13 subaru 4
#> 14 toyota 5.12
#> 15 volkswagen 4.59
#>
#> [[2]]
#> # A tibble: 15 x 2
#> manufacturer mean_hwy
#> <chr> <dbl>
#> 1 audi 26.4
#> 2 chevrolet 21.9
#> 3 dodge 17.9
#> 4 ford 19.4
#> 5 honda 32.6
#> 6 hyundai 26.9
#> 7 jeep 17.6
#> 8 land rover 16.5
#> 9 lincoln 17
#> 10 mercury 18
#> 11 nissan 24.6
#> 12 pontiac 26.4
#> 13 subaru 25.6
#> 14 toyota 24.9
#> 15 volkswagen 29.2
#>
#> [[3]]
#> # A tibble: 15 x 2
#> manufacturer mean_cty
#> <chr> <dbl>
#> 1 audi 17.6
#> 2 chevrolet 15
#> 3 dodge 13.1
#> 4 ford 14
#> 5 honda 24.4
#> 6 hyundai 18.6
#> 7 jeep 13.5
#> 8 land rover 11.5
#> 9 lincoln 11.3
#> 10 mercury 13.2
#> 11 nissan 18.1
#> 12 pontiac 17
#> 13 subaru 19.3
#> 14 toyota 18.5
#> 15 volkswagen 20.9
# or
nms %>%
map_dfc(~ mpg %>%
group_by(manufacturer) %>%
summarise('mean_{.x}' := mean(eval_tidy(sym(.x)))) %>%
`[`(, 2) ) %>% #avoid duplicated manufacturer columns
mutate(group_by(mpg, manufacturer) %>% summarise())
#> # A tibble: 15 x 4
#> mean_cyl mean_hwy mean_cty manufacturer
#> <dbl> <dbl> <dbl> <chr>
#> 1 5.22 26.4 17.6 audi
#> 2 7.26 21.9 15 chevrolet
#> 3 7.08 17.9 13.1 dodge
#> 4 7.2 19.4 14 ford
#> 5 4 32.6 24.4 honda
#> 6 4.86 26.9 18.6 hyundai
#> 7 7.25 17.6 13.5 jeep
#> 8 8 16.5 11.5 land rover
#> 9 8 17 11.3 lincoln
#> 10 7 18 13.2 mercury
#> 11 5.54 24.6 18.1 nissan
#> 12 6.4 26.4 17 pontiac
#> 13 4 25.6 19.3 subaru
#> 14 5.12 24.9 18.5 toyota
#> 15 4.59 29.2 20.9 volkswagen
Создано 2021-06-13 пакетом reprex (v2.0.0)
Ответ №2:
Вы можете изменить функцию на прием строк.
library(dplyr)
query <- function(test){
avg_test_score = scores %>%
group_by(student) %>% summarise(mean.score = mean(.data[[test]]))
}
Для одной колонки это будет работать query("english.test")
.
Для нескольких столбцов вы можете использовать lapply
/ map
—
multiple_cols <- c('english.test', 'french.test')
purrr::map(multiple_cols, query)