2016-02-06 33 views
5

我知道改进循环已经被问过很多次了。 我们可以应用族函数来改进R中的for循环。取决于另一个矩阵的改进矩阵操作循环的方法

但是,有没有一种方法可以改进矩阵的操作,其中这些操作依赖于另一个矩阵?我这里的意思是这样的,在那里我test设置为2的元素是基于另一个矩阵index

for (i in 1:nrow(test)){ 
    test[i,index[i,]] <- 2 
} # where index is predetermined matrix 

另一个例子是这样的,当我在test基于元素的顺序设置的值另一个矩阵anyMatrix行:

for (i in 1:nrow(test)){ 
    test[i,] <- order(anyMatrix[i,]) 
} 

我可以lapply或sapply用在这里,但他们返回一个列表,它需要时间相同数量的将其转换回矩阵。

重复的例子:

test <- matrix(0, nrow = 10, ncol = 10) 
set.seed(1234) 
index <- matrix(sample.int(10, 10*10, TRUE), 10, 10) 
anyMatrix <- matrix(rnorm(10*10), nrow = 10, ncol = 10) 

for (i in 1:nrow(test)){ 
    test[i,index[i,]] <- 2 
} 

for (i in 1:nrow(test)){ 
    test[i,] <- order(anyMatrix[i,]) 
} 

回答

6

你真的出现在这里有两个独立的问题。

问题1:给定一个矩阵index,你要设置test[i,j] 2如果j出现在indexi行每行i和列j。这可以通过简单的矩阵索引来完成,传递索引的2列矩阵,其中第一列是要索引的所有元素的行,第二列是要索引的所有元素的列:

test[cbind(as.vector(row(index)), as.vector(index))] <- 2 
test 
#  [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] 
# [1,] 2 2 0 2 2 2 2 0 2  2 
# [2,] 2 0 2 2 2 2 2 0 2  2 
# [3,] 2 2 2 2 0 0 2 2 0  0 
# [4,] 2 2 0 0 0 2 2 2 0  2 
# [5,] 2 2 2 2 0 0 0 0 2  0 
# [6,] 0 0 0 0 0 2 2 2 2  0 
# [7,] 2 0 2 2 2 2 2 0 0  0 
# [8,] 2 0 2 2 2 2 0 2 0  2 
# [9,] 2 2 2 2 0 0 2 0 2  2 
# [10,] 2 0 2 0 0 2 2 2 2  0 

由于这样做在单个向量化操作中的所有操作,它应该比遍历行并分别处理它们要快。以下是一个具有100万行和10列的示例:

OP <- function(test, index) { 
    for (i in 1:nrow(test)){ 
    test[i,index[i,]] <- 2 
    } 
    test 
} 
josliber <- function(test, index) { 
    test[cbind(as.vector(row(index)), as.vector(index))] <- 2 
    test 
} 
test.big <- matrix(0, nrow = 1000000, ncol = 10) 
set.seed(1234) 
index.big <- matrix(sample.int(10, 1000000*10, TRUE), 1000000, 10) 
identical(OP(test.big, index.big), josliber(test.big, index.big)) 
# [1] TRUE 
system.time(OP(test.big, index.big)) 
# user system elapsed 
# 1.564 0.014 1.591 
system.time(josliber(test.big, index.big)) 
# user system elapsed 
# 0.408 0.034 0.444 

这里,向量化方法的速度提高了3.5倍。

问题2:你想的testi行设置为order应用于anyMatrix相应的行。你可以用apply做到这一点:

(test <- t(apply(anyMatrix, 1, order))) 
#  [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] 
# [1,] 1 10 7 8 4 5 3 6 2  9 
# [2,] 8 7 1 6 3 4 9 5 10  2 
# [3,] 4 9 7 1 3 2 6 10 5  8 
# [4,] 1 2 6 4 10 3 9 8 7  5 
# [5,] 9 6 5 1 2 7 10 4 8  3 
# [6,] 9 3 8 6 5 10 1 4 7  2 
# [7,] 3 7 2 5 6 8 9 4 1 10 
# [8,] 9 8 1 3 4 6 7 10 5  2 
# [9,] 8 4 3 6 10 7 9 5 2  1 
# [10,] 4 1 9 3 6 7 8 2 10  5 

我不会期望太多在运行时这里的变化,因为apply其实只是通过行循环类似于你如何在解决方案中循环。尽管如此,我更喜欢这个解决方案,因为这样做的好处在于键入更少,更“R”的做事方式。

请注意,这两个应用程序都使用完全不同的代码,这在R数据操作中非常典型 - 有许多不同的专用操作符,您需要选择适合您的任务的代码。我不认为有一个单一的功能,甚至是一小组函数,它们将能够处理所有的基于另一个矩阵的数据的矩阵操作。

+0

谢谢,但在第一个中cbind的速度如何? cbind不会比通常的循环花费更多的时间吗?你有基准吗? – rmania

+0

@rmania我已经更新了这个答案,包括一个基准,显示矢量化索引操作相比于循环替代方法产生加速。在R中,用一次执行所有这些操作的单个操作来替换许多重复的快速操作通常会产生巨大的加速。 – josliber