【问题标题】:Eliminate the need for a loop in a simple example在一个简单的例子中消除对循环的需要
【发布时间】:2022-01-13 17:27:36
【问题描述】:

我目前正在使用循环解决一个问题,但有些事情告诉我,可以不这样做。我认为可行的主要原因是所有外生过程在时间 0 时都是已知的。

基本上,有两个余额,a 和 b,会随着时间的推移而耗尽。假设 1 从 800 开始,一个从 200 开始。每个时期,有两个外生过程 x 和 y。 X 耗尽余额 a 和 b 与其总余额成比例。 Y直接耗尽y直到为0,然后耗尽x。

例如,周期 1:x = 10y = 5。期末a = 800 - .8 * 10 = 792, y = 200 - .2 * 10 - 5 =193。下一个时期,x 的乘数发生了变化。现在 a 为 792/985,y 为 193/995。

这是一个使用循环的非常简单的例子:

data <- data.frame(start_a = NA, start_b = NA, proportion = NA, x = runif(10, 1, 50), y = runif(10, 1, 50), end_a = NA, end_b = NA)

for (i in 1:(nrow(data))){
    data$start_a[i] <- ifelse(i==1, 800, data$end_a[i-1])

    data$start_b[i] <- ifelse(i==1, 200, data$end_b[i-1])

    data$proportion[i] <- data$start_a[i]/(data$start_a[i] + data$start_b[i])

    data$end_a[i] <- data$start_a[i] - data$proportion[i]*data$x[i] -

    ifelse((data$start_b[i] - (1-data$proportion[i])*data$x[i])<= data$y[i], data$y[i] - data$start_b[i] - (1-data$proportion[i])*data$x[i], 0)

    data$end_b[i] <- data$start_b[i] - (1-data$proportion[i])*data$x[i] - min(data$y[i], data$start_b[i] - (1-data$proportion[i])*data$x[i])
}

再一次,x 和 y 的完整时间历史在开始时是已知的,所以我有直觉认为不需要循环。

【问题讨论】:

  • 可能不会。 data$end_ai[i] 和 data$end_b[i] 的值在循环的一个步骤中计算并用于下一步。对于矢量化,所有值必须在操作开始时已知。另外,你不应该在循环中使用ifelse,因为它是矢量化的,而是if(...) {...} else {...}

标签: r loops


【解决方案1】:

添加到@jblood94 答案以对 x 和 y 使用随机向量

n1 <- length(cumsum(y)[cumsum(y) < b])
aOut <- c(a+b, a + b -cumsum(x+y), 0)
aOut <- aOut[aOut > 0]
a1 <- c(a, a*cumprod(1 - x[1:n1]/aOut[1:n1]))
b1 <- aOut[1:length(a1)] - a1
idx <- match(TRUE, b1 < 0) - 1L
bOut <- c(b1[1:idx], rep(0, length(aOut) - idx))
aOut[1:idx] <- a1[1:idx]
output = data.frame(a = aOut, b = bOut)

【讨论】:

    【解决方案2】:

    根据你的解释,这是一个使用矢量化来获取ab的函数:

    fSeries <- function(a, b, x, y) {
      n1 <- b%/%y
      aOut <- seq(a + b, 0, -x - y)
      a1 <- c(a, a*cumprod(1 - x/aOut[1:n1]))
      b1 <- aOut[1:length(a1)] - a1
      idx <- match(TRUE, b1 < 0) - 1L
      bOut <- c(b1[1:idx], rep(0, length(aOut) - idx))
      aOut[1:idx] <- a1[1:idx]
      return(data.frame(a = aOut, b = bOut))
    }
    
    df <- fSeries(800, 200, 10, 5)
    list(head = head(df), tail = tail(df))
    #> $head
    #>          a        b
    #> 1 800.0000 200.0000
    #> 2 792.0000 193.0000
    #> 3 783.9594 186.0406
    #> 4 775.8773 179.1227
    #> 5 767.7530 172.2470
    #> 6 759.5854 165.4146
    #> 
    #> $tail
    #>     a b
    #> 62 85 0
    #> 63 70 0
    #> 64 55 0
    #> 65 40 0
    #> 66 25 0
    #> 67 10 0
    

    【讨论】:

    • 这太棒了。非常感谢 - 大多数人放弃了,因为他们在我的循环中看到了一个 i-1,但这实际上是一个数学问题,而不是一个编码问题,而你已经解决了。我做了一些调整,对 x 或 y 使用随机过程,而不是常数
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-31
    • 2020-11-25
    • 2011-09-03
    • 2023-03-25
    • 2015-09-30
    • 2019-02-21
    • 1970-01-01
    相关资源
    最近更新 更多