根据另一个矩阵改进矩阵操作循环的方法

时间:2016-02-06 15:04:23

标签: r matrix lapply mapply

我知道改进循环已被问过很多次。 我们可以应用族函数来改进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,])
}

1 个答案:

答案 0 :(得分:6)

这里你似乎有两个不同的问题。

问题1 :给定矩阵index,对于每行i和列j,您希望test[i,j]设置为2 { {1}}显示在j的行i中。这可以通过简单的矩阵索引来完成,传递索引的2列矩阵,其中第一列是要索引的所有元素的行,第二列是要索引的所有元素的列:

index

由于这会在单个矢量化操作中执行所有操作,因此它应该比循环遍历行并单独处理它们更快。这是一个包含100万行和10列的示例:

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

这里,矢量化方法快了3.5倍。

问题2 :您希望将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 的行i设置为应用于test的相应行的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 实际上只是循环遍历行,类似于你在解决方案中循环的方式。不过,我更喜欢这种解决方案,因为它打字很少,输入次数也越多。&#34; R&#34;做事的方式。

请注意,这两个应用程序都使用了非常不同的代码,这在R数据操作中非常典型 - 有许多不同的专业运算符,您需要选择适合您任务的运算符。我不认为这是一个单一的函数,甚至是一小部分能够处理所有矩阵操作的函数,其中该操作基于来自另一个矩阵的数据。