基于另一个矩阵对一个矩阵排序

时间:2012-06-19 20:17:04

标签: r matrix

我试图将一个矩阵的行与相同维度的另一个矩阵的行的顺序相同。但是,如果没有显式循环,我无法弄清楚如何做到这一点。似乎我应该能够通过子集和应用或Map功能来实现这一点,但我无法弄清楚如何做到这一点。

这是一个玩具示例:

sortMe <- matrix(rnorm(6), ncol=2)
sortBy <- matrix(c(2,1,3, 1,3,2), ncol=2)

sorted <- sortMe 
for (i in 1:ncol(sortMe)) {
  sorted[,i] <- sortMe[,i][sortBy[,i]]
}

使用此方法,生成的sorted矩阵包含sortMe的值,其排序顺序与sortBy矩阵相同。知道如何在没有循环的情况下做到这一点吗?

3 个答案:

答案 0 :(得分:8)

这(使用两列整数矩阵来索引矩阵的两个维度)应该可以解决这个问题:

sorted <- sortMe
sorted[] <- sortMe[cbind(as.vector(sortBy), as.vector(col(sortBy)))]

答案 1 :(得分:3)

使用lapply会有效。

matrix(unlist(lapply(1:2, function(n) sortMe[,n][sortBy[,n]])), ncol=2)

但可能有一种更有效的方法......

答案 2 :(得分:3)

我打算建议你坚持原来的版本。我认为你写的原始循环比其他解决方案更容易阅读和理解(也可能更容易编写)。

此外,循环几乎与其他解决方案一样快:(在他从帖子中删除之前,我借用了@Josh O'Brien的计时代码。)

set.seed(444)
n = 1e7
sortMe <- matrix(rnorm(2 * n), ncol=2)
sortBy <- matrix(c(sample(n), sample(n)), ncol=2)

#---------------------------------------------------------------------------
# @JD Long, original post.
system.time({
    sorted_JD <- sortMe
    for (i in 1:ncol(sortMe)) {
        sorted_JD[, i] <- sortMe[, i][sortBy[, i]]
    } 
})
#   user  system elapsed 
#  1.190   0.165   1.334 

#---------------------------------------------------------------------------
# @Julius (post is now deleted).
system.time({
    sorted_Jul2 <- sortMe
    sorted_Jul2[] <- sortMe[as.vector(sortBy) + 
        rep(0:(ncol(sortMe) - 1) * nrow(sortMe), each = nrow(sortMe))]
})
#   user  system elapsed 
#  1.023   0.218   1.226 

#---------------------------------------------------------------------------
# @Josh O'Brien
system.time({
    sorted_Jos <- sortMe
    sorted_Jos[] <- sortMe[cbind(as.vector(sortBy), as.vector(col(sortBy)))]
})
#   user  system elapsed 
#  1.070   0.217   1.274 

#---------------------------------------------------------------------------
# @Justin
system.time({
    sorted_Just = matrix(unlist(lapply(1:2,
        function(n) sortMe[,n][sortBy[,n]])), ncol=2)
})
#   user  system elapsed 
#  0.989   0.199   1.162 


all.equal(sorted_JD, sorted_Jul2)
# [1] TRUE
all.equal(sorted_JD, sorted_Jos)
# [1] TRUE
all.equal(sorted_JD, sorted_Just)
# [1] TRUE