Каковы преимущества определения и вызова функции внутри другой функции в R?
подход 1
f1 <- function(x)
{
# Do calculation xyz ....
f2 <- function(y)
{
# Do stuff...
return(some_object)
}
return(f2(x))
}
подход 2
f2 <- function(y)
{
# Do stuff...
return(some_object)
}
f3 <- function(x)
{
# Do calculation xyz ....
return(f2(x))
}
предположим f1
и f3
оба делают те же вычисления и дают тот же результат.
есть значительное преимущества в использовании подхода 1, называя f1()
, vs подход 2, вызов f3()
?
является ли определенный подход более благоприятным, когда:
большие данные передаются и / или из
f2
?скорость-большая проблема. Е. Г.
f1
илиf3
вызываются повторно в симуляциях.
(подход 1 кажется распространенным в пакетах, определяя внутри другого)
одно преимущество использования подхода f1
это f2
не будет существовать вне f1
после f1
закончил вызов (и f2
вызывается только в f1
или f3
).
2 ответов
преимущества определения f2
внутри f1
:
-
f2
только внутриf1
, полезной еслиf2
предназначен только для использования внутриf1
, хотя в пространствах имен пакетов это спорно, так как вы просто не будете экспортироватьf2
Если вы определили его за пределами -
f2
имеет доступ к переменным внутриf1
, что можно считать хорошим или плохим:- хорошо, потому что вам не нужно передавать переменные через интерфейс функции, и вы можете использовать
<<-
реализовать такие вещи, как memoization и т. д. - плохо, по тем же причинам...
- хорошо, потому что вам не нужно передавать переменные через интерфейс функции, и вы можете использовать
недостатки:
-
f2
необходимо переопределять каждый раз, когда вы вызываетеf1
, что добавляет некоторые накладные расходы (не очень накладные расходы, но определенно есть)
размер данных не имеет значения, так как R не будет копировать данные, если он не изменяется в любом сценарии. Как отмечено в разделе недостатки, определение f2
за пределами f1
должно быть немного быстрее, особенно если вы повторяете в противном случае относительно низкую накладную операцию много раз. Вот пример:
> fun1 <- function(x) {
+ fun2 <- function(x) x
+ fun2(x)
+ }
> fun2a <- function(x) x
> fun3 <- function(x) fun2a(x)
>
> library(microbenchmark)
> microbenchmark(
+ fun1(TRUE), fun3(TRUE)
+ )
Unit: nanoseconds
expr min lq median uq max neval
fun1(TRUE) 656 674.5 728.5 859.5 17394 100
fun3(TRUE) 406 434.5 480.5 563.5 1855 100
в этом случае мы экономим 250ns (edit: разница на самом деле 200ns; верьте или нет дополнительный набор {}
это fun1
имеет стоимость еще 50ns). Не так много, но можно сложить, если внутренняя функция более сложная или вы повторяете функцию много много раз.
вы обычно используете подход 2. Некоторые исключения
-
функция закрытия:
f = function() { counter = 1 g = function() { counter <<- counter + 1 return(counter) } } counter = f() counter() counter()
закрытие функции позволяет нам запомнить состояние.
-
иногда удобно определять только функции, поскольку они используются только в одном месте. Например, при использовании
optim
, мы часто настраиваем существующую функцию. Например,pdf = function(x, mu) dnorm(x, mu, log=TRUE) f = function(d, lower, initial=0) { ll = function(mu) { if(mu < lower) return(-Inf) else -sum(pdf(d, mu)) } optim(initial, ll) } f(d, 1.5)
на
ll
функция использует набор данныхd
и снизу. Этот это удобно, так как это может быть единственное время, когда мы используем/нуждаемся в .