提问人:Rosalin August 提问时间:11/8/2023 更新时间:11/9/2023 访问量:81
将 are 中的所有矩阵组合相加,以便我稍后可以调用名称
Adding together all combinations of matrices in R so I can call the names later
问:
我有几个计数变量矩阵,我们可以表示如下:
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)
一方面,这似乎确实可以使所有组合都起作用。但它不允许我知道哪个组合是哪个。
如何将所有矩阵相加,并确保名称反映要添加的矩阵,以便以后可以调用它们?
答:
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
如果要创建变量,如名称所示,可以进一步使用PQ
PQR
out
list2env
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)另一种可能性是使用列表推导式。 是从上面来的。第一个参数定义名称,第二个参数定义值。L
gen.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 + R
PQ
PQ = P + Q; PQR = P + Q + R
(n-1)*2^n + 1
n
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
上一个:按行从矩阵中抽样
下一个:自定义排序(非字母顺序)
评论