简体   繁体   中英

R: Use outer() on user-defined function

I want to use a user-defined function with the outer function. I want to use every combination of the two vectors' elements as arguments for my function myfun .

v1= c(30, 60, 100)
v2 = c(30, 60, 100)

myfun = function(x, y){
  rt = unlist(Vectorize(retimes::rexgauss)(n = x, tau = y, mu = 500, sigma = 50))
  ks = ks.test(rt, "pnorm", mean(rt), sd(rt))$p.value
  shap = shapiro.test(rt)$p.value
  z = skew(rt) / sqrt(6/length(rt))
  ztest = pnorm(-abs(z))*2
  results = c(ks, shap, ztest)
  names(results) = c("ks", "shapiro", "ztest")
  return(results)
}

outer(v1, v2, myfun)

If I do it like this, I get this error:

Error in dim(robj) <- c(dX, dY) : dims [product 9] do not match the length of object [3]

I want to avoid looping over all the elements of my two vectors. How can I use the outer function here? How do I vectorize my udf properly?

To use outer , some basic "requirements":

  1. the function will take two vectors all at once (as shown below); whether it chooses to do vectorized work on them or work on them individually is up to you;

  2. it must return a vector of the same length as x (and y ); and

  3. you must expect the output as a matrix of dimensions length(x),length(y) .

Interpreting that these are not all true for you, we move on. "The right function" depends on how you want the model to be run. A companion function to outer is expand.grid (and tidyr::crossing , the tidyverse version), in that it creates the same combinations of the supplied vectors. For instance:

outer(c(30,60,90), c(30, 60, 100), function(x,y) {browser();1;})
# Called from: FUN(X, Y, ...)
# Browse[2]> 
x
# [1] 30 60 90 30 60 90 30 60 90
# Browse[2]> 
y
# [1]  30  30  30  60  60  60 100 100 100

and

eg <- expand.grid(x=c(30,60,90), y=c(30, 60, 100))
eg
#    x   y
# 1 30  30
# 2 60  30
# 3 90  30
# 4 30  60
# 5 60  60
# 6 90  60
# 7 30 100
# 8 60 100
# 9 90 100

(which you can then access as eg$x and eg$y ).

Some options:

  1. if you want your function to be called once (as with outer ) with two arguments, and it will figure out what to do:

     eg <- expand.grid(x=c(30,60,90), y=c(30, 60, 100)) do.call("myfunc", eg)

    Note that if given character arguments, it will (similar to data.frame ) create factor s by default. It does accept the stringsAsFactors=FALSE argument.

  2. if you want your function to be called for each pair of the vectors (so 9 times in this example), then do one either

    myfunc(eg$x, eg$y)

    if the number of vectors is known. If not, then using eg from above, then

    do.call("mapply", c(myfunc, eg))

    should work. Depending on the output, you can preclude it from "simplifying" the output (ie, force a list output) with

     do.call("mapply", c(myfunc, eg, SIMPLIFY=FALSE))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM