Каковы преимущества определения и вызова функции внутри другой функции в 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и снизу. Этот это удобно, так как это может быть единственное время, когда мы используем/нуждаемся в .