如何正确使用tidyverse包中的map()函数在添加矩阵计算层时?

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

How to use the map() function from the tidyverse package correctly in adding layers of matrix calculations?

问题

我对map()函数感到陌生并遇到了障碍。在下面标为“工作代码”的代码中,它可以正常运行。工作代码将matList列表中的元素扩展为每个系列("mat_One"等)中嵌套在matList中的矩阵小组,并将计算每个矩阵的“Inflows”列,作为嵌套在allocate列表中的各系列向量值与flexVector向量中的值的乘积。

在下面的“失败代码”中,我尝试将产品插入到呈现矩阵的“Due”列中,产品是balVector(没有系列指定)与ratesVector(适用于该系列)的乘积,使用代码行Due = balVector * alc * rates[[names(allocate)]][[.y]],但我收到了错误消息。

我对使用map()函数的方式有什么错误?更一般地说,我需要知道如何使用map()reduce()在各种矩阵和向量之间移动并执行计算。我需要添加更多计算列,其中一些不像map2()那样通过两个向量并行移动。

在下面的图像中,我展示了运行createBucketMap()的输出应该是什么样子。

工作代码:

library(tidyverse)

seriesVector <- function() {c("mat_One", "mat_Two")}
matList <- list(mat_One = c("Boy", "Cat"), mat_Two = c("Boy", "Bat"))
allocate <- list(mat_One = c(0.6, 0.5, 0.4), mat_Two = c(0.4, 0.5, 0.6))
flowVector <- c(6, 5, 4)
balVector <- c(1000, 900, 800)
rates <- list(mat_One = 0.10, mat_Two = 0.20)

createBucketMap <- function() {
  map(allocate, \(alc) alc*flowVector) |>
  map2(matList, \(alc, matL) expand.grid(
    V1 = matL, 
    Inflow = alc,
    Due = 0,
    Cover_due = 0,
    Outflow = 0)
     ) |>
  map(\(dfs) group_split(dfs, V1, .keep = FALSE) |>
        map(as.matrix))  |>
  map2(matList, ~set_names(.x, .y))
}

createBucketMap()

失败代码:

library(tidyverse)

createBucketMap <- function() {
  map(allocate, \(alc) alc * flowVector) |>
    map2(matList, \(alc, matL) expand.grid(
      V1 = matL,
      Inflow = alc,
      Due = balVector * alc * rates[[names(allocate)]][[.y]],
      Cover_due = 0,
      Outflow = 0)
    ) |>
    map(\(dfs) group_split(dfs, V1, .keep = FALSE) |>
          map(as.matrix)) |>
    map2(matList, ~ set_names(.x, .y))
}

createBucketMap()

编辑原文: 添加来自接受答案的代码,但不使用中间数据框,在仅矩阵上运行所有计算:

createBucketMap <- function() {
  imap(matList, \(matL, matL_name) {
    map(matL, \(x) {
      alc <- allocate[[matL_name]]
      rate <- rates[[matL_name]]
      matrix(
        c(flowVector * alc, balVector * alc * rate, rep(0, length(flowVector)), rep(0, length(flowVector))),
        ncol = 4,
        dimnames = list(NULL, c("Inflow", "Due", "Cover_due", "Outflow"))
      )
    }) |>
      set_names(matL)
  })
}

createBucketMap()
英文:

I am new to the map() function and have hit a stumbling block. In the code below denoted as "working code", it works fine. Working code expands the elements in the matList list into a little group of matrices for each series ("mat_One", etc.) embedded in matList and calculates the "Inflows" column of each matrix as the product of the respective series vector values embedded in the allocate list and the value in the flexVector vector.

In the below "Failed code" I am trying to insert into the "Due" columns of the rendered matrices the products of the balVector (no series designation) and the ratesVector (for the applicable series) with the line of code Due = balVector * alc * rates[[names(allocate)]][[.y]], but I get an error message.

What am I doing wrong with my use of the map() function?

More generally, I need to know how to perform calculations by moving through various matrices and vectors using map() and reduce(). I have more calculation columns to add, some of which don't move in parallel through 2 vectors the way that map2() does.

In the image below I show what the output of running createBucketMap() should look like.

如何正确使用tidyverse包中的map()函数在添加矩阵计算层时?

Working code:

library(tidyverse)

seriesVector &lt;- function() {c(&quot;mat_One&quot;, &quot;mat_Two&quot;)}
matList &lt;- list(mat_One = c(&quot;Boy&quot;, &quot;Cat&quot;),mat_Two = c(&quot;Boy&quot;, &quot;Bat&quot;))
allocate &lt;- list(mat_One = c(0.6,0.5,0.4),mat_Two = c(0.4,0.5,0.6))
flowVector &lt;- c(6,5,4)
balVector &lt;- c(1000,900,800)
rates &lt;- list(mat_One = 0.10,mat_Two = 0.20)

createBucketMap &lt;- function(){
  map(allocate, \(alc) alc*flowVector) |&gt;
  map2(matList, \(alc, matL) expand.grid(
    V1 = matL, 
    Inflow = alc,
    Due = 0,
    Cover_due = 0,
    Outflow = 0)
     ) |&gt;
  map(\(dfs) group_split(dfs, V1, .keep = FALSE) |&gt;
        map(as.matrix))  |&gt;
  map2(matList, ~set_names(.x, .y))
}
createBucketMap()

