Skip to content

Commit bb13348

Browse files
author
WesIngwersen
committed
Revise aggregateMatrix to use matrix algebra
1 parent b042a75 commit bb13348

File tree

1 file changed

+33
-20
lines changed

1 file changed

+33
-20
lines changed

R/UtilityFunctions.R

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ joinStringswithSlashes <- function(...) {
2323
return(str)
2424
}
2525

26-
#' Aggregate matrix by rows then by columns
26+
#' Aggregate matrix from one BEA level to another by rows and columns
2727
#'
2828
#' @param matrix A matrix
2929
#' @param from_level The level of BEA code this matrix starts at
@@ -34,25 +34,38 @@ aggregateMatrix <- function (matrix, from_level, to_level, model) {
3434
# Determine the columns within MasterCrosswalk that will be used in aggregation
3535
from_code <- paste0("BEA_", from_level)
3636
to_code <- paste0("BEA_", to_level)
37-
# Aggregate by rows
38-
value_columns_1 <- colnames(matrix)
39-
df_fromlevel <- merge(matrix, unique(model$crosswalk[, c(from_code, to_code)]),
40-
by.x = 0, by.y = from_code)
41-
df_fromlevel_agg <- stats::aggregate(df_fromlevel[, value_columns_1],
42-
by = list(df_fromlevel[, to_code]), sum)
43-
rownames(df_fromlevel_agg) <- df_fromlevel_agg[, 1]
44-
df_fromlevel_agg[, 1] <- NULL
45-
# aggregate by columns
46-
value_columns_2 <- rownames(df_fromlevel_agg)
47-
df_fromlevel_agg <- merge(t(df_fromlevel_agg),
48-
unique(model$crosswalk[, c(from_code, to_code)]),
49-
by.x = 0, by.y = from_code)
50-
matrix_fromlevel_agg <- stats::aggregate(df_fromlevel_agg[, value_columns_2],
51-
by = list(df_fromlevel_agg[, to_code]), sum)
52-
# reshape back to orginal CxI (IxC) format
53-
rownames(matrix_fromlevel_agg) <- matrix_fromlevel_agg[, 1]
54-
matrix_fromlevel_agg <- t(matrix_fromlevel_agg[, -1])
55-
return(matrix_fromlevel_agg)
37+
38+
#Clean up matrix, remove location from row and col names
39+
rownames_before <- rownames(matrix)
40+
colnames_before <- colnames(matrix)
41+
rownames(matrix) <- gsub("/.*","",rownames(matrix))
42+
colnames(matrix) <- gsub("/.*","",colnames(matrix))
43+
44+
# Get crosswalk for full matching between schema
45+
cw <- unique(model$crosswalk[, c(from_code, to_code)])
46+
cw$one <- 1
47+
48+
# Build row aggregation matrix
49+
row_cw <- cw[cw[,from_code] %in% rownames(matrix),]
50+
identical(row.names(row_cw),)
51+
52+
# Cast row crosswalk into a correspondence matrix of 1s
53+
Xl <- reshape2::acast(row_cw,as.formula(paste(to_code,"~",from_code)),value.var = "one", fill = 0)
54+
55+
#! Check ordering
56+
Xl <- Xl[,order(rownames(matrix))]
57+
identical(colnames(Xl),rownames(matrix))
58+
59+
# Build col aggregation matrix
60+
col_cw<- cw[cw[,from_code] %in% colnames(matrix),]
61+
62+
# Cast row crosswalk into a correspondence matrix of 1s
63+
Xr <- reshape2::acast(col_cw,as.formula(paste(from_code,"~",to_code)),value.var = "one", fill = 0)
64+
65+
# Matrix multiply to perform aggregation
66+
matrix_agg <- Xl %*% matrix %*% Xr
67+
68+
return(matrix_agg)
5669
}
5770

5871
#' Generate Output Ratio table, flexible to Commodity/Industry output and model Commodity/Industry type

0 commit comments

Comments
 (0)