Использование mapply внутри функции ()

Я пытаюсь сгенерировать несколько серий случайных чисел, каждая из которых имеет свой набор параметров. Затем я хочу повторить все это. Я хочу иметь функцию для этого, и мне кажется, что это должен быть однострочник с чем-то вроде rnorm() для генерации чисел, mapply() для генерации этих чисел для нескольких наборов параметров и replicate() для повторения всего процесса.

Для этого я написал функцию, ... аргумента которой я хочу соответствовать ... в mapply, но похоже, что ... игнорируется mapply. У меня есть несколько примеров, которые должны прояснить мой желаемый результат, а также проблему:

 # Some values to be passed to the ... of mapply
 mus <- c(-30, 0, 30)
 sds <- c(0.1, 1, 10)

 # =================================
 # = What I want, if it would work =
 # =================================
 f <- function(n=3, ...){
    replicate(2, mapply(rnorm, MoreArgs=list(n=n), ...))
 }
 f(mean=mus, sd=sds) # Doesn't work :(

>, , 1
>
>           [,1]
>[1,] -0.4901243
>[2,]  0.8268027
>[3,] -0.4829781
>
>, , 2
>
>            [,1]
>[1,] -0.02025903
>[2,] -1.57011537
>[3,]  0.49234503


# ==========================================================
# = What I can currently get to work, but not style I want =
# ==========================================================
# I can't understand why f.inside is needed!
f2 <- function(n=3, ...){
    f.inside <- function() mapply(rand.gen, MoreArgs=list(n=n), ...)
    replicate(2, f.inside())
}
f2(mean=mus, sd=sds) # Desired output

>, , 1
>
>          [,1]        [,2]      [,3]
>[1,] -29.83762 -0.06138165  9.956601
>[2,] -30.04880  1.39123405 33.036675
>[3,] -29.94070 -1.15741513 19.337497
>[4,] -29.92360  0.74300731 38.741367
>[5,] -29.81723  0.84565813 22.261605
>
>, , 2
>
>          [,1]       [,2]     [,3]
>[1,] -30.01407 -0.5198845 20.85942
>[2,] -29.77586 -0.1705062 22.06274
>[3,] -29.96901 -0.4412471 21.42849
>[4,] -30.04079  0.4230790 28.35480
>[5,] -30.04794  0.3000821 50.09012

Полагаю, мне нужно чем-то обернуть ...; Я случайно пробовал такие вещи, как alist(), list(), bquote(), expression(), as.call() и несколько других неудачных подходов.

1) Почему mapply в f(), похоже, полностью игнорирует ...? РЕДАКТИРОВАТЬ: это был вспомогательный вопрос, ответ на который - "точки не работают с репликой ». Хорошо, перейдем к основному вопросу ...

# =====================================
# = OK, Function for Refined Question =
# =====================================
f.edit <- function(n=3, ...){
    l <- list(...)
    replicate(2,mapply(rnorm, MoreArgs=list(n=n), l))
}
f.edit(mean=mus, sd=sds) # Doesn't work :(

2) Как разделить элементы объекта на элементы длины (объекта) и передать их как отдельные элементы в ... mapply?

Мне нужно улучшить свои эллипсы. Я действительно озадачен этим.


person rbatt    schedule 05.08.2015    source источник
comment
Лучшее решение - использовать тот факт, что rnorm уже векторизован по своим аргументам mean и sd. Например, f<-function(n,reps,mean,sd) {m<-length(mean);aperm(array(rnorm(n*m*reps,mean,sd),c(m,n,reps)),c(2,1,3))}   -  person A. Webb    schedule 05.08.2015
comment
@ A.Webb Хороший, хороший аргумент; к сожалению, делаю это в стиле arima.sim; т.е. rnorm может быть любой функцией генерации чисел, которая имеет n в качестве аргумента. Но вы правильно подметили.   -  person rbatt    schedule 05.08.2015
comment
Что касается редактирования f.edit, попробуйте вместо этого function(n=3, ...){dots<-list(...);replicate(2, do.call(mapply,c(list(FUN=rnorm),dots,list(MoreArgs=list(n=n)))))}   -  person A. Webb    schedule 05.08.2015
comment
@ A.Webb Вот и все! Хорошо, я пробовал что-то вроде do.call, но не получилось; Я все еще пытаюсь понять, зачем нужна именно такая структура list() и c(), но, как известно, это необходимо. Мило спасибо.   -  person rbatt    schedule 05.08.2015
comment
@nongkrong Ваше решение работает, но я все еще пытаюсь его понять. Я никогда раньше не использовал обозначение '', так что спасибо, что познакомили меня с ним, а также с as.call, с которым я тоже не знаком. Благодаря тонну!   -  person rbatt    schedule 05.08.2015
comment
@rbatt аналогично решению do.call, за исключением того, что вы сами создаете вызов. Обратные кавычки - это просто способ называть вещи, например, попробуйте `one and two` <- 3; `one and two`   -  person Rorschach    schedule 06.08.2015


Ответы (2)


В моде, который вы пытаетесь использовать в _1 _...

  • Вы можете составить список аргументов и выполнить do.call с mapply

    function(n=3, ...){
      dots<-list(...);
      replicate(2,do.call(mapply,c(list(FUN=rnorm),dots,list(MoreArgs=list(n=n)))))
    }
    
  • Или извлеките аргументы и вызовите напрямую

    function(n=3, ...){
      dots<-list(...);
      replicate(2,mapply(rnorm,dots$mean,dots$sd,MoreArgs=list(n=n)))
    }
    

В любом случае вы принудительно оцениваете ... в правильной среде, как это также делается в ваших f2 и альтернативе MrFlick.

Проблема с написанным f.edit в том, что rnorm вызывается как rnorm(n,list(means=mus,sd=sds)), а не как rnorm(n,means=mu,sd=sds).


Однако в этом случае вы можете рассмотреть возможность использования того факта, что rnorm уже векторизован по своим аргументам mean и sd.

function(n,reps,mean,sd) {
  m<-length(mean);
  aperm(array(rnorm(n*m*reps,mean,sd),c(m,n,reps)),c(2,1,3))
}
person A. Webb    schedule 05.08.2015
comment
так что в f.edit нет способа сделать что-нибудь с l, чтобы он работал? Я просто пытаюсь осознать это. Я знаю, что передаю только 1 аргумент вместо нескольких ... но могу ли я разделить этот 1 на несколько? Я думаю, это то, что вы делаете с do.call. - person rbatt; 06.08.2015
comment
@rbatt Посмотрите, проясняют ли приведенные выше правки, что происходит в f.edit. - person A. Webb; 06.08.2015

Проблема в том, что вам не разрешено использовать ... с replicate, как уже упоминалось здесь.

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

Другой вариант - избегать replicate и использовать lapply (со значениями индекса, которые вы в конечном итоге игнорируете)

f3 <- function(n=3, ...){
    lapply(1:2, function(i, ...) mapply(rnorm, MoreArgs=list(n=n), ...), ...)
}
f3(mean=mus, sd=sds)
person MrFlick    schedule 05.08.2015