Loop R:创建多个矩阵,在循环之外使用结果,保存多个结果,替代高效解决方案

问题描述 投票:0回答:1

由类别、年份、累积百分比、残差组成的虚拟数据集(=1-Cum.Perc)

年份 班级 类型 暨全氯乙烯 研究
1 A D 0.4 0.6
2 A D 0.7 0.3
3 A D 0.9 0.1
4 A D 0.95 0.05
5 A D 1 0
1 A
2 A …. …. ….
1 B D 0.3 0.7
2 B D 0.6 0.4
3 B D 0.9 0.1
4 B D 0.95 0.05
5 B D 1 0
…. B …. ….

主要问题:

我可以生成一系列矩阵,但我已经使用循环完成了。我需要一些帮助来找到更有效的解决方案。 我找到了一些步骤的解决方法,例如将标签附加到输出上,我认为它们不够强大并且需要改进。 我正在努力访问循环的输出(单个矩阵)。

到目前为止我所做的和存在的问题:

使用循环生成百分比矩阵“X”和分配金额矩阵“Z”。

为每一组创建一个矩阵。每个组都由一组分层变量来标识(为了简单起见,类是虚拟数据中显示的唯一变量)。

问题:

(i) 矩阵已正确创建。但是,如何使用循环的替代选项生成矩阵?例如,我不知道如何将我的代码转换为函数,然后使用

apply()
。您能否帮助找到更有效的选项(也许)不太复杂,以便我可以在必要时进行编辑和控制?

(ii) 要分别对每个组应用相同的计算,我使用命令行

df <- subset(data, Class == k)
。我需要引入额外的分层变量,例如类型(所以我会有 A 类和 D 类、A 类和 I 类、B 类和 D 类等)。我正在考虑为每个子组创建一个唯一的 ID,因此我只需修改代码即可表示
subset(data, NewVar == h)
。或者有更好的办法吗?

问题:

(i) 我需要将循环外部的矩阵导出到:

(i.a) 单独的单独矩阵 – 目前我已成功将导出输出到列表

[output.X[[k]] <- print(round(X,4))]
但我不确定如何自动创建单独的 R 对象,每个对象包含一个矩阵(我可以一次手动创建一个矩阵对象(例如
XA <- output.X$A
);

(i.b) 一个 excel 文件 – 我已经成功做到了,但我目前正在“手动”命名工作表

sheetName=list("A", "B")
,但我需要根据矩阵的名称自动命名工作表,因为我将有 40 个矩阵(当我现场进行时)并且我不能依赖手动归因的标签。

# Create empty objects for loop iterations
X <- matrix(data=0, nrow=5, ncol=5)
Z <- matrix(data=0, nrow=5, ncol=5)
Y <- matrix(data=0, nrow=5, ncol=10)

# Create empty lists for outputs
output.X <- vector("list")
output.Z <- vector("list")
output.Y <- vector("list")

# Create Class list for loop
Class <- list("A", "B")

# Generate cashflows and apportion corresponding values
for (k in Class){
    for (j in 1:5){
        for (i in 1:5){
            df <- subset(data, Class == k)    # Split data set by Class
            df$Incr <- c(df$Cum.Perc[df$Year == 1], diff(df$Cum.Perc)) # Create incremental values
            X[i,j] <- df$Incr[i+j]/df$Res[j]  # Create cashflows
            Z[i,j] <- X[i,j]*df$Amount[j]     # Allocate Amounts
        }
        z <- (j*2)-1
        w <- (j*2)
        Y[ ,z] <- Z[ , j]   # For combined output of Z and X
        Y[ ,w] <- X[ , j]   # For combined output of Z and X
    }
    output.X[[k]] <- print(round(X,4)) # Output
    output.Z[[k]] <- print(round(Z,4)) # Output
    output.Y[[k]] <- print(round(Y,4)) # Output
}
# Save output to excel
write.xlsx(output.X, file="output.X.xlsx", sheetName=list("A", "B"), rowNames=FALSE, append=TRUE) 
write.xlsx(output.Z, file="output.Z.xlsx", sheetName=list("A", "B"), rowNames=FALSE, append=TRUE)
write.xlsx(output.Y, file="output.Y.xlsx", sheetName=list("A", "B"), rowNames=FALSE, append=TRUE)

谢谢你

r loops matrix
1个回答
0
投票

这是一个可能的 tidyverse 解决方案。代码运行,但我无法检查结果,因为您的测试数据集不完整并且您没有提供任何预期的输出。

请注意:

  • 我已将
    data$aAmount
    替换为随机数据,因为您的输入数据中缺少
    Amount
  • 我已重命名您的对象
    T
    以避免与内置
    T
    混淆。
  • 我希望可以简化或删除你的
    i
    j
    循环,但我还没有研究逻辑来理解它们的作用。
library(tidyverse)
library(openxlsx)

classNames <- data %>% distinct(Class) %>% pull(Class)

res <- data %>% 
  group_by(Class) %>% 
  group_map(
    function(.x, .y) {
      X <- matrix(data=0, nrow=5, ncol=5)
      Z <- matrix(data=0, nrow=5, ncol=5)
      T_ <- matrix(data=0, nrow=5, ncol=10)
      for (j in 1:5) {
        for (i in 1:5) {
          .x$Incr <- c(.x$Cum.Perc[.x$Year == 1], diff(.x$Cum.Perc)) # Create incremental values
          X[i,j] <- .x$Incr[i+j]/.x$Res[j]  # Create cashflows
          Z[i,j] <- X[i,j]* rnorm(1)     # Allocate RANDOM Amounts
          # Z[i,j] <- X[i,j]*.x$Amount[j]     # Allocate Amounts
        }
        z <- (j*2)-1
        w <- (j*2)
        T_[ ,z] <- Z[ , j]   # For combined output of Z and X
        T_[ ,w] <- X[ , j]  # For combined output of Z and X
      }
      rv <- list(X = X, Z = Z, T_ = T_)
      # Save output to excel
      for (nm in names(rv)) {
        for (cn in classNames) {
          write.xlsx(rv[[nm]], file=paste0("output.", nm, ".xlsx"), sheetName=cn, rowNames=FALSE, append=TRUE)
        }
      }
      rv
    }
  ) 

res

测试数据

data <- tribble(
  ~Year, ~Class, ~Type, ~Cum.Perc, ~Res,
1,  "A",    "D",    0.4,    0.6,
2,  'A',    "D",    0.7,    0.3,
3,  "A",    "D",    0.9,    0.1,
4,  "A",    'D',    0.95,   0.05,
5,  "A",    "D",    1,  0,
1,  'B',    'D',    0.3,    0.7,
2,  "B",    "D",    0.6,    0.4,
3,  "B",    "D",    0.9,    0.1,
4,  "B",    "D",    0.95,   0.05,
5,  "B",    "D",    1,  0)
© www.soinside.com 2019 - 2024. All rights reserved.