0

I wanted to ask if someone knows a workaround of how I can dynamically assign arguments to R's sampling functions, i.e., I want to write a list with different names, say "mean" and "sd", and the elements of both of these sub-lists contain the corresponding numeric values for these parameters I want to have. As an example, I would like to do this:

#Distribution of Interest
SamplingDistribution <- rnorm

#Parameters of Interest for Normal Distribution
Parameters <- list(mean    = c(1, -1), 
                   sd      =  c(1, 2)   
               )

#Not Working Example
SamplingDistribution (n = 1, 
                      for(i in 1:length(Parameters) ){
                      names(Parameters)[i] <- Parameters[i]
                      }
  )

So ideally i just clarify the sampling distribution of interest at the beginning and then can put any argument that I want (in any order) in the Parameters list. Then the for loop just loops through the names of the parameters lists, and assigns the corresponding numeric values to the sample. Thanks to your input!

Best regards,

Edit: I get that I can just use the listnames in the rnorm function, but the focus of this question is really to somehow dynamically assign that, i.e. I can just expand the parameter list with more arguments and I dont have to assign anything new to the sampling procedure. I tried already around quite a bit with message/pasteo/cat/..., but the rnorm() function seems to not really accept any of these ...

3 Answers3

3

You can vectorize a function with Vectorize such that vectors can be used for its parameters:

rnormV <- Vectorize(rnorm)

rnormV(1, Parameters[[1]], Parameters[[2]])
# [1] -0.0530436 -0.2327272
Sven Hohenstein
  • 80,497
  • 17
  • 145
  • 168
2

There are a number of approaches to this, but to begin you'll want to check out the apply family of functions, helpful link here:

Parameters <- list(mean    = c(1, -1), 
                   sd      =  c(1, 2))

set.seed(1)

mapply(function(mn, sd) rnorm(1, mean = mn, sd = sd),
       Parameters[[1]],
       Parameters[[2]])

[1]  0.3735462 -0.6327134

Second Attempt:

This doesn't perfectly recreate what you're looking for, but I believe it gets close.

library(purrr)

my_sampling <- function(dst, par_list){
  map(transpose(par_list), 
         function(params){
           do.call(dst, params)
         })
}

norm_params <- list(n       = c(2,1),
                    mean    = c(1, -1), 
                    sd      = c(1, 2))

pois_params <- list(n      = c(5, 6),
                    lambda = c(3, 4))

set.seed(1)

my_sampling(rnorm, norm_params)

[[1]]
[1] 0.3735462 1.1836433

[[2]]
[1] -2.671257

my_sampling(rpois, pois_params)

[[1]]
[1] 6 4 3 1 2

[[2]]
[1] 2 5 3 5 4 5
zack
  • 5,205
  • 1
  • 19
  • 25
  • Thanks for your input and the link! The problem with this solution is that you would still need to clarify the function arguments, with the for loop proposed above I could just about add any argument to the list and then have this argument in the sampling step. I will edit my initial question. – MrVengeanZe Nov 20 '18 at 17:20
  • I guess to me it's unclear what you actually want. Different distributions will take different parameters, so it's unclear to me how you wouldn't end up writing the analogous version of the proposed solution for various sampling distributions. – zack Nov 20 '18 at 17:30
  • Thats actually exactly what I am looking for, i.e when i switch to a Beta distribution, i would assing "rbeta" to SamplingDistribution and adjust the Parameters list correspondingly, i.e. I get rid of mean and sd, and assign an Alpha, Beta and all other arguments that I want to do. I would like to do so as I have sample from this target many times, and would like a way to adjust the code fast and conventiently. – MrVengeanZe Nov 20 '18 at 17:34
  • I see - I believe the answer will involve splicing the list of parameters into a more generic function, but I'm unable to figure it out right now... – zack Nov 20 '18 at 17:47
  • I've given it another shot, hopefully this is at least closer to your goal – zack Nov 20 '18 at 21:44
  • Zack, this is brilliant! Thank you very much, fantastic idea. – MrVengeanZe Nov 21 '18 at 11:15
  • Also, I like the idea that n is not restricted to be an integer, but can be a vector – MrVengeanZe Nov 21 '18 at 11:23
1

mapply works

#Parameters of Interest for Normal Distribution
Parameters <- list(mean = c(1, -1), 
                   sd = c(1, 2)   
)
#Working Example
mapply(rnorm, n=1, mean=Parameters$mean, sd=Parameters$sd)
[1]  0.03164361 -1.12035840

Update

If you don't want to explicitly name the parameters or rely on any external packages you could simply do (see a similar answer for one set of parameters here) :

#Parameters of Interest for Normal Distribution
Parameters <- list(n = 1,
                   mean = c(10, -1), 
                   sd = c(1, 2))

do.call(Vectorize(rnorm),Parameters)

And if you will always have the same n and don't want it in your parameters list then you could do:

#Parameters of Interest for Normal Distribution
Parameters <- list(mean = c(1, -1), 
                   sd = c(1, 2)   
)

do.call(Vectorize(rnorm),c(list(n=1),Parameters))

Wrapped up in a nice function:

sampling <- function(fun, n, params{
  do.call(Vectorize(fun),c(list(n=n),params)
}

sampling(rnorm, 1, Parameters)
rookie
  • 641
  • 5
  • 9