映射以获得更好的性能
mapply for better performance
我想将函数应用于矩阵输入 a
,此函数会将第一个元素更改为 c[a[1]]
,将下一个元素更改为 b[a[i],a[i+1]]
,从 [=15= 开始] 最多 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
中的性能大幅下降
第一步:使用单索引寻址矩阵
在 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 步:完成解决方案
因为 a
和 c
只有一行,所以应该将它们存储为向量而不是矩阵。
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)]
您还将 c
的 a[1]
元素作为最终结果的第一个元素,因此我们需要通过以下方式连接:c[a[1]]
和 b[b_ind]
:
a <- c(c[a[1]], b[b_ind])
# > a
# [1] 4 16 14 3
这种方法是完全矢量化的,甚至比 *apply
家族更好。
alexis_laz的备注
alexis_laz 提醒我我们也可以使用 "matrix-index",也就是说,我们也可以通过以下方式寻址矩阵 b
:
b[cbind(a[1:(n-1)],a[2:n])] ## or b[cbind(a[-n], a[-1])]
但是,我认为使用单索引稍微快一些,因为我们需要逐行访问索引矩阵才能寻址b
,所以我们比使用向量索引付出了更高的内存延迟。
我想将函数应用于矩阵输入 a
,此函数会将第一个元素更改为 c[a[1]]
,将下一个元素更改为 b[a[i],a[i+1]]
,从 [=15= 开始] 最多 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
第一步:使用单索引寻址矩阵
在 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 步:完成解决方案
因为 a
和 c
只有一行,所以应该将它们存储为向量而不是矩阵。
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)]
您还将 c
的 a[1]
元素作为最终结果的第一个元素,因此我们需要通过以下方式连接:c[a[1]]
和 b[b_ind]
:
a <- c(c[a[1]], b[b_ind])
# > a
# [1] 4 16 14 3
这种方法是完全矢量化的,甚至比 *apply
家族更好。
alexis_laz的备注
alexis_laz 提醒我我们也可以使用 "matrix-index",也就是说,我们也可以通过以下方式寻址矩阵 b
:
b[cbind(a[1:(n-1)],a[2:n])] ## or b[cbind(a[-n], a[-1])]
但是,我认为使用单索引稍微快一些,因为我们需要逐行访问索引矩阵才能寻址b
,所以我们比使用向量索引付出了更高的内存延迟。