由类别、年份、累积百分比、残差组成的虚拟数据集(=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)
谢谢你
这是一个可能的 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)