在一个简单的例子中消除对循环的需要

Posted

技术标签:

【中文标题】在一个简单的例子中消除对循环的需要【英文标题】: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 ... 【参考方案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 使用随机过程,而不是常数

以上是关于在一个简单的例子中消除对循环的需要的主要内容,如果未能解决你的问题,请参考以下文章

如何从阻力网络中消除循环

如何在opengl游戏循环中使用双核?

简单的例子进入无限循环

EBNF形式的简单编程语言

FastReport最简单的一个C#例子(传个参数)

JWT 如何消除对每个请求进行数据库查找的需要?