向量化函数中 sapply() 的意外行为
Unexpected behaviour of sapply() within vectorized function
我想尝试一下模运算并编写了一些看似无辜的函数...但对以下意想不到的行为感到非常惊讶:
crt <- function(x, mods = c(5, 7)) {
sapply(mods, \(y) x %% y)
}
crt <- Vectorize(crt)
crt(20)
## [,1]
## [1,] 0
## [2,] 6
crt(55)
## [,1]
## [1,] 0
## [2,] 6
crt(1:100)
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14]
## [1,] 1 2 3 4 0 1 2 3 4 0 1 2 3 4
## [2,] 1 2 3 4 5 6 0 1 2 3 4 5 6 0
## [,15] [,16] [,17] [,18] [,19] [,20] [,21] [,22] [,23] [,24] [,25] [,26]
## [1,] 0 1 2 3 4 0 1 2 3 4 0 1
## [2,] 1 2 3 4 5 6 0 1 2 3 4 5
## [,27] [,28] [,29] [,30] [,31] [,32] [,33] [,34] [,35] [,36] [,37] [,38]
## [1,] 2 3 4 0 1 2 3 4 0 1 2 3
## [2,] 6 0 1 2 3 4 5 6 0 1 2 3
## [,39] [,40] [,41] [,42] [,43] [,44] [,45] [,46] [,47] [,48] [,49] [,50]
## [1,] 4 0 1 2 3 4 0 1 2 3 4 0
## [2,] 4 5 6 0 1 2 3 4 5 6 0 1
## [,51] [,52] [,53] [,54] [,55] [,56] [,57] [,58] [,59] [,60] [,61] [,62]
## [1,] 1 2 3 4 0 1 2 3 4 0 1 2
## [2,] 2 3 4 5 6 0 1 2 3 4 5 6
## [,63] [,64] [,65] [,66] [,67] [,68] [,69] [,70] [,71] [,72] [,73] [,74]
## [1,] 3 4 0 1 2 3 4 0 1 2 3 4
## [2,] 0 1 2 3 4 5 6 0 1 2 3 4
## [,75] [,76] [,77] [,78] [,79] [,80] [,81] [,82] [,83] [,84] [,85] [,86]
## [1,] 0 1 2 3 4 0 1 2 3 4 0 1
## [2,] 5 6 0 1 2 3 4 5 6 0 1 2
## [,87] [,88] [,89] [,90] [,91] [,92] [,93] [,94] [,95] [,96] [,97] [,98]
## [1,] 2 3 4 0 1 2 3 4 0 1 2 3
## [2,] 3 4 5 6 0 1 2 3 4 5 6 0
## [,99] [,100]
## [1,] 4 0
## [2,] 1 2
crt(x = 1:100, mods = c(12, 60))
## [1] 1 2 3 4 5 6 7 8 9 10 11 12 1 14 3 16 5 18 7 20 9 22 11 24 1
## [26] 26 3 28 5 30 7 32 9 34 11 36 1 38 3 40 5 42 7 44 9 46 11 48 1 50
## [51] 3 52 5 54 7 56 9 58 11 0 1 2 3 4 5 6 7 8 9 10 11 12 1 14 3
## [76] 16 5 18 7 20 9 22 11 24 1 26 3 28 5 30 7 32 9 34 11 36 1 38 3 40
为什么最后一个函数调用 crt(x = 1:100, mods = c(12, 60))
给出了完全不同的输出?第一个矢量化输出 crt(1:100)
是我想要和期望的,最后一个在结构上似乎没有什么不同,但结果是......为什么?我该如何解决这个问题以获得与第一个相同的输出?
如果您稍微调整一下代码
crt <- function(x, mods = c(5, 7)) {
sapply(mods, \(y) unlist(x %% y))
}
crt <- Vectorize(crt)
并使用不同的 mods
参数调用它,例如
crt(1:100, mods = list(c(6, 12)))
输出看起来像预期的那样:
> crt(1:100, list(c(6, 12)))
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14] [,15] [,16] [,17] [,18]
[1,] 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0
[2,] 1 2 3 4 5 6 7 8 9 10 11 0 1 2 3 4 5 6
[,19] [,20] [,21] [,22] [,23] [,24] [,25] [,26] [,27] [,28] [,29] [,30] [,31] [,32] [,33] [,34] [,35]
[1,] 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5
[2,] 7 8 9 10 11 0 1 2 3 4 5 6 7 8 9 10 11
[,36] [,37] [,38] [,39] [,40] [,41] [,42] [,43] [,44] [,45] [,46] [,47] [,48] [,49] [,50] [,51] [,52]
[1,] 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4
[2,] 0 1 2 3 4 5 6 7 8 9 10 11 0 1 2 3 4
[,53] [,54] [,55] [,56] [,57] [,58] [,59] [,60] [,61] [,62] [,63] [,64] [,65] [,66] [,67] [,68] [,69]
[1,] 5 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3
[2,] 5 6 7 8 9 10 11 0 1 2 3 4 5 6 7 8 9
[,70] [,71] [,72] [,73] [,74] [,75] [,76] [,77] [,78] [,79] [,80] [,81] [,82] [,83] [,84] [,85] [,86]
[1,] 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2
[2,] 10 11 0 1 2 3 4 5 6 7 8 9 10 11 0 1 2
[,87] [,88] [,89] [,90] [,91] [,92] [,93] [,94] [,95] [,96] [,97] [,98] [,99] [,100]
[1,] 3 4 5 0 1 2 3 4 5 0 1 2 3 4
[2,] 3 4 5 6 7 8 9 10 11 0 1 2 3 4
根据?Vectorize
The arguments named in the vectorize.args argument to Vectorize are the arguments passed in the ... list to mapply. Only those that are actually passed will be vectorized; default values will not.
此处,在 OP 的函数中,'mods' 具有默认值。如果我们删除它
crt <- function(x, mods) {
sapply(mods, \(y) x %% y)
}
crt <- Vectorize(crt)
-测试
> crt(1:100, mods = c(5, 7))
[1] 1 2 3 4 0 6 2 1 4 3 1 5 3 0 0 2 2 4 4 6 1 1 3 3 0 5 2 0 4 2 1 4 3 6 0 1 2 3 4 5 1 0 3 2 0 4 2 6 4 1 1 3 3 5 0 0 2 2 4 4 1 6 3 1 0 3 2 5 4 0 1 2 3 4
[75] 0 6 2 1 4 3 1 5 3 0 0 2 2 4 4 6 1 1 3 3 0 5 2 0 4 2
> crt(1:100, mods = c(12, 60))
[1] 1 2 3 4 5 6 7 8 9 10 11 12 1 14 3 16 5 18 7 20 9 22 11 24 1 26 3 28 5 30 7 32 9 34 11 36 1 38 3 40 5 42 7 44 9 46 11 48 1
[50] 50 3 52 5 54 7 56 9 58 11 0 1 2 3 4 5 6 7 8 9 10 11 12 1 14 3 16 5 18 7 20 9 22 11 24 1 26 3 28 5 30 7 32 9 34 11 36 1 38
[99] 3 40
这里的输出格式在两个级别上确定 - 1) 默认使用 simplify = TRUE
的 sapply
和默认使用 SIMPLIFY = TRUE
[=24 的 Vectorize
=]
此外,根据定义的函数,Vectorize
在内部并不是真正需要的,它使用 *apply
函数进行循环,我们已经使用 [= 定义了 crt
13=] 在 'mods' 上循环。在这些参数上应用 %%
的函数是 %%
,默认情况下它已经是矢量化函数。
我想尝试一下模运算并编写了一些看似无辜的函数...但对以下意想不到的行为感到非常惊讶:
crt <- function(x, mods = c(5, 7)) {
sapply(mods, \(y) x %% y)
}
crt <- Vectorize(crt)
crt(20)
## [,1]
## [1,] 0
## [2,] 6
crt(55)
## [,1]
## [1,] 0
## [2,] 6
crt(1:100)
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14]
## [1,] 1 2 3 4 0 1 2 3 4 0 1 2 3 4
## [2,] 1 2 3 4 5 6 0 1 2 3 4 5 6 0
## [,15] [,16] [,17] [,18] [,19] [,20] [,21] [,22] [,23] [,24] [,25] [,26]
## [1,] 0 1 2 3 4 0 1 2 3 4 0 1
## [2,] 1 2 3 4 5 6 0 1 2 3 4 5
## [,27] [,28] [,29] [,30] [,31] [,32] [,33] [,34] [,35] [,36] [,37] [,38]
## [1,] 2 3 4 0 1 2 3 4 0 1 2 3
## [2,] 6 0 1 2 3 4 5 6 0 1 2 3
## [,39] [,40] [,41] [,42] [,43] [,44] [,45] [,46] [,47] [,48] [,49] [,50]
## [1,] 4 0 1 2 3 4 0 1 2 3 4 0
## [2,] 4 5 6 0 1 2 3 4 5 6 0 1
## [,51] [,52] [,53] [,54] [,55] [,56] [,57] [,58] [,59] [,60] [,61] [,62]
## [1,] 1 2 3 4 0 1 2 3 4 0 1 2
## [2,] 2 3 4 5 6 0 1 2 3 4 5 6
## [,63] [,64] [,65] [,66] [,67] [,68] [,69] [,70] [,71] [,72] [,73] [,74]
## [1,] 3 4 0 1 2 3 4 0 1 2 3 4
## [2,] 0 1 2 3 4 5 6 0 1 2 3 4
## [,75] [,76] [,77] [,78] [,79] [,80] [,81] [,82] [,83] [,84] [,85] [,86]
## [1,] 0 1 2 3 4 0 1 2 3 4 0 1
## [2,] 5 6 0 1 2 3 4 5 6 0 1 2
## [,87] [,88] [,89] [,90] [,91] [,92] [,93] [,94] [,95] [,96] [,97] [,98]
## [1,] 2 3 4 0 1 2 3 4 0 1 2 3
## [2,] 3 4 5 6 0 1 2 3 4 5 6 0
## [,99] [,100]
## [1,] 4 0
## [2,] 1 2
crt(x = 1:100, mods = c(12, 60))
## [1] 1 2 3 4 5 6 7 8 9 10 11 12 1 14 3 16 5 18 7 20 9 22 11 24 1
## [26] 26 3 28 5 30 7 32 9 34 11 36 1 38 3 40 5 42 7 44 9 46 11 48 1 50
## [51] 3 52 5 54 7 56 9 58 11 0 1 2 3 4 5 6 7 8 9 10 11 12 1 14 3
## [76] 16 5 18 7 20 9 22 11 24 1 26 3 28 5 30 7 32 9 34 11 36 1 38 3 40
为什么最后一个函数调用 crt(x = 1:100, mods = c(12, 60))
给出了完全不同的输出?第一个矢量化输出 crt(1:100)
是我想要和期望的,最后一个在结构上似乎没有什么不同,但结果是......为什么?我该如何解决这个问题以获得与第一个相同的输出?
如果您稍微调整一下代码
crt <- function(x, mods = c(5, 7)) {
sapply(mods, \(y) unlist(x %% y))
}
crt <- Vectorize(crt)
并使用不同的 mods
参数调用它,例如
crt(1:100, mods = list(c(6, 12)))
输出看起来像预期的那样:
> crt(1:100, list(c(6, 12)))
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14] [,15] [,16] [,17] [,18]
[1,] 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0
[2,] 1 2 3 4 5 6 7 8 9 10 11 0 1 2 3 4 5 6
[,19] [,20] [,21] [,22] [,23] [,24] [,25] [,26] [,27] [,28] [,29] [,30] [,31] [,32] [,33] [,34] [,35]
[1,] 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5
[2,] 7 8 9 10 11 0 1 2 3 4 5 6 7 8 9 10 11
[,36] [,37] [,38] [,39] [,40] [,41] [,42] [,43] [,44] [,45] [,46] [,47] [,48] [,49] [,50] [,51] [,52]
[1,] 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4
[2,] 0 1 2 3 4 5 6 7 8 9 10 11 0 1 2 3 4
[,53] [,54] [,55] [,56] [,57] [,58] [,59] [,60] [,61] [,62] [,63] [,64] [,65] [,66] [,67] [,68] [,69]
[1,] 5 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3
[2,] 5 6 7 8 9 10 11 0 1 2 3 4 5 6 7 8 9
[,70] [,71] [,72] [,73] [,74] [,75] [,76] [,77] [,78] [,79] [,80] [,81] [,82] [,83] [,84] [,85] [,86]
[1,] 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2
[2,] 10 11 0 1 2 3 4 5 6 7 8 9 10 11 0 1 2
[,87] [,88] [,89] [,90] [,91] [,92] [,93] [,94] [,95] [,96] [,97] [,98] [,99] [,100]
[1,] 3 4 5 0 1 2 3 4 5 0 1 2 3 4
[2,] 3 4 5 6 7 8 9 10 11 0 1 2 3 4
根据?Vectorize
The arguments named in the vectorize.args argument to Vectorize are the arguments passed in the ... list to mapply. Only those that are actually passed will be vectorized; default values will not.
此处,在 OP 的函数中,'mods' 具有默认值。如果我们删除它
crt <- function(x, mods) {
sapply(mods, \(y) x %% y)
}
crt <- Vectorize(crt)
-测试
> crt(1:100, mods = c(5, 7))
[1] 1 2 3 4 0 6 2 1 4 3 1 5 3 0 0 2 2 4 4 6 1 1 3 3 0 5 2 0 4 2 1 4 3 6 0 1 2 3 4 5 1 0 3 2 0 4 2 6 4 1 1 3 3 5 0 0 2 2 4 4 1 6 3 1 0 3 2 5 4 0 1 2 3 4
[75] 0 6 2 1 4 3 1 5 3 0 0 2 2 4 4 6 1 1 3 3 0 5 2 0 4 2
> crt(1:100, mods = c(12, 60))
[1] 1 2 3 4 5 6 7 8 9 10 11 12 1 14 3 16 5 18 7 20 9 22 11 24 1 26 3 28 5 30 7 32 9 34 11 36 1 38 3 40 5 42 7 44 9 46 11 48 1
[50] 50 3 52 5 54 7 56 9 58 11 0 1 2 3 4 5 6 7 8 9 10 11 12 1 14 3 16 5 18 7 20 9 22 11 24 1 26 3 28 5 30 7 32 9 34 11 36 1 38
[99] 3 40
这里的输出格式在两个级别上确定 - 1) 默认使用 simplify = TRUE
的 sapply
和默认使用 SIMPLIFY = TRUE
[=24 的 Vectorize
=]
此外,根据定义的函数,Vectorize
在内部并不是真正需要的,它使用 *apply
函数进行循环,我们已经使用 [= 定义了 crt
13=] 在 'mods' 上循环。在这些参数上应用 %%
的函数是 %%
,默认情况下它已经是矢量化函数。