R передать переменные в пользовательскую функцию purrr - PullRequest
1 голос
/ 03 февраля 2020

Как мне отформатировать пользовательскую функцию для передачи переменных в функцию h2o? Я не могу понять правильный синтаксис quo / expr / ensym.

Вот небольшой пример синтаксиса, который я не могу понять:

suppressMessages(library(h2o))
#> Warning: package 'h2o' was built under R version 3.6.2

suppressMessages(library(rlang))
h2o.init()
#>  Connection successful!

data_h2o <- as.h2o(iris)

h2o.cor(data_h2o$Sepal.Length, data_h2o$Sepal.Width, use = "everything", method = "Pearson")
#> [1] -0.1175698



# function to take two variables and return the correlation

## in a larger data set I only care about how the target variable
## relates to the dependent variables
cor_function <- function(var1, var2) {
  var_1 = deparse(substitute(var1))
  var_2 = deparse(substitute(var2))
  r = h2o::h2o.cor(data_h2o[[var_1]], data_h2o[[var_2]], use = "complete.obs", na.rm = TRUE, method = "spearman")
  out <-  tibble::enframe(r, name = NULL)
  out$var1 = var_1
  out$var2 = var_2
  return(r)
}

# this works
cor_function(Sepal.Length, Sepal.Width)
#> [1] -0.1795433

params_to_run <- expand.grid(var1 = "Sepal.Length", var2 = c("Sepal.Width", "Petal.Width"))

suppressMessages(library(purrr))

purrr::map(params_to_run, cor_funtion)
#> Error in if ((nrow(x) == 1L || (ncol(x) == 1L && ncol(y) == 1L))) .eval.scalar(expr) else .fetch.data(expr, : missing value where TRUE/FALSE needed

Создано в 2020-02-03 с помощью пакета Представить (v0.3.0)

Это похоже на другие вопросы без ответов:

1 Ответ

1 голос
/ 04 февраля 2020

Я думаю, что здесь есть несколько проблем, самая важная из которых - это сочетание аккуратности и стандартной оценки. В cor_function(Sepal.Length, Sepal.Width) аргументы передаются в виде выражений, тогда как элементы в params_to_run являются строками (или факторами).

Поскольку я не вижу, что аккуратная оценка здесь действительно необходима, и map ping поверх строк кажется более естественным, я предлагаю решение без аккуратной оценки.

library("h2o")

library("purrr")
library("dplyr")

h2o.init()

data_h2o <- as.h2o(iris)

params_to_run <- expand.grid(var1 = "Sepal.Length", var2 = c("Sepal.Width", "Petal.Width"))
params_to_run
#>           var1        var2
#> 1 Sepal.Length Sepal.Width
#> 2 Sepal.Length Petal.Width

cor_fun <- function(data, x, y, FUN, ...) {
    # as.character() because expand.grid() produces factors
    r <- FUN(x = data[, as.character(x)], y = data[, as.character(y)], ...)
    return(r)
}

cor_fun(iris,     "Sepal.Length", "Sepal.Width", cor)
#> [1] -0.1175698
cor_fun(data_h2o, "Sepal.Length", "Sepal.Width", h2o.cor)
#> [1] -0.1175698
mutate(params_to_run, res = map2(var1, var2, ~cor_fun(data_h2o, .x, .y, h2o.cor)))
#>           var1        var2        res
#> 1 Sepal.Length Sepal.Width -0.1175698
#> 2 Sepal.Length Petal.Width  0.8179411

? Обратите также внимание, что params_to_run - это фрейм данных, и вы хотите l oop между строками. map() будет l oop по столбцам (например, lapply()), поэтому я использую mutate(), чтобы применить map() к каждой строке. Также обратите внимание, что cor_fun() требуется два аргумента, поэтому используется map2().

В конце концов, можно даже сделать это без пользовательской функции cor_fun():

mutate(params_to_run, 
       res = map2(var1, var2, ~h2o.cor(x = data_h2o[, as.character(.x)],
                                       y = data_h2o[, as.character(.y)])))
#>           var1        var2        res
#> 1 Sepal.Length Sepal.Width -0.1175698
#> 2 Sepal.Length Petal.Width  0.8179411

Ниже Вы находите раствор с приборкой Eval. Однако, это не будет работать с params_to_run, который содержит строки (или факторы, фактически).

cor_fun2 <- function(data, x, y, FUN, ...) {
    x <- rlang::enquo(x)
    y <- rlang::enquo(y)
    r <- FUN(x = data[, quo_name(x)], y = data[, quo_name(y)], ...)
    return(r)
}
cor_fun2(data_h2o, Sepal.Length, Sepal.Width, h2o::h2o.cor)
#> [1] -0.1175698

Создано в 2020-02-04 пакетом prex (v0.3.0)

...