функция для запуска по выбранным столбцам с помощью dplyr (tidyeval) - PullRequest
2 голосов
/ 15 апреля 2020

Я некоторое время боролся с реализацией https://dplyr.tidyverse.org/articles/programming.html Хэдли, и я не могу заставить ее работать в моих целях.

В моем игрушечном примере я хочу написать функцию, которая будет принимать в качестве аргументов два столбца (имена столбцов известны) и запускать t.test. Проблема в том, что я не могу передать имена столбцов в t.test. Вот оно:

df <- tibble(
names = LETTERS[1:10],
colA = rnorm(10),
colB = rnorm(10, 1, 2),
colC = rnorm(10, 3, 4)
)

И это то, что я имею в виду (обратите внимание, что я использую magrittr для извлечения столбцов как векторов напрямую):

myFun <- function(data, column_name1, column_name2) {
    data %$%
    t.test(column_name1, column_name2)$p.value
}
myFun(df, colA, colB) # doesn't work

Руководство Хэдли говорит, что проанализируйте имена столбцов должным образом, нам нужно использовать quosure, чтобы «заключить в кавычки» имена переменных, а затем «снять их в кавычки», когда они используются в функции (он использует слова «dark magi c», что звучит для меня точно). Я интерпретировал это так:

myFun <- function(data, column_name1, column_name2) {
    col1 <- enquo(column_name1)
    col2 <- enquo(column_name2)
    data %$%
    t.test(!!col1, !!col2)$p.value
}
myFun(df, colA, colB)

Это, однако, приводит к ошибке:

Error: Quosures can only be unquoted within a quasiquotation context.

  # Bad:
  list(!!myquosure)

  # Good:
  dplyr::mutate(data, !!myquosure)

Что, я думаю, означает, что я не могу использовать quosure с t.test (не функция Tidyverse)? Поэтому я пока отказался от своего t.test и попытался проверить, сработал ли просто выбор столбцов:

myFun <- function(data, column_name1, column_name2) {
    col1 <- enquo(column_name1)
    col2 <- enquo(column_name2)
    data %>%
    dplyr::select(!!col1, !!col2)
}
myFun(df, colA, colB)

Это работает. Но тогда это:

myFun <- function(data, column_name1, column_name2) {
    col1 <- enquo(column_name1)
    col2 <- enquo(column_name2)
    data %>%
    dplyr::select(!!col1, !!col2) %$%
    t.test(col1, col2)$p.value
}
myFun(df, colA, colB)

- нет, с ошибкой Error in t.test.formula(colA, colB) : 'formula' missing or incorrect (хотя я не использую обозначение формулы для t.test). Просто чтобы быть ясно, это работает нормально: df %$% t.test(colA, colB)$p.value.

Я хотел бы понять, почему передача имен столбцов (которые выбраны правильно!) Не работает в этой функции и, если это безнадежно идея запустить попарно t.tests, что является лучшим решением? Конечной целью этого является более крупная функция, которая будет принимать произвольный набор числовых столбцов и выполнять все попарные t.test возможные.

Спасибо!

кДж

Ответы [ 3 ]

3 голосов
/ 15 апреля 2020

Несколько моментов:

  • В этом руководстве рассказывается о взаимодействии с функциями tidy eval. Вместо этого вы пытаетесь создать новую функцию tidy eval.

  • Это WIP, который не будет завершен, потому что мы упростили tidy eval, и он больше не нуждается в книга. Я рекомендую перейти к следующей версии виньетки для программирования dplyr: https://dplyr.tidyverse.org/dev/articles/programming.html (удалите /dev из URL, как только выйдет dplyr 1.0).

  • Хороший подход - использовать transmute() или select() для ввода данных, а затем работать с фреймом данных.

  • Однако лучше всего взаимодействовать с select(), когда вы работаете с несколько переменных. Здесь вы хотите выбрать один, который не подтвержден select(). Например, пользователь может указать starts_with() в качестве входных данных.

  • Главное, чего не хватает в вашей функции, так это того, что вы не задали имена констант для столбца, чтобы их можно было выбирать и поставьте их на t.test().

Я предлагаю что-то вроде (не проверено):

t_test <- function(data, col1, col2) {
  data <- data %>% transmute(
    col1 = {{ col1 }},
    col2 = {{ col2 }}
  )

  test <- t.test(data$col1, data$col2)
  test$p.value
}
1 голос
/ 15 апреля 2020

Я полагаю, что вы близки, попробуйте:

myfun <- function(data, c1, c2) {
  c1 <- enquo(c1)
  c2 <- enquo(c2)
  t.test(pull(data, !!c1), pull(data, !!c2))$p.value
}
myfun(df, colA, colB)
# [1] 0.1179605

Проблема с вашей последней версией в том, что вы передаете тибл на t.test, но вам нужно 2 вектора.

0 голосов
/ 15 апреля 2020

Вы можете сделать это в базе R с помощью deparse(substitute()):

myFun <- function(data, col1, col2) {
  t.test(data[[deparse(substitute(col1))]] , data[[deparse(substitute(col2))]])$p.value
}

Так, что:

myFun(df, colA, colB)
#> [1] 0.01541674
...