【问题标题】:Lapply over several parameters, faster method覆盖多个参数,更快的方法
【发布时间】:2019-01-02 01:30:32
【问题描述】:

假设我有两个向量

 a <- c(1,2,3,4,5)
 b <- c(6,7,8,9,10)

还有一个函数

calc <- function(x,y){x + y)

我想将这个函数应用于a 中的第一个值,用于b 中的每个值。假设在我的情况下calc 只允许来自ab 的单个值作为输入,所以lapply(a,calc,b) 将不起作用,因为长度(b)不是1(给我一个错误)。

另外mapply 也没有给我想要的解决方案,它只将函数应用于配对值,即1+62+7 等。

所以我构建了一个函数,它给了我想要的解决方案

myfunc <- function(z){lapply(a,calc,z)}

并将其应用于 b

solution <- lapply(b,myfunc)

我们在这里看到lapply(a,calc,b) 或嵌套lapply(a,lapply,calc,b) 的区别在于它为我提供了自己列表中的所有值。这就是我想要的,或者至少它是一个给我正确结果且没有错误的函数。

现在,有没有更快/更简单的方法,因为我只是在这里做了一点实验。而且我的函数比calc 大得多,需要10分钟,但也许我必须精简我的原始函数,这里不会有更快的方法......

编辑:

在我的函数中有这样的东西,

calc <- function(x,y){
# ...
number <- x
example <- head(number,n=y)
# ...
}

向量作为 y 的输入不再起作用。使用lapply(a,lapply,calc,b)lapply(a,calc,b) 时出现错误,

Error in head.default(number, n = y) : length(n) == 1L is not TRUE 

【问题讨论】:

  • 不返回列表中的结果,但也许你可以使用outer(a,b,calc)?
  • @Florian 需要小心外部,function 需要正确矢量化
  • 在@AkselA 的回复下查看我的评论...
  • 我很困惑。我们已经知道您的函数只接受标量或单个值作为输入。在评论中,您询问了如何访问值,那是关于什么的?和你提到的线性回归有什么关系吗?
  • 好吧,我的函数输出是线性回归的拟合,使用我的解决方案我可以简单地访问它们,但是使用您的解决方案导致矩阵拟合似乎被拆分了。该解决方案应该有 5x5 拟合,因此矩阵中有 25 个元素,但您的矩阵中有 300 个元素......

标签: r apply lapply mapply


【解决方案1】:

正如弗洛里安所说,outer() 可能是一个选择。

outer(a, b, calc)
#      [,1] [,2] [,3] [,4] [,5]
# [1,]    7    8    9   10   11
# [2,]    8    9   10   11   12
# [3,]    9   10   11   12   13
# [4,]   10   11   12   13   14
# [5,]   11   12   13   14   15

但正如 MichaelChirico 所提到的,使用未矢量化的函数将无法工作。在这种情况下,必须一起破解其他东西。这些可能会或可能不会比您当前的解决方案更快。

所有组合(因此calc(1, 6)calc(6, 1) 都被执行,类似于outer()

计算次数:n2

eg <- expand.grid(a, b)

m1 <- mapply(calc, eg[,1], eg[, 2])
matrix(m1, 5)
#      [,1] [,2] [,3] [,4] [,5]
# [1,]    7    8    9   10   11
# [2,]    8    9   10   11   12
# [3,]    9   10   11   12   13
# [4,]   10   11   12   13   14
# [5,]   11   12   13   14   15

只有唯一的组合(所以假设你的函数是对称的)

计算次数:(n2 - n) / 2

cn <- t(combn(1:length(a), 2))

m2 <- mapply(calc, a[cn[, 1]], b[cn[, 2]])
mat <- matrix(, length(a), length(a))
mat[upper.tri(mat)] <- m2
mat
#      [,1] [,2] [,3] [,4] [,5]
# [1,]   NA    8    9   10   11
# [2,]   NA   NA   10   11   12
# [3,]   NA   NA   NA   12   13
# [4,]   NA   NA   NA   NA   14
# [5,]   NA   NA   NA   NA   NA

第二个忽略对角线,但添加这些值很容易,因为这就是 OPs mapply() 调用返回的内容。

diag(mat) <- mapply(calc, a, b)
mat
#      [,1] [,2] [,3] [,4] [,5]
# [1,]    7    8    9   10   11
# [2,]   NA    9   10   11   12
# [3,]   NA   NA   11   12   13
# [4,]   NA   NA   NA   13   14
# [5,]   NA   NA   NA   NA   15

【讨论】:

  • 如上所述outer() 不适用于我的函数,因为我需要单个输入值(这就是为什么 lapply / 嵌套 lapply 也不起作用)。您使用 mapply 计算的第二个命题没有错误。结果值符合线性回归 (fit &lt;- lm(value1~value2)),我将如何访问它们? (m 是matrix
  • 使用我自己的函数,输出是一个列表,我可以通过for (i in 1:length(solution)){ for (j in 1:length(solution[[i]])){ print(summary(solution[[i]][[j]])) }访问它们
  • @jackbauer:如果您将这些详细信息添加到您的问题中可能会更好。也许给你的实际数据的一个示例子集?或者您可以使用像 mtcars 这样的内置数据集来解释您的问题。
【解决方案2】:

这为我解决了这个问题,将SIMPLIFY=FALSE 添加到mapply 函数中,感谢@AkselA。

eg <- expand.grid(a, b)

m1 <- mapply(calc, eg[,1], eg[, 2],SIMPLIFY=FALSE)

但是,这种方法只比我在我的 OP 中自己的解决方案快一点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多