创建具有前一列功能的列的表的更好方法?

0 r dplyr

使用R,我想创建一个包含10,000个场景(行)和50个列的表,表示年度投资组合余额.每列的值应等于前一列的值减去一定的支出(例如,每年40,000美元),然后乘以随机生成的市场收益(表示为增长率).所有情景余额在零年开始时为1,000,000美元.

例如,市场在第1年回报率为6%(增长率为1.06).投资者有100万美元,花费40,000美元,留下960,000美元,然后赚取6%,留下一年的余额1,017,600美元.以下栏目(年份)以1,017,600美元开始,花费40,000美元,然后应用新的随机市场回报创建第二年余额.我重复50列(年)并重复该过程10,000个50年的情景.

我这样做循环如下:

# Set initial values

set.seed(27514)
n <- 10000 # number of scenarios
mu <- .05 # market return expectation
sigma <- .12 # market return volatility
portfolio <- 1000000 # $1,000000
yrs <- 50 # years of market returns and corresponding portfolio balances
spend <- 40000 # dollar amount to spend annually
balances <- matrix(nrow=n,ncol=yrs)


# function newbalance returns a portfolio balance for the current year (column) by subtracting an amount spent from the portfolio's
# previous balance (column - 1) and then applying the current year's market return to the remaining balance. If the
# new balance is negative, it is changed to zero.

newBalance <- function (lastYearBal,currentReturn,spend) { max(0,(lastYearBal - spend) * currentReturn) }

# Create table of n rows and (yrs = 50) columns of random market returns, expressed as growth rates (1.0 plus return)

marketReturns <- matrix(rlnorm(n*yrs,mu,sigma), n, yrs) 

# Create 50 columns of n rows of portfolio balances based on the market returns matrix and constant annual spending = spend

for (i in 1:n) {
  for (j in 1:yrs) {
    if (j == 1) {oldBalance <- portfolio} 
    else {oldBalance <- balances[i,j-1]}
    balances[i,j] <- newBalance(oldBalance,marketReturns[i,j],spend)
  }
}
Run Code Online (Sandbox Code Playgroud)

我正在寻找一种"更好"的方式来做到这一点,并且更好的意思是1)更清楚的是有人理解代码,2)更快,并且,希望,3)两者.

我刚刚开始使用dplyr并想知道是否有办法用Mutate做这个,也许.

建议大加赞赏.

Fra*_*ank 5

除了不进行矢量化之外,OP的循环是可以的max.我会把它写成

do.call(cbind,
Reduce( 
  function(x,y) pmax(0, (x - spend)*y), 
  as.data.frame(marketReturns), 
  init = portfolio, 
  accumulate = TRUE
)[-1]
)
Run Code Online (Sandbox Code Playgroud)

这使

          [,1]      [,2]      [,3]      [,4]      [,5]
 [1,] 1225023.5 1356133.0 1411918.2 1422467.3 1333403.1
 [2,]  886324.3 1116834.2 1393490.6 1290055.2 1188176.0
 [3,] 1263106.3 1211609.4 1187170.0 1256445.9 1129850.1
 [4,]  751897.5  749431.7  637428.4  717144.9  795654.3
 [5,]  972910.2  832125.1  852293.3  717697.8  664908.3
 [6,]  994046.2  922805.8  880951.7  814622.0  674656.3
 [7,] 1077494.7  970762.1 1097041.3  963056.8  834362.0
 [8,] 1034696.9 1145020.8 1132916.7 1292145.0 1567837.9
 [9,] 1042336.3 1107492.6 1204792.5 1196458.1  991649.2
[10,]  860172.0  830692.4  934326.0  945027.2  932220.1
Run Code Online (Sandbox Code Playgroud)

Reduce 是标题中问题的一个非常标准的工具:

创建具有前一列功能的列的表的更好方法?

Reduce迭代列表; 所以as.data.frame上面用来转换marketReturns成列的列表(也称为一个data.frame).pmax(...)从相同长度的多个向量中获取项目的"并行最大值".标量喜欢0并且portfolio默默地"回收"成为适当长度的载体.


在旁边.这个问题可以说比StackOverflow 更适合代码审查.虽然它是可重复的,但是示例数据太大而无法显示和检查这里的帖子,所以我已切换到n=10,yrs=5.

  • 我永远不会理解这个`Reduce`,`Filter`,`Negate`等等.无论如何+ 1! (2认同)