R中的多重外积

snvhrwxg  于 2023-06-19  发布在  其他
关注(0)|答案(4)|浏览(134)

假设我们有四个向量,每个向量都是三维的:

v1 <- c(1, 2, 3)
v2 <- c(4, 5, 6)
v3 <- c(2, 2, 2)
v4 <- c(3, 2, 1)

我的目标是创建一个包含每个向量的外积的数组:

tmp_array <- array(NA, dim = c(3, 3, 4))
tmp_array[, , 1] <- outer(v1, v1)
tmp_array[, , 2] <- outer(v2, v2)
tmp_array[, , 3] <- outer(v3, v3)
tmp_array[, , 4] <- outer(v4, v4)

我们现在得到的是一个包含四个向量的矩阵:

tmp_matrix <- rbind(v1, v2, v3, v4)

我想用tmp_matrix来生成tmp_array
我试过outer(t(tmp_matrix), tmp_matrix)outer(tmp_matrix, tmp_matrix)等等,但这些都不是解决方案。
如何创建tmp_array?(即不使用循环)

pxy2qtax

pxy2qtax1#

可以使用apply(..., simplify = FALSE)simplify2array()将外积矩阵列表转换为三维数组。

simplify2array(apply(tmp_matrix, 1, \(v) outer(v, v), simplify = FALSE))
, , v1

     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    2    4    6
[3,]    3    6    9

, , v2

     [,1] [,2] [,3]
[1,]   16   20   24
[2,]   20   25   30
[3,]   24   30   36

, , v3

     [,1] [,2] [,3]
[1,]    4    4    4
[2,]    4    4    4
[3,]    4    4    4

, , v4

     [,1] [,2] [,3]
[1,]    9    6    3
[2,]    6    4    2
[3,]    3    2    1
jucafojl

jucafojl2#

使用mapply(),你可以通过将"array"参数传递给simplify参数来获得simplify2array(),你可以这样实现:

mapply(
  function(row){
    outer(row, row, FUN = `*`)
  },
  split(
    tmp_matrix, 
    seq_len(nrow(tmp_matrix))
  ),
  SIMPLIFY = "array"
)
huwehgph

huwehgph3#

您可以使用tcrossprod(而不是outer)+ dim<-

> `dim<-`(do.call(cbind, lapply(list(v1, v2, v3, v4), tcrossprod)), c(3, 3, 4))
, , 1

     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    2    4    6
[3,]    3    6    9

, , 2

     [,1] [,2] [,3]
[1,]   16   20   24
[2,]   20   25   30
[3,]   24   30   36

, , 3

     [,1] [,2] [,3]
[1,]    4    4    4
[2,]    4    4    4
[3,]    4    4    4

, , 4

     [,1] [,2] [,3]
[1,]    9    6    3
[2,]    6    4    2
[3,]    3    2    1

泛化

为了概括这些情况(不仅仅是v1v2v3v4),我们可以构建一个自定义函数f,如下所示

f <- function(...) {
    lst <- list(...)
    if (var(lengths(lst)) > 0) stop("Input vectors should be of the same length!")
    n <- length(lst[[1]])
    `dim<-`(do.call(cbind, lapply(lst, tcrossprod)), c(n, n, length(lst)))
}

使得

> f(v1, v2)
, , 1

     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    2    4    6
[3,]    3    6    9

, , 2

     [,1] [,2] [,3]
[1,]   16   20   24
[2,]   20   25   30
[3,]   24   30   36

> f(1:5, 6:10, 11:15)
, , 1

     [,1] [,2] [,3] [,4] [,5]
[1,]    1    2    3    4    5
[2,]    2    4    6    8   10
[3,]    3    6    9   12   15
[4,]    4    8   12   16   20
[5,]    5   10   15   20   25

, , 2

     [,1] [,2] [,3] [,4] [,5]
[1,]   36   42   48   54   60
[2,]   42   49   56   63   70
[3,]   48   56   64   72   80
[4,]   54   63   72   81   90
[5,]   60   70   80   90  100

, , 3

     [,1] [,2] [,3] [,4] [,5]
[1,]  121  132  143  154  165
[2,]  132  144  156  168  180
[3,]  143  156  169  182  195
[4,]  154  168  182  196  210
[5,]  165  180  195  210  225

> f(v1, 1:2)
Error in f(v1, 1:2) : Input vectors should be of the same length!
jobtbby3

jobtbby34#

我相信你可以尝试一下R中的sweep()函数。在这里可以看到一些使用sweep()的例子,https://www.r-bloggers.com/2022/07/how-to-use-the-sweep-function-in-r/
它是对数组或矩阵执行元素操作的函数。在这种情况下,您可以使用它将tmp_matrix的每一列与其自身相乘,并将结果分配给tmp_array的相应切片。我认为您可以通过指定2作为MARGIN参数来指示该操作应该沿着列执行。
代码如下所示:

# Define the vectors
v1 <- c(1, 2, 3)
v2 <- c(4, 5, 6)
v3 <- c(2, 2, 2)
v4 <- c(3, 2, 1)

# Create tmp_matrix
tmp_matrix <- rbind(v1, v2, v3, v4)

# Calculate tmp_array using sweep()
tmp_array <- array(NA, dim = c(3, 3, 4))
tmp_array[, , 1] <- sweep(tmp_matrix, 2, STATS = tmp_matrix[, 1], FUN = "*")
tmp_array[, , 2] <- sweep(tmp_matrix, 2, STATS = tmp_matrix[, 2], FUN = "*")
tmp_array[, , 3] <- sweep(tmp_matrix, 2, STATS = tmp_matrix[, 3], FUN = "*")
tmp_array[, , 4] <- sweep(tmp_matrix, 2, STATS = tmp_matrix[, 4], FUN = "*")

# Print tmp_array
print(tmp_array)

相关问题