为了更好的表现而努力

时间:2016-06-22 00:03:39

标签: r performance matrix mapply

我想将函数应用于矩阵输入a,此函数会将第一个元素更改为c[a[1]],将下一个元素更改为b[a[i],a[i+1]]i = 1开始到i = ncol(a) - 1

示例输入:

a <- matrix(c(1,4,3,1),nrow=1)
b <- matrix(1:25,ncol=5,nrow=5)
c <- matrix(4:8,ncol=5,nrow=1)

预期产出:

>a
4 16 14 3

#c[a[1]] gave us the first element: 4
#b[a[1],a[2]] gave us the second element: 16 
#b[a[2],a[3]] gave us the third element: 14
#b[a[3],a[4]] gave us the fourth element: 3

到目前为止,我一直试图使用mapply()但没有任何成功。我们的想法是避免循环,因为这些东西会导致R

的主要性能下降

1 个答案:

答案 0 :(得分:8)

步骤1:使用单个索引寻址矩阵

在R矩阵中,元素按列主要顺序存储到向量中,因此A[i, j]A[(j-1)*nrow(A) + i]相同。考虑一个随机3乘3矩阵的例子:

set.seed(1); A <- round(matrix(runif(9), 3, 3), 2)

> A
     [,1] [,2] [,3]
[1,] 0.27 0.91 0.94
[2,] 0.37 0.20 0.66
[3,] 0.57 0.90 0.63

现在,这个矩阵有3行(nrow(A) = 3)。比较:

A[2,3]  # 0.66
A[(3-1) * 3 + 2]  # 0.66

第2步:向量化

您可以一次处理矩阵的多个元素。 但是,您只能使用单一索引模式(此处不太精确,请参阅@ alexis_laz稍后的评论)。例如,如果您要提取A[1,2]A[3,1],但是如果您这样做:

A[c(1,3), c(2,1)]
#      [,1] [,2]
# [1,] 0.91 0.27
# [2,] 0.90 0.57

你实际上得到了一个阻止。现在,如果您使用单个索引,您将获得所需:

A[3 * (c(2,1) - 1) + c(1,3)]
# [1] 0.91 0.57

第3步:获取问题的单一索引

假设n <- length(a)并且您想要解决b

的这些元素
a[1]    a[2]
a[2]    a[3]
 .       .
 .       .
a[n-1]  a[n]

您可以使用单个索引nrow(b) * (a[2:n] - 1) + a[1:(n-1)]

第4步:完成解决方案

由于ac只有一行,因此应将它们存储为向量而不是矩阵。

a <- c(1,4,3,1)
c <- 4:8

如果您获得了一个矩阵而没有选择(因为它们目前在您的问题中),您可以通过以下方式将它们转换为向量:

a <- as.numeric(a)
c <- as.numeric(c)

现在,如上所述,我们有地址b矩阵的索引:

n <- length(a)
b_ind <- nrow(b) * (a[2:n] - 1) + a[1:(n-1)]

您还会将a[1]的{​​{1}}元素作为最终结果的第一个元素,因此我们需要连接:cc[a[1]]

b[b_ind]

这种方法完全矢量化,甚至比a <- c(c[a[1]], b[b_ind]) # > a # [1] 4 16 14 3 系列更好。

alexis_laz的评论

alexis_laz提醒我,我们也可以使用“矩阵索引”,即我们也可以通过以下方式处理矩阵*apply

b

但是,我认为使用单个索引稍微快一点,因为我们需要逐行访问索引矩阵才能解决b[cbind(a[1:(n-1)],a[2:n])] ## or b[cbind(a[-n], a[-1])] ,所以我们支付的内存延迟比使用矢量索引要高。