Список функций: применять дополнительный аргумент только к тем функциям, которые могут его принять - PullRequest
3 голосов
/ 16 февраля 2020

У меня есть список функций, большинство из которых принимают один и тот же дополнительный аргумент (na.rm = TRUE).

Я хочу добавить функцию, которая не принимает этот аргумент (length). Можно ли применить дополнительный аргумент только к функциям, которые могут его принять? Я думал об использовании ..., но я не совсем уверен, как его применить, и возможно ли это вообще.

Я использую lapply, но доволен любыми опциями, в том числе и за пределами базы R.

x <- c(1:10,NA)

# working example only with functions that take the extra argument

show_stats <- function(x) {
  funs <- list(mean = mean, sd = sd)
  lapply(funs, function(f) f(x, na.rm = TRUE))
}
show_stats(x) 
#> $mean
#> [1] 5.5
#> 
#> $sd
#> [1] 3.02765

# sadly not working, because length() only takes one argument
show_stats <- function(x) {
  funs <- list(mean = mean, sd = sd, n = length)
  lapply(funs, function(f) f(x, na.rm = TRUE))
}

show_stats(x)
#> Error in f(x, na.rm = TRUE): 2 arguments passed to 'length' which requires 1

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

Ответы [ 3 ]

6 голосов
/ 16 февраля 2020

1) Вопрос не ясен относительно того, что ожидается в качестве вывода для length, но если вопрос заключается в том, как удалить NA, независимо от того, принимает ли функция аргумент na.rm или нет, тогда сначала просто удалите NA.

show_stats2 <- function(x) {
  funs <- list(mean = mean, sd = sd, length = length)
  lapply(funs, function(f) f(na.omit(x)))
}

2) Другая возможность, которая позволяет функциям иметь произвольно изменяющиеся аргументы, заключается в следующем. Каждая функция определяется как простая формула с подходящими аргументами. Здесь используется fn$ из gsubfn для преобразования формулы в функцию.

library(gsubfn)
show_stats3 <- function(x) {
  funs <- list(mean = ~ mean(x, na.rm = TRUE), 
               sd = ~ sd(x, na.rm = TRUE),
               length = ~ length(x))
  fn$lapply(funs, function(f) fn$identity(f)(x))
}

3) Вот вариант (2), который требует, чтобы вы написали слово function но так же гибок:

show_stats4 <- function(x) {
  funs <- list(mean = function(x) mean(x, na.rm = TRUE), 
               sd = function(x) sd(x, na.rm = TRUE),
               length = length)
  lapply(funs, function(f) f(x))
}

4) Еще одним вариантом является использование Curry из функционального пакета:

library(functional)
show_stats5 <- function(x) {
  funs <- list(mean = Curry(mean, na.rm = TRUE), 
               sd = Curry(sd, na.rm = TRUE),
               length = length)
  lapply(funs, function(f) f(x))
}
3 голосов
/ 16 февраля 2020

Я не уверен, является ли это самым безопасным способом сделать это, но вы можете использовать tryCatch, при котором, если возникает ошибка, вы возвращаете f(x) без каких-либо дополнительных аргументов.

show_stats <- function(x) {
  funs <- list(mean = mean, sd = sd, n = length)
  lapply(funs, function(f) tryCatch(f(x, na.rm = TRUE), error = function(e) f(x)))
}
show_stats(x) 

#$mean
#[1] 5.5

#$sd
#[1] 3.02765

#$n
#[1] 11
2 голосов
/ 16 февраля 2020

Вы также можете попробовать partial из purrr, не будучи уверенным, что вы нацелены на это. Вы также можете проверить, возможно, безопасно и тихо от мурлыкать, они могут быть полезны в некоторых случаях

func_factory <- function(x){
  partial(x, na.rm=T)
}

show_stats <- function(x) {
  funs <- list(mean = func_factory(mean), 
               sd = func_factory(sd), n = length)

  lapply(funs, function(f) f(x))
}

show_stats(x)

Вывод:

> show_stats(x)
$mean
[1] 5.5

$sd
[1] 3.02765

$n
[1] 11

> 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...