如何对 R 中 "series" 个向量的操作进行向量化
How to vectorize an operation on a "series" of vectors in R
我在 R 中有一个函数,它接受一个标量和一个向量作为参数,对它们执行一些操作并返回一个值。
给定一个“系列”标量(此处为向量 mya
)和一个“系列”向量(此处为矩阵 myv
),我如何将对 myf
以便 mya
中的每个元素与 myv
?
中的相应向量对应
mya = 1:3
myv = matrix(1:30, 10, 3)
myf = function(a, v) {
return(sum(a / (a/v + 1)))
}
sapply(1:3, function(x) {myf(mya[x], myv[,x])})
# [1] 7.980123 17.649590 26.809440
所以上面我想避免循环 sapply
操作直接做这样的事情:
myf(mya, myv)
# [1] 49.37443 <- Here I would like 3 values
这里的大问题是性能:在我的实际情况下,mya
和 myv
分别有超过 10e6 个值或向量,而 myf
复杂得多。
预先,您的 myv
可能被组织为一系列向量,每个向量一列;许多工具最好将其转换为 list
向量。
asplit(myv, 2)
# [[1]]
# [1] 1 2 3 4 5 6 7 8 9 10
# [[2]]
# [1] 11 12 13 14 15 16 17 18 19 20
# [[3]]
# [1] 21 22 23 24 25 26 27 28 29 30
基础 R
sapply
/lapply
对单个 vector/list 就像 mapply
/Map
对 n
一样。
Map(myf, mya, asplit(myv , 2))
# [[1]]
# [1] 7.980123
# [[2]]
# [1] 17.64959
# [[3]]
# [1] 26.80944
mapply(myf, mya, asplit(myv , 2))
# [1] 7.980123 17.649590 26.809440
整洁宇宙
参数的顺序不同,而不是单个参数,它需要所有参数都在 list
本身中。
purrr::pmap(list(mya, asplit(myv , 2)), myf)
# [[1]]
# [1] 7.980123
# [[2]]
# [1] 17.64959
# [[3]]
# [1] 26.80944
purrr::pmap_dbl(list(mya, asplit(myv , 2)), myf)
# [1] 7.980123 17.649590 26.809440
考虑到评论的替代方法。
这种方法确实是向量化的,但是对函数进行了一些解构。
colSums(t(mya / (mya / t(myv) + 1)))
# [1] 7.980123 17.649590 26.809440
为了达到这一点,需要认识到 t
ranspose 在哪里是必要的。我将从一些已知点开始:
mya[1] / myv[,1] + 1
# [1] 2.000000 1.500000 1.333333 1.250000 1.200000 1.166667 1.142857 1.125000 1.111111 1.100000
为了用矩阵(而不仅仅是向量)来模拟,我们可以尝试
(mya / myv + 1)
# [,1] [,2] [,3]
# [1,] 2.000000 1.181818 1.142857
# [2,] 2.000000 1.250000 1.045455
# [3,] 2.000000 1.076923 1.086957
# [4,] 1.250000 1.142857 1.125000
# [5,] 1.400000 1.200000 1.040000
# [6,] 1.500000 1.062500 1.076923
# [7,] 1.142857 1.117647 1.111111
# [8,] 1.250000 1.166667 1.035714
# [9,] 1.333333 1.052632 1.068966
# [10,] 1.100000 1.100000 1.100000
但是如果你注意到,mya
在 myv
上的划分是按列划分的,所以它扩展到
c(mya[1] / myv[1,1], mya[2] / myv[2,1], mya[3] / myv[3,1], mya[1] / myv[4,1], ...)
我们希望将其转置的位置。好的,所以我们转置它,以便 myv
的 行 是垂直的。
(mya / t(myv) + 1)[1,]
# [1] 2.000000 1.500000 1.333333 1.250000 1.200000 1.166667 1.142857 1.125000 1.111111 1.100000
这样更好。现在我们需要为下一步做同样的事情。这将我们带到
t(mya / (mya / t(myv) + 1))
# [,1] [,2] [,3]
# [1,] 0.5000000 1.692308 2.625000
# [2,] 0.6666667 1.714286 2.640000
# [3,] 0.7500000 1.733333 2.653846
# [4,] 0.8000000 1.750000 2.666667
# [5,] 0.8333333 1.764706 2.678571
# [6,] 0.8571429 1.777778 2.689655
# [7,] 0.8750000 1.789474 2.700000
# [8,] 0.8888889 1.800000 2.709677
# [9,] 0.9000000 1.809524 2.718750
# [10,] 0.9090909 1.818182 2.727273
因为您想对每个 mya
值求和。知道我们在 mya
中有三个并且我们看到三列,可能会推断我们需要对每一列求和。我们可以凭经验证明:
sum(mya[1] / (mya[1] / myv[,1] + 1))
# [1] 7.980123
colSums(t(mya / (mya / t(myv) + 1)))
# [1] 7.980123 17.649590 26.809440
但实际上,当我们不能对行进行转置和求和时,我们不需要先t
先排列然后求和:-)
rowSums(mya / (mya / t(myv) + 1))
# [1] 7.980123 17.649590 26.809440
我在 R 中有一个函数,它接受一个标量和一个向量作为参数,对它们执行一些操作并返回一个值。
给定一个“系列”标量(此处为向量 mya
)和一个“系列”向量(此处为矩阵 myv
),我如何将对 myf
以便 mya
中的每个元素与 myv
?
mya = 1:3
myv = matrix(1:30, 10, 3)
myf = function(a, v) {
return(sum(a / (a/v + 1)))
}
sapply(1:3, function(x) {myf(mya[x], myv[,x])})
# [1] 7.980123 17.649590 26.809440
所以上面我想避免循环 sapply
操作直接做这样的事情:
myf(mya, myv)
# [1] 49.37443 <- Here I would like 3 values
这里的大问题是性能:在我的实际情况下,mya
和 myv
分别有超过 10e6 个值或向量,而 myf
复杂得多。
预先,您的 myv
可能被组织为一系列向量,每个向量一列;许多工具最好将其转换为 list
向量。
asplit(myv, 2)
# [[1]]
# [1] 1 2 3 4 5 6 7 8 9 10
# [[2]]
# [1] 11 12 13 14 15 16 17 18 19 20
# [[3]]
# [1] 21 22 23 24 25 26 27 28 29 30
基础 R
sapply
/lapply
对单个 vector/list 就像 mapply
/Map
对 n
一样。
Map(myf, mya, asplit(myv , 2))
# [[1]]
# [1] 7.980123
# [[2]]
# [1] 17.64959
# [[3]]
# [1] 26.80944
mapply(myf, mya, asplit(myv , 2))
# [1] 7.980123 17.649590 26.809440
整洁宇宙
参数的顺序不同,而不是单个参数,它需要所有参数都在 list
本身中。
purrr::pmap(list(mya, asplit(myv , 2)), myf)
# [[1]]
# [1] 7.980123
# [[2]]
# [1] 17.64959
# [[3]]
# [1] 26.80944
purrr::pmap_dbl(list(mya, asplit(myv , 2)), myf)
# [1] 7.980123 17.649590 26.809440
考虑到评论的替代方法。
这种方法确实是向量化的,但是对函数进行了一些解构。
colSums(t(mya / (mya / t(myv) + 1)))
# [1] 7.980123 17.649590 26.809440
为了达到这一点,需要认识到 t
ranspose 在哪里是必要的。我将从一些已知点开始:
mya[1] / myv[,1] + 1
# [1] 2.000000 1.500000 1.333333 1.250000 1.200000 1.166667 1.142857 1.125000 1.111111 1.100000
为了用矩阵(而不仅仅是向量)来模拟,我们可以尝试
(mya / myv + 1)
# [,1] [,2] [,3]
# [1,] 2.000000 1.181818 1.142857
# [2,] 2.000000 1.250000 1.045455
# [3,] 2.000000 1.076923 1.086957
# [4,] 1.250000 1.142857 1.125000
# [5,] 1.400000 1.200000 1.040000
# [6,] 1.500000 1.062500 1.076923
# [7,] 1.142857 1.117647 1.111111
# [8,] 1.250000 1.166667 1.035714
# [9,] 1.333333 1.052632 1.068966
# [10,] 1.100000 1.100000 1.100000
但是如果你注意到,mya
在 myv
上的划分是按列划分的,所以它扩展到
c(mya[1] / myv[1,1], mya[2] / myv[2,1], mya[3] / myv[3,1], mya[1] / myv[4,1], ...)
我们希望将其转置的位置。好的,所以我们转置它,以便 myv
的 行 是垂直的。
(mya / t(myv) + 1)[1,]
# [1] 2.000000 1.500000 1.333333 1.250000 1.200000 1.166667 1.142857 1.125000 1.111111 1.100000
这样更好。现在我们需要为下一步做同样的事情。这将我们带到
t(mya / (mya / t(myv) + 1))
# [,1] [,2] [,3]
# [1,] 0.5000000 1.692308 2.625000
# [2,] 0.6666667 1.714286 2.640000
# [3,] 0.7500000 1.733333 2.653846
# [4,] 0.8000000 1.750000 2.666667
# [5,] 0.8333333 1.764706 2.678571
# [6,] 0.8571429 1.777778 2.689655
# [7,] 0.8750000 1.789474 2.700000
# [8,] 0.8888889 1.800000 2.709677
# [9,] 0.9000000 1.809524 2.718750
# [10,] 0.9090909 1.818182 2.727273
因为您想对每个 mya
值求和。知道我们在 mya
中有三个并且我们看到三列,可能会推断我们需要对每一列求和。我们可以凭经验证明:
sum(mya[1] / (mya[1] / myv[,1] + 1))
# [1] 7.980123
colSums(t(mya / (mya / t(myv) + 1)))
# [1] 7.980123 17.649590 26.809440
但实际上,当我们不能对行进行转置和求和时,我们不需要先t
先排列然后求和:-)
rowSums(mya / (mya / t(myv) + 1))
# [1] 7.980123 17.649590 26.809440