Умножьте массив на другой массив разных измерений в R - PullRequest
0 голосов
/ 29 февраля 2020

Я пытаюсь найти самое эффективное / самое короткое / самое красивое решение для умножения массива на другой массив. Массивы имеют разные размеры.

Я хочу умножить массив consumption (dim = c(4, 5, 4)) на массив emissionFactors, равный dim = c(1, 5, 4). Я хочу, чтобы одно значение столбца в emissionFactors влияло на весь столбец в consumption для каждого измерения. Результат должен быть в том же формате и размерах, что и consumption. Весь необходимый код предоставлен здесь:

Прямо сейчас у меня есть для l oop, который делает эту работу, но я хотел бы избавиться от него. Я пытался использовать sapply, чтобы найти более короткое / красивое решение этой проблемы, но я не мог получить его лучше, чем раньше.

Можно ли сделать это умножение в более короткой форме, сохранив при этом его читабельность?

# needed vars
decades <- c("2020", "2030", "2040", "2050")
energyTypes <- c("Wood", "Fossils", "Ambient energy", "District heating",
                 "Electricity")
housingTypes <- c("Detached houses", "Terraced houses", 
                  "Residential blocks of flats", "Service buildings")

# consumption, array to be multiplied
consumption <- array(0, dim = c(4, 5, 4), dimnames = list(housingTypes, energyTypes, decades))
consumption[1, , 1] <- c(11385, 3148, 4958, 2629, 9607)
consumption[2, , 1] <- c(126, 186, 591, 3105, 1385)
consumption[3, , 1] <- c(47, 543, 81, 13635, 1136)
consumption[4, , 1] <- c(874, 3273, 183, 11902, 2106)
consumption[1, , 2] <- c(7447, 1463, 7114, 1645, 7253)
consumption[2, , 2] <- c(80, 0, 824, 2174, 1132)
consumption[3, , 2] <- c(0, 0, 836, 10355, 810)
consumption[4, , 2] <- c(1085, 1460, 953, 9027, 1810)
consumption[1, , 3] <- c(6256, 295, 7880, 639, 5323)
consumption[2, , 3] <- c(73, 0, 878, 1594, 861)
consumption[3, , 3] <- c(0, 0, 1180, 7767, 686)
consumption[4, , 3] <- c(919, 434, 1788, 6870, 1612)
consumption[1, , 4] <- c(4677, 0, 7686, 131, 4199)
consumption[2, , 4] <- c(53, 0, 811, 1221, 650)
consumption[3, , 4] <- c(0, 0, 1179, 6082, 435)
consumption[4, , 4] <- c(435, 3, 2249, 5328, 1260)

# emissionFactors is the array to multiply with
emissionFactors <- array(0, dim = c(1, 5, 4), dimnames = list("kg", energyTypes, decades))
emissionFactors[1, , 1] <- c(0, 263, 0, 160, 65)
emissionFactors[1, , 2] <- c(0, 263, 0, 76, 31)
emissionFactors[1, , 3] <- c(0, 263, 0, 64, 24)
emissionFactors[1, , 4] <- c(0, 263, 0, 45, 12)

# this array will be populated with the multiplied data from consumption * emissionFactors
emissions <- array(0, dim = c(4, 5, 4), dimnames = list(housingTypes, energyTypes, decades))

# Original version of the multiplying, has an undesired for loop
for (decade in 1:length(decades)) {

  emissions[, , decade] <- 
    consumption[, , decade] %*%
    diag(emissionFactors[, , decade])
}

# An further attempt, not any prettier. I thought one of the functions in the apply family would do the job but I can't get apply to work the way I would want
emissions2 <- sapply(1:dim(consumption)[3],
                     function(i) 
                       consumption[, , i] %*% 
                       diag(emissionFactors[, , i]))
emissions2 <- array(emissions2,
                    c(4, 5, 4),
                    dimnames = list(housingTypes, energyTypes, decades))

Спасибо за любые советы.

Ответы [ 2 ]

1 голос
/ 29 февраля 2020

Повторите указатель в первом измерении 4 раза.

n <- dim(consumption)[1] # 4
result <- consumption * emissionFactors[rep(1, n),, ]
identical(result, emissions)
## [1] TRUE
1 голос
/ 29 февраля 2020

Использовать опцию simplify="array".

sapply(1:length(decades), function(i) 
  `colnames<-`(consumption[, , i] %*% diag(emissionFactors[, , i]),
               colnames(consumption)), simplify="array")
# , , 1
# 
#                             Wood Fossils Ambient energy District heating Electricity
# Detached houses                0  827924              0           420640      624455
# Terraced houses                0   48918              0           496800       90025
# Residential blocks of flats    0  142809              0          2181600       73840
# Service buildings              0  860799              0          1904320      136890
# 
# , , 2
# 
#                             Wood Fossils Ambient energy District heating Electricity
# Detached houses                0  384769              0           125020      224843
# Terraced houses                0       0              0           165224       35092
# Residential blocks of flats    0       0              0           786980       25110
# Service buildings              0  383980              0           686052       56110
# 
# , , 3
# 
#                             Wood Fossils Ambient energy District heating Electricity
# Detached houses                0   77585              0            40896      127752
# Terraced houses                0       0              0           102016       20664
# Residential blocks of flats    0       0              0           497088       16464
# Service buildings              0  114142              0           439680       38688
# 
# , , 4
# 
#                             Wood Fossils Ambient energy District heating Electricity
# Detached houses                0       0              0             5895       50388
# Terraced houses                0       0              0            54945        7800
# Residential blocks of flats    0       0              0           273690        5220
# Service buildings              0     789              0           239760       15120
...