通过交替列合并矩阵

17
我正在寻找一种常规方法来合并两个矩阵,使得新矩阵中来自这两个初始矩阵的列交替出现。
col1m1...col1m2...col2m1...col2m2...col3m1...col3m2......
例如:
matrix.odd  <- matrix(c(rep(1,3),rep(3,3),rep(5,3)),nrow=3,ncol=3)
matrix.even <- matrix(c(rep(2,3),rep(4,3),rep(6,3)),nrow=3,ncol=3)
# would look like
matrix.combined <- matrix(c(rep(1,3),rep(2,3),rep(3,3),rep(4,3),rep(5,3),rep(6,3)),
                          nrow=3,ncol=6)

我正在寻找一种通用方法,因为我的矩阵组合不仅超过了 3 列。我尝试了一些 for 循环和 if 语句,但结果并不理想。在组合矩阵和交替矩阵的搜索也没有什么成果。有什么想法吗?

5个回答

14

应该做些类似这样的事情:

m <- cbind(matrix.odd, matrix.even)                   # combine
m <- m[, c(matrix(1:ncol(m), nrow = 2, byrow = T))]   # then reorder

另一个有趣的选择:

matrix(rbind(matrix.odd, matrix.even), nrow = nrow(matrix.odd))

并且要玩许多矩阵游戏:

weave = function(...) {
  l = list(...)
  matrix(do.call(rbind, l), nrow = nrow(l[[1]]))
}

+1 不错的解决方案。但我建议指定 byrow=TRUE,因为 T 可能会被用户重新绑定。 - Jason Morgan
@eddi,您能展示一下如何适应行合并吗?谢谢。 - Anusha
@Anusha 可能是这样的:matrix(t(cbind(matrix.odd, matrix.even)), ncol = ncol(matrix.odd), byrow = T) - eddi
@eddi 谢谢。我试着用 bycol,但我认为它没有定义。 - Anusha
基准测试中,我发现你的第一个建议是最快的解决方案,@flodel的解决方案也差不多。相比之下,你的“其他有趣选项”似乎要慢大约20%。(Zero的解决方案需要的时间略少于两倍,而Simon的解决方案需要的时间略多于两倍,但这在一定程度上取决于矩阵的形状。) - Silverfish

9
rows.combined <- nrow(matrix.odd) 
cols.combined <- ncol(matrix.odd) + ncol(matrix.even)
matrix.combined <- matrix(NA, nrow=rows.combined, ncol=cols.combined)
matrix.combined[, seq(1, cols.combined, 2)] <- matrix.odd
matrix.combined[, seq(2, cols.combined, 2)] <- matrix.even

@zero323 我尝试通过执行 matrix.combined(seq(1, rows.combined,2), ] 将其适应于行,但它只添加了第一个矩阵而不是第二个。如何将其用于行? - Anusha

5
alternate.cols <- function(m1, m2) {
  cbind(m1, m2)[, order(c(seq(ncol(m1)), seq(ncol(m2))))]
}

identical(matrix.combined, alternate.cols(matrix.odd, matrix.even))
# [1] TRUE

如果 m1m2 的列数不同,该功能也会做出正确的事情(主观判断):

alternate.cols(matrix.odd, matrix.even[, -3])
#      [,1] [,2] [,3] [,4] [,5]
# [1,]    1    2    3    4    5
# [2,]    1    2    3    4    5
# [3,]    1    2    3    4    5

很容易将其推广到任意数量的矩阵:

alternate.cols <- function(...) {
  l <- list(...)
  m <- do.call(cbind, l)
  i <- order(sequence(sapply(l, ncol)))
  m[, i]
}

2
您可以将其转换为3D数组,然后进行转置...
arr <- array( c(m1,m2) , dim = c(dim(m1),2) )
matrix( aperm( arr , c(1,3,2) ) , nrow(m1) )
     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]    1    2    3    4    5    6
[2,]    1    2    3    4    5    6
[3,]    1    2    3    4    5    6

作为一个函数,可以推广到许多矩阵...
bindR <- function(...){
    args <- list(...)
    dims <- c( dim(args[[1]]) , length(args) )
    arr <- array( unlist( args ) , dim = dims )
    matrix( aperm( arr , c(1,3,2) ) , dims[1] )
}


bindR(m1,m2,m1,m2)
#     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
#[1,]    1    2    1    2    3    4    3    4    5     6     5     6
#[2,]    1    2    1    2    3    4    3    4    5     6     5     6
#[3,]    1    2    1    2    3    4    3    4    5     6     5     6

0

可能有更简洁的方法来完成这个任务。如果矩阵很大,你可能需要寻找更高效的方法。

# Test data
(X <- matrix(1:16, nrow=4, ncol=4))
(Y <- matrix(-16:-1, nrow=4, ncol=4))

# Set indices for the new matrix
X.idx <- seq(1, ncol(X)*2, by=2)
Y.idx <- seq(2, ncol(Y)*2+1, by=2)

# Column bind the matrices and name columns according to the indices
XY <- cbind(X, Y)
colnames(XY) <- c(X.idx, Y.idx)

# Now order the columns
XY[, order(as.numeric(colnames(XY)))]

谢谢。 我正在尝试更大的矩阵集(每个矩阵有5列)。 一切都进行得很顺利,直到最后一个命令对列进行排序。 我得到的排序是1,10,2,3,4,5,6,7,8,9。这需要一个"as.numeric"参数吗?我会尝试一些东西。 - Will Phillips
你说得对。我会改的,不过eddi的解决方案可能更好。 - Jason Morgan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接