如何在一个逐行处理矩阵的for循环中包含一些列向计算?

huangapple go评论82阅读模式
英文:

How to include some column-wise calculations in a for-loop that is otherwise working its way through a matrix row-wise?

问题

在下面的myFunction()代码中,我正在尝试扩展它,以包括对函数生成的矩阵同一行中进行计算,否则会执行逐列计算的for循环。在渲染矩阵的“Draw_...”列中的任何金额都必须减去同一行左侧列中以“Draw...”开头的列中的值。有没有关于如何实现这一点的想法?

请注意,在从中提取此示例的完整代码中,“Draw_...”项的数量会根据函数参数的不同而变化,因此对Draw_Cl_ADraw_Cl_B等的引用不能硬编码,必须是动态的,就像下面的代码提供的那样。

以下输出显示了代码当前生成的内容以及我希望它生成的内容:

当前输出:

     Inflow Target Top_up Draw_Cl_A Draw_Cl_B Draw_Cl_C
[1,]    3.6   12.0    3.6       1.0       3.0       0.5
[2,]    2.5    9.0    2.5       2.0       2.0       0.6
[3,]  160.0    6.4   15.5       2.9       2.9       2.9

期望输出:

     Inflow Target Top_up Draw_Cl_A Draw_Cl_B Draw_Cl_C  | 注意事项(运行代码时不要呈现!!)         |
[1,]    3.6   12.0    3.6       1.0       2.6       0.0  | 第1行:Draw_Cl_B和Draw_Cl_B与上面相比有所变化 |
[2,]    2.5    9.0    2.5       2.0       0.5       0.0  | 第2行:Draw_Cl_B和Draw_Cl_B与上面相比有所变化 |
[3,]  160.0    6.4   12.5       3.0       9.5       0.0  | 第2行:Draw_Cl_B和Draw_Cl_B与上面相比有所变化 |

上述期望输出的注释解释如下:

如何在一个逐行处理矩阵的for循环中包含一些列向计算?

代码:

serAlloc <- c(0.6, 0.5, 0.4)
inFlow <- c(6, 5, 400) 
balance <- c(1000, 900, 800)
rsv <- list(
  Target = 0.02,
  Floor = 0.005,
  Cl = c("A", "B", "C")
)
rsvTarget <- list(
  A = c(1,2,3),
  B = c(3,2,18),
  C = c(0.5,0.6,7)
)