Failed code:

library(tidyverse)
createBucketMap &lt;- function() {
  map(allocate, \(alc) alc * flowVector) |&gt;
    map2(matList, \(alc, matL) expand.grid(
      V1 = matL,
      Inflow = alc,
      Due = balVector * alc * rates[[names(allocate)]][[.y]],
      Cover_due = 0,
      Outflow = 0)
    ) |&gt;
    map(\(dfs) group_split(dfs, V1, .keep = FALSE) |&gt; 
          map(as.matrix)) |&gt;
    map2(matList, ~ set_names(.x, .y))
}
createBucketMap()

Edit OP: add code from the accepted answer but without using an intermediate dataframe, running all calculations on only a matrix:

createBucketMap &lt;- function() {
  imap(matList, \(matL, matL_name) {
    map(matL, \(x) {
      alc &lt;- allocate[[matL_name]]
      rate &lt;- rates[[matL_name]]
      matrix(
        c(flowVector * alc, balVector * alc * rate, rep(0, length(flowVector)), rep(0, length(flowVector))),
        ncol = 4,
        dimnames = list(NULL, c(&quot;Inflow&quot;, &quot;Due&quot;, &quot;Cover_due&quot;, &quot;Outflow&quot;))
      )
    }) |&gt;
      set_names(matL)
  })
}
createBucketMap()

答案1

得分: 3

# 在我看来,你可以大幅简化你的代码,但对于最终结果我有点不确定。在下面的代码中,我首先循环遍历你的`matList`,它已经反映了你所期望的最终列表的嵌套结构。为此,我使用了`imap`,它可以循环遍历列表和列表名称。对于每个列表元素,我使用另一个`map`来循环遍历内部元素并创建矩阵:

createBucketMap <- function() {
  imap(matList, \(matL, matL_name) {
    map(matL, \(x) {
      alc <- allocate[[matL_name]]
      rate <- rates[[matL_name]]
      data.frame(
        Inflow = flowVector * alc,
        Due = balVector * alc * rate,
        Cover_due = 0,
        Outflow = 0
      ) |> as.matrix()
    }) |> set_names(matL)
  })
}

createBucketMap()
#> $mat_One
#> $mat_One$Boy
#>      Inflow Due Cover_due Outflow
#> [1,]    3.6  60         0       0
#> [2,]    2.5  45         0       0
#> [3,]    1.6  32         0       0
#> 
#> $mat_One$Cat
#>      Inflow Due Cover_due Outflow
#> [1,]    3.6  60         0       0
#> [2,]    2.5  45         0       0
#> [3,]    1.6  32         0       0
#> 
#> 
#> $mat_Two
#> $mat_Two$Boy
#>      Inflow Due Cover_due Outflow
#> [1,]    2.4  80         0       0
#> [2,]    2.5  90         0       0
#> [3,]    2.4  96         0       0
#> 
#> $mat_Two$Bat
#>      Inflow Due Cover_due Outflow
#> [1,]    2.4  80         0       0
#> [2,]    2.5  90         0       0
#> [3,]    2.4  96         0       0
英文:

A bit unsure about your final result but IMHO you could simplify your code considerably. In the code below I first loop over your matList which already reflects the nested structure of your desired final list. To this end I use imap which loops over both the list and the list names. For each list element I use another map to loop over the inner elements and to create the matrices:

library(tidyverse)

createBucketMap &lt;- function() {
  imap(matList, \(matL, matL_name) {
    map(matL, \(x) {
      alc &lt;- allocate[[matL_name]]
      rate &lt;- rates[[matL_name]]
      data.frame(
        Inflow = flowVector * alc,
        Due = balVector * alc * rate,
        Cover_due = 0,
        Outflow = 0
      ) |&gt;
        as.matrix()
    }) |&gt;
      set_names(matL)
  })
}

createBucketMap()
#&gt; $mat_One
#&gt; $mat_One$Boy
#&gt;      Inflow Due Cover_due Outflow
#&gt; [1,]    3.6  60         0       0
#&gt; [2,]    2.5  45         0       0
#&gt; [3,]    1.6  32         0       0
#&gt; 
#&gt; $mat_One$Cat
#&gt;      Inflow Due Cover_due Outflow
#&gt; [1,]    3.6  60         0       0
#&gt; [2,]    2.5  45         0       0
#&gt; [3,]    1.6  32         0       0
#&gt; 
#&gt; 
#&gt; $mat_Two
#&gt; $mat_Two$Boy
#&gt;      Inflow Due Cover_due Outflow
#&gt; [1,]    2.4  80         0       0
#&gt; [2,]    2.5  90         0       0
#&gt; [3,]    2.4  96         0       0
#&gt; 
#&gt; $mat_Two$Bat
#&gt;      Inflow Due Cover_due Outflow
#&gt; [1,]    2.4  80         0       0
#&gt; [2,]    2.5  90         0       0
#&gt; [3,]    2.4  96         0       0

huangapple
  • 本文由 发表于 2023年6月12日 15:48:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/76454544.html
匿名

发表评论

匿名网友

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

确定