[英]How to define multiple variables with lapply?
我想將具有不同值的多個變量的函數應用於列表。 我知道如何使用一個變化的變量來做到這一點
sapply(c(1:10), function(x) x * 2)
# [1] 2 4 6 8 10 12 14 16 18 20
但不是兩個。 我首先手動向你展示我想要的東西(實際上我使用lapply()
但sapply()
在SO中更具概要性):
# manual
a <- sapply(c(1:10), function(x, y=2) x * y)
b <- sapply(c(1:10), function(x, y=3) x * y)
c <- sapply(c(1:10), function(x, y=4) x * y)
c(a, b, c)
# [1] 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30 4 8 12
# [24] 16 20 24 28 32 36 40
這是我試圖定義x
和y
嘗試。
# attempt
X <- list(x = 1:10, y = 2:4)
sapply(c(1:10, 2:4), function(x, y) x * y)
# Error in FUN(X[[i]], ...) : argument "y" is missing, with no default
解決方案的基准
library(microbenchmark)
microbenchmark(sapply = as.vector(sapply(1:10, function(x, y) x * y, 2:4)),
mapply = mapply( FUN = function(x, y) x * y, 1:10, rep( x = 2:4, each = 10)),
sapply2 = as.vector(sapply(1:10, function(y) sapply(2:4, function(x) x * y))),
outer = c(outer(1:10, 2:4, function(x, y) x * y)))
# Unit: microseconds
# expr min lq mean median uq max neval
# sapply 34.212 36.3500 62.44864 39.1295 41.9090 2304.542 100
# mapply 62.008 65.8570 87.82891 70.3470 76.5480 1283.342 100
# sapply2 196.714 203.9835 262.09990 223.6550 232.2080 3344.129 100
# outer 7.698 10.4775 13.02223 12.4020 13.4715 53.883 100
mapply()
將函數應用於多個列表或向量參數。
rep()
也用於重復值2,3和4.在each
參數中指定10, rep()
重復x
每個元素10次。
這是必要的,因為mapply()
- 1:10中的第一個參數長度為10。
# supply the function first, followed by the
# arguments in the order in which they are called in `FUN`
mapply( FUN = function(x, y) x * y
, 1:10
, rep( x = 2:4, each = 10)
)
# [1] 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30 4 8 12 16 20
# [26] 24 28 32 36 40
首先,如果你的函數是矢量化的,你可以用lapply()
來做這個。 在這種情況下,它是:
x <- 1:10
unlist(lapply(2:4, function(y) x*y))
# OR
unlist(lapply(2:4, function(x=x,y) x*y))
其次,如果需要對兩個向量的每個組合應用函數,請使用outer()
:
xf <- 1:10
yf <- 2:4
c(xf %o% yf)
# OR spelled out for any function:
c(outer(xf,yf,FUN = `*`))
如果使用mapply,則可以使用參數MoreArgs
來避免使用rep
來構造參數:
xf <- 1:10
yf <- 2:4
mapply(function(x,y) x*y,
y = yf,
MoreArgs = list(x = xf))
這與我上面展示的lapply()
構造完全等效。 生成的矩陣也可以使用SIMPLIFY = FALSE
和unlist()
轉換為向量:
unlist(mapply(function(x,y) x*y,
y = yf,
MoreArgs = list(x = xf),
SIMPLIFY = FALSE))
哪種解決方案最方便,取決於您的實際用例。 時間方面它們都是可比的,在最近的R版本中,可能outer()
將比其他解決方案慢一點。
為了說明結果如何根據對象的大小和順序而大不相同,我包括以下基准測試結果(下面的代碼和輸出)。 這表明:
outer()
不一定是最快的解決方案,盡管它通常是最快的解決方案之一。 mapply()
手動重復一個向量會增加很多開銷,即使是double sapply()
調用也會更快。 代碼: 警告:這將運行一段時間
fx <- sample(1e4)
fy <- sample(1e3)
library(microbenchmark)
microbenchmark(sapply = as.vector(sapply(fx, function(x, y) x * y, fy)),
mapply = mapply( FUN = function(x, y) x * y, fx, rep( fy, each = 1e4)),
sapply2 = as.vector(sapply(fx, function(y) sapply(fy, function(x) x * y))),
outer = c(outer(fx, fy, function(x, y) x * y)),
mapply2 = mapply(function(x,y) x*y, x=fx, MoreArgs = list(y = fy)),
mapply3 = mapply(function(x,y) x*y, y=fy, MoreArgs = list(x = fx)),
times = 15)
我機器上的輸出:
Unit: milliseconds
expr min lq mean median uq max neval cld
sapply 89.52318 92.98653 344.1538 117.11280 239.64887 1485.3178 15 a
mapply 20471.02137 22925.42757 24478.5985 24650.29055 25627.31232 28840.3494 15 c
sapply2 7472.02251 8268.04696 9519.8016 8707.19193 9528.46181 14182.7537 15 b
outer 77.62331 85.94651 189.5107 91.83722 182.08506 1119.6620 15 a
mapply2 77.76871 79.71924 143.9484 81.24168 84.53247 971.1792 15 a
mapply3 65.21709 71.85662 107.9586 73.80779 124.21141 242.0760 15 a
嘗試outer
:
c(outer(1:10, 2:4, Vectorize(function(x, y) x*y)))
## [1] 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30 4 8 12 16 20
## [26] 24 28 32 36 40
如果函數已經被矢量化,就像在這里一樣,那么我們可以省略Vectorize
:
c(outer(1:10, 2:4, function(x, y) x * y))
## [1] 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30 4 8 12 16 20
## [26] 24 28 32 36 40
實際上,在這種特殊情況下,顯示的匿名函數是默認函數,因此這將起作用:
c(outer(1:10, 2:4))
## [1] 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30 4 8 12 16 20
## [26] 24 28 32 36 40
在這個特殊情況下我們也可以使用:
c(1:10 %o% 2:4)
## [1] 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30 4 8 12 16 20
## [26] 24 28 32 36 40
如果您的起點是問題中顯示的列表X
,那么:
c(outer(X[[1]], X[[2]], Vectorize(function(x, y) x * y)))
## [1] 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30 4 8 12 16 20
## [26] 24 28 32 36 40
要么
c(do.call("outer", c(unname(X), Vectorize(function(x, y) x*y))))
## [1] 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30 4 8 12 16 20
## [26] 24 28 32 36 40
如果適用,前面部分適用於縮短它的地方。
另一個想法是兩次使用sapply
。
as.vector(sapply(2:4, function(y) sapply(1:10, function(x) x * y)))
[1] 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30 4 8 12 16 20 24 28 32 36 40
或者我們可以使用map2_int
從purrr
包。 map2_int
可以遍歷兩個長度相同的向量,並確保輸出為整數。 所以我們需要使用rep(a, length(b))
和rep(b, each = length(a))
來確保每個元素都是成對的。 purrr
~.x * .y
是在purrr
指定函數的簡潔方法。
library(purrr)
a <- 1:10
b <- 2:4
map2_int(rep(a, length(b)), rep(b, each = length(a)), ~.x * .y)
# [1] 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30 4 8 12 16 20 24 28 32 36 40
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.