R函数的选择性`for`循环:`for`循环或`Vectorize`

时间:2017-12-08 23:58:28

标签: r function for-loop vectorization

我有一个名为{ "type": "https://example.com/probs/out-of-credit", "title": "You do not have enough credit.", "detail": "Your current balance is 30, but that costs 50.", "instance": "/account/12345/msgs/abc", "balance": 30, "accounts": ["/account/12345", "/account/67890"] } 的小R函数。我正在尝试允许该函数的用户为参数abvector(不是两者)提供m

问题: 我想知道如何设置s循环,以便根据用户的选择选择性地循环form? [在这里使用s会更好吗?]

这是我的R代码没有成功:

Vectorize

2 个答案:

答案 0 :(得分:2)

一想法:

ab <- function(m, s, lo = -Inf, hi = Inf) {
  if (length(m) > 1) {
    if (length(s) > 1) {
      warning("'m' and 's' are both long, truncating 's'")
    }
    s <- rep(s[1], length(m))
  } else {
    m <- rep(m, length(s))
  }
  # something else here ...
}

所有这一切都是确保两个变量的长度相同,从而迫使一个变量成为不变的变量。 (我认为这就是你要做的......)

我认为你不能有效地对基本计算进行矢量化,因为(除其他事项外)integrate确实需要一次处理一个问题。为了改进任何事情,我可能会建议进行所有计算并将所有值都返回到单个列表中。从那里开始,单独绘制线条非常简单:

ab <- function(m, s, lo = -Inf, hi = Inf,
               xrange = c(-3, 3), n = 50) {
  if (length(m) > 1) {
    if (length(s) > 1) {
      warning("'m' and 's' are both long, truncating 's'")
    }
    s <- rep(s[1], length(m))
  } else {
    m <- rep(m, length(s))
  }
  xs <- seq(xrange[1], xrange[2], length = n)
  out <- mapply(function(a,b) {
    p = function(x) dnorm(x, a, b)
    f = function(x) p(x) / integrate(p, lo, hi)[[1]]
    list(x = xs, y = sapply(xs, f))
  }, m, s, SIMPLIFY = FALSE)
  out
}
ret <- ab(m = c(0, .5), s = 1)
str(ret)
# List of 2
#  $ :List of 2
#   ..$ x: num [1:50] -3 -2.88 -2.76 -2.63 -2.51 ...
#   ..$ y: num [1:50] 0.00443 0.00635 0.00897 0.01247 0.01709 ...
#  $ :List of 2
#   ..$ x: num [1:50] -3 -2.88 -2.76 -2.63 -2.51 ...
#   ..$ y: num [1:50] 0.000873 0.00133 0.001996 0.002951 0.004298 ...

从这里开始,你应该能够一次性地绘制所有内容:

yrange <- c(0, max(sapply(ret, `[[`, "y")))
plot(0, type = 'n', xlim = c(-3,3), ylim = yrange,
     ylab = "Density", xlab = "Z")
ign <- mapply(function(d,i) lines(y~x, data=d, col=i),
              ret, seq_along(ret))

sample dnorm curves

计算部分与绘图部分分开,通常有利于(恕我直言)计算速度,无需重新计算的情节再现以及代码组织。

答案 1 :(得分:0)

我非常感谢我们的同事@r2evans给出了答案,但我认为这个问题可能有一个更简单的解决方案(即一行if语法):

ab = function(m, s, lo = -Inf, hi = Inf){

loop = if(length(m) > 1) length(m) else length(s)

p = if(length(m) > 1) function(x) dnorm(x, m[i], s) else function(x) dnorm(x, m, s[i])

for(i in 1:loop){
f = function(x) p(x)/integrate(p, lo, hi)[[1]]
curve(f, -3, 3, add = i!= 1, col = i)
 }
}
# Example of use:
ab(m = c(0, 1), 1)
#Example of use:
ab(m = 0, c(1, 2))

enter image description here