myFunction <- function(nbr_rows) {
  mat <- matrix(0, nbr_rows, length(rsv$Cl) + 3)
  colnames(mat) <- c(
    'Inflow',
    'Target',
    'Top_up',
    paste0('Draw_Cl_', rsv$Cl)
  )
  
  for (k in 1:nbr_rows) {
    trackBal <- balance[k]
    serPct <- serAlloc[k]
    serInflow <- inFlow[k]
    mat[k, "Inflow"] <- serPct * serInflow
    
    # 计算所有“cl”之前的当前行的累积提取,通过在列名中识别“Draw”来实现
    cum_draws_lag <- if(k == 1){0} else {sum(mat[1:k-1, grepl("^Draw", colnames(mat)))}
    
    mat[k, "Target"] <- trackBal * serPct * rsv$Target
    mat[k, "Top_up"] <- min(mat[k, "Inflow"], mat[k, "Target"] + cum_draws_lag)
    
    for (cl_name in rsv$Cl) {
      target_draw <- rsvTarget[[cl_name]][[k]]
      draw <- min(target_draw,cumsum(mat[1:k,"Target"])-cum_draws_lag)
      mat[k, paste0("Draw_Cl_", cl_name)] <- draw
    }
  }
  return(mat)
}
myFunction(3)
英文:

In the code below for myFunction(), I'm trying to expand it to include calculations along the same row of the function-generated matrix where a for-loop is otherwise performing column-wise calculations. Any amounts in the "Draw_..." columns of the rendered matrix have to be reduced by the values in the columns to the left along the same row that also begin with "Draw...". Any ideas for how to do this?

Note that in the full code this example is extracted from, the number of "Draw_..." items vary based on function parameters so the references to Draw_Cl_A, Draw_Cl_B, etc., can't be hardwired but must be dynamic as the below code provides.

The outputs below shows what the code currently generates and what I would like to it to generate:

Current output:

     Inflow Target Top_up Draw_Cl_A Draw_Cl_B Draw_Cl_C
[1,]    3.6   12.0    3.6       1.0       3.0       0.5
[2,]    2.5    9.0    2.5       2.0       2.0       0.6
[3,]  160.0    6.4   15.5       2.9       2.9       2.9

Desired output:

     Inflow Target Top_up Draw_Cl_A Draw_Cl_B Draw_Cl_C  | Notes (NOT TO RENDER WHEN RUNNINGCODE!!)         |
[1,]    3.6   12.0    3.6       1.0       2.6       0.0  | Row 1: Draw_Cl_B and Draw_Cl_B change from above |
[2,]    2.5    9.0    2.5       2.0       0.5       0.0  | Row 2: Draw_Cl_B and Draw_Cl_B change from above |
[3,]  160.0    6.4   12.5       3.0       9.5       0.0  | Row 2: Draw_Cl_B and Draw_Cl_B change from above |

Explanations for above Notes for desired outputs:
如何在一个逐行处理矩阵的for循环中包含一些列向计算?

Code:

serAlloc &lt;- c(0.6, 0.5, 0.4)
inFlow &lt;- c(6, 5, 400) 
balance &lt;- c(1000, 900, 800)
rsv &lt;- list(
  Target = 0.02,
  Floor = 0.005,
  Cl = c(&quot;A&quot;, &quot;B&quot;, &quot;C&quot;)
)
rsvTarget &lt;- list(
  A = c(1,2,3),
  B = c(3,2,18),
  C = c(0.5,0.6,7)
)

myFunction &lt;- function(nbr_rows) {
  mat &lt;- matrix(0, nbr_rows, length(rsv$Cl) + 3)
  colnames(mat) &lt;- c(
    &#39;Inflow&#39;,
    &#39;Target&#39;,
    &#39;Top_up&#39;,
    paste0(&#39;Draw_Cl_&#39;, rsv$Cl)
  )
  
  for (k in 1:nbr_rows) {
    trackBal &lt;- balance[k]
    serPct &lt;- serAlloc[k]
    serInflow &lt;- inFlow[k]
    mat[k, &quot;Inflow&quot;] &lt;- serPct * serInflow
    
    # calculate cumulative draws for all &quot;cl&quot; prior to the current row by identifying &quot;Draw&quot; in col name
    cum_draws_lag &lt;- if(k == 1){0} else {sum(mat[1:k-1, grepl(&quot;^Draw&quot;, colnames(mat))])}
    
    mat[k, &quot;Target&quot;] &lt;- trackBal * serPct * rsv$Target
    mat[k, &quot;Top_up&quot;] &lt;- min(mat[k, &quot;Inflow&quot;], mat[k, &quot;Target&quot;] + cum_draws_lag)
    
    for (cl_name in rsv$Cl) {
      target_draw &lt;- rsvTarget[[cl_name]][[k]]
      draw &lt;- min(target_draw,cumsum(mat[1:k,&quot;Target&quot;])-cum_draws_lag)
      mat[k, paste0(&quot;Draw_Cl_&quot;, cl_name)] &lt;- draw
    }
  }
  return(mat)
}
myFunction(3)

答案1

得分: 1

这里是一个解决方案。解决这个问题的关键部分是找出如何将当前正在计算的for循环中的矩阵单元格左侧的列隔离出来(请参见下面代码中的subCols),并使用grepl()函数进一步将那些以“Draw”开头命名的列进一步子集化为左侧的列。然后对这些子集列(和行)中的值进行求和。下面代码中的subColssumDraws对象解决了这个问题并讲述了整个过程。请注意,还需要对OP代码进行其他小的修复,例如将cumsum()替换为sum(),将cumsum()中的引用(已更改为sum())从“Target”更改为“Top-up”。在这个示例中使用for循环的好处是,您可以耐心地逐行分开运行每一行代码;我无法想象使用lapply()map()来做这种事情。

myFunction <- function(nbr_rows) {
  mat <- matrix(0, nbr_rows, length(rsv$Cl) + 3)
  colnames(mat) <- c(
    'Inflow',
    'Target',
    'Top_up',
    paste0('Draw_Cl_', rsv$Cl)
  )
  
  for (k in 1:nbr_rows) {
    trackBal <- balance[k]
    serPct <- serAlloc[k]
    serInflow <- inFlow[k]
    mat[k, "Inflow"] <- serPct * serInflow
    
    # calculate cumulative draws for all "cl" prior to the current row by identifying "Draw" in col name
    cum_draws_lag <- if(k == 1){0} else {sum(mat[1:k-1, grepl("^Draw", colnames(mat)))}
    
    mat[k, "Target"] <- trackBal * serPct * rsv$Target
    mat[k, "Top_up"] <- min(mat[k, "Inflow"], mat[k, "Target"] + cum_draws_lag)
    
    for (cl_name in rsv$Cl) {
      target_draw <- rsvTarget[[cl_name]][[k]]
      subCols <- which(rsv$Cl==cl_name)+3-1 # subset columns to the left of current column
      sumDraws <- sum(mat[k,1:subCols][grepl("^Draw", colnames(mat)[1:subCols])]) # sum "Draws" of cols to the left
      draw <- min(target_draw,sum(mat[1:k,"Top_up"])-cum_draws_lag - sumDraws)
      mat[k, paste0("Draw_Cl_", cl_name)] <- draw
    }
  }
  return(mat)
}
myFunction(3)
英文:

Here's a solution. The key part to solving this was figuring out how to isolate columns to the left of the matrix cell that is currently being calculated in the for-loop (see subCols in the code below) and using the grepl() function to further subset those columns to the left of the matrix cell into those columns starting with "Draw" in their names. The values in those subset columns (and rows) are then summed. Objects subCols and sumDraws in the code below solved this issue and tell the story. Note that there were other little fixes required from the OP code, such replacing the cumsum() with sum(), changing a reference in that cumsum() (that was changed to sum()) from "Target" to "Top-up". The nice thing about for-loops like in this example is that you can patiently walk through and run every single line of code separately; I can't imagine doing this sort of thing with lapply() or map().

Code:

myFunction &lt;- function(nbr_rows) {
  mat &lt;- matrix(0, nbr_rows, length(rsv$Cl) + 3)
  colnames(mat) &lt;- c(
    &#39;Inflow&#39;,
    &#39;Target&#39;,
    &#39;Top_up&#39;,
    paste0(&#39;Draw_Cl_&#39;, rsv$Cl)
  )
  
  for (k in 1:nbr_rows) {
    trackBal &lt;- balance[k]
    serPct &lt;- serAlloc[k]
    serInflow &lt;- inFlow[k]
    mat[k, &quot;Inflow&quot;] &lt;- serPct * serInflow
    
    # calculate cumulative draws for all &quot;cl&quot; prior to the current row by identifying &quot;Draw&quot; in col name
    cum_draws_lag &lt;- if(k == 1){0} else {sum(mat[1:k-1, grepl(&quot;^Draw&quot;, colnames(mat))])}
    
    mat[k, &quot;Target&quot;] &lt;- trackBal * serPct * rsv$Target
    mat[k, &quot;Top_up&quot;] &lt;- min(mat[k, &quot;Inflow&quot;], mat[k, &quot;Target&quot;] + cum_draws_lag)
    
    for (cl_name in rsv$Cl) {
      target_draw &lt;- rsvTarget[[cl_name]][[k]]
      subCols &lt;- which(rsv$Cl==cl_name)+3-1 # subset columns to the left of current column
      sumDraws &lt;- sum(mat[k,1:subCols][grepl(&quot;^Draw&quot;, colnames(mat)[1:subCols])]) # sum &quot;Draws&quot; of cols to the left
      draw &lt;- min(target_draw,sum(mat[1:k,&quot;Top_up&quot;])-cum_draws_lag - sumDraws)
      mat[k, paste0(&quot;Draw_Cl_&quot;, cl_name)] &lt;- draw
    }
  }
  return(mat)
}
myFunction(3)

huangapple
  • 本文由 发表于 2023年6月16日 01:39:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/76484224.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定