将 are 中的所有矩阵组合相加,以便我稍后可以调用名称

Adding together all combinations of matrices in R so I can call the names later

提问人:Rosalin August 提问时间:11/8/2023 更新时间:11/9/2023 访问量:81

问:

我有几个计数变量矩阵,我们可以表示如下:

P <- matrix(c(1, 2 ,0, 2, 5, 1, 0, 6, 1), nrow = 3)
Q <- matrix(c(1, 0, 0, 2, 3, 1, 0, 4, 1), nrow = 3)
R <- matrix(c(2, 1, 1, 5, 6, 4, 0, 4, 1), nrow = 3)
S <- matrix(c(9, 7, 5, 4, 7, 3, 2, 6, 3), nrow = 3)

我想创建将这些矩阵相加的所有组合。例如。P+Q、P+R、P+S、Q+R、Q+S、R+S、P+Q+R、P+R+S、P+Q+S、Q+R+S...

我知道如何手动运行它:

PQ <-P+Q

> PQ
     [,1] [,2] [,3]
[1,]    2    4    0
[2,]    2    8   10
[3,]    0    2    2

PQR <- P+Q+R

> PQR
     [,1] [,2] [,3]
[1,]    4    9    0
[2,]    3   14   14
[3,]    1    6    3

但是我的真实数据集有 9 个矩阵,这意味着 501 个组合,这需要很长时间才能写出来。

所以我试了一下:

# generate all possible combinations of the matrices
combs <- combn(list(P, Q, R, S), 2, simplify = FALSE)

print(combs)

# sum the matrices in each combination
sums <- lapply(combs, function(x) Reduce("+", x))


# print the result
print(sums)

一方面,这似乎确实可以使所有组合都起作用。但它不允许我知道哪个组合是哪个。

如何将所有矩阵相加,并确保名称反映要添加的矩阵,以便以后可以调用它们?

R 矩阵 组合

评论


答:

2赞 ThomasIsCoding 11/8/2023 #1

您可以尝试以下代码

lst <- list(P = P, Q = Q, R = R, S = S)
out <- do.call(
    c,
    lapply(
        2:length(lst),
        \(k) unlist(
            combn(lst,
                k, \(...)
                setNames(
                    list(Reduce(`+`, ...)),
                    paste0(names(...), collapse = "")
                ),
                simplify = FALSE
            ),
            recursive = FALSE
        )
    )
)

哪里给out

$PQ
     [,1] [,2] [,3]
[1,]    2    4    0
[2,]    2    8   10
[3,]    0    2    2

$PR
     [,1] [,2] [,3]
[1,]    3    7    0
[2,]    3   11   10
[3,]    1    5    2

$PS
     [,1] [,2] [,3]
[1,]   10    6    2
[2,]    9   12   12
[3,]    5    4    4

$QR
     [,1] [,2] [,3]
[1,]    3    7    0
[2,]    1    9    8
[3,]    1    5    2

$QS
     [,1] [,2] [,3]
[1,]   10    6    2
[2,]    7   10   10
[3,]    5    4    4

$RS
     [,1] [,2] [,3]
[1,]   11    9    2
[2,]    8   13   10
[3,]    6    7    4

$PQR
     [,1] [,2] [,3]
[1,]    4    9    0
[2,]    3   14   14
[3,]    1    6    3

$PQS
     [,1] [,2] [,3]
[1,]   11    8    2
[2,]    9   15   16
[3,]    5    5    5

$PRS
     [,1] [,2] [,3]
[1,]   12   11    2
[2,]   10   18   16
[3,]    6    8    5

$QRS
     [,1] [,2] [,3]
[1,]   12   11    2
[2,]    8   16   14
[3,]    6    8    5

$PQRS
     [,1] [,2] [,3]
[1,]   13   13    2
[2,]   10   21   20
[3,]    6    9    6

如果要创建变量,如名称所示,可以进一步使用PQPQRoutlist2env

list2env(out, envir = .GlobalEnv)
5赞 G. Grothendieck 11/8/2023 #2

1)创建一个命名列表,首先计算总和,然后添加名称。

L <- list(P = P, Q = Q, R = R, S = S)

make_sums <- function(x, n) {
  y <- combn(x, n, Reduce, f = `+`, simplify = FALSE)
  names(y) <- combn(names(x), n, paste, collapse = "+")
  y
}

Sums <- c( make_sums(L, 2), make_sums(L, 3) )

2)另一种可能性是使用列表推导式。 是从上面来的。第一个参数定义名称,第二个参数定义值。Lgen.named.list

library(listcompr)

Sums2 <- gen.named.list("{i}+{j}", L[[i]] + L[[j]],
  i = names(L), j = names(L), i < j)

Sums3 <- gen.named.list("{i}+{j}+{k}", L[[i]] + L[[j]] + L[[k]], 
  i = names(L), j = names(L), k = names(L), i < j, j < k)

Sums <- c(Sums2, Sums3)
1赞 jblood94 11/8/2023 #3

一个函数,它以递归方式构建组合,例如,,因为的结果也被存储。与朴素的 方法相比,这导致矩阵求和更少。总体而言,这导致矩阵列表的矩阵求和较少。PQ = P + Q; PQR = PQ + RPQPQ = P + Q; PQR = P + Q + R(n-1)*2^n + 1n

combosum1 <- function(lst) {
  f <- function(m, nm, j) {
    m;nm
    for (k in (j + 1L):n) {
      i <<- i + 1L
      out[[i]] <<- m + lst[[k]]
      nms_out[i] <<- paste0(nm, nms[[k]])
      if (k < n) Recall(out[[i]], nms_out[i], k)
    }
  }
  
  n <- length(lst)
  nms <- names(lst)
  out <- vector("list", 2^n - n - 1)
  nms_out <- character(length(out))
  i <- 0L
  for (j in 1:(n - 1L)) f(lst[[j]], nms[j], j)
  names(out) <- nms_out
  out
}

使用朴素方法的函数:

combosum2 <- function(lst) {
  do.call(
    c,
    lapply(
      2:length(lst),
      \(k) unlist(
        combn(lst,
              k, \(...)
              setNames(
                list(Reduce(`+`, ...)),
                paste0(names(...), collapse = "")
              ),
              simplify = FALSE
        ),
        recursive = FALSE
      )
    )
  )
}

证明等效性:

lst <- list(P = P, Q = Q, R = R, S = S)
sums1 <- combosum1(lst)
sums2 <- combosum2(lst)
# reorder `sums2` by name
sums2 <- sums2[order(names(sums2))]
identical(sums1, sums2)
#> [1] TRUE

标杆:

lst <- setNames(replicate(9, matrix(sample(0:10, 100, 1), 10), FALSE), LETTERS[7:15])

bench::mark(
  combosum1 = combosum1(lst),
  combosum2 = combosum2(lst),
  check = FALSE
)
#> # A tibble: 2 × 6
#>   expression      min   median `itr/sec` mem_alloc `gc/sec`
#>   <bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#> 1 combosum1    1.68ms   1.74ms      564.     228KB     17.4
#> 2 combosum2    4.42ms   4.61ms      215.     840KB     18.9