如何避免在 R 中的用户定义函数上使用 sapply()

How to avoid using sapply() on user defined functions in R

我是 R 编程的初学者。最近写了一个自定义函数如下:

foo <- function(x){
power <- 1:4
sum(x^power)
}

当 x 是单个数字时,此函数可以正常工作。例如,当 x = 1 时,结果为 4,当 x = 10 时,结果为 11110。但是,此函数不适用于向量。例如,当x <- c(1, 10)时,结果是10102,这不是我想要的。我想要的结果是一个向量,例如 4 11110。我知道这个问题可以通过在函数上使用 sapply() 或在函数内添加 for 循环来解决,但我认为可能还有另一种方法可以在不使用循环或“应用”函数的情况下重写函数。我尝试了不同的方法来重写函数但没有任何效果,有人可以帮我解决这个问题吗?谢谢!

我认为没有办法避免任何类型的隐式或显式循环,因为 power 是一个向量,而您将 x 传递给它,这是另一个向量。

这里有几个选项:

  1. 你最好的选择是 sapply(你已经猜到了)。
sapply(c(1, 10), foo)
#[1]     4 11110
  1. 另一种方法是使用 Vectorize,您无法“看到”循环但它仍然在下面循环,因为它是 mapply.
  2. 的包装器
Vectorize(foo)(c(1, 10))
#[1]     4 11110
  1. 使用outer
foo <- function(x){
  power <- 1:4
  rowSums(outer(x, power, `^`))
}
foo(c(1, 10))
#[1]     4 11110

显然您也可以编写一个简单的 for 循环并将 c(1, 10) 传递给它。

从数学上讲,一种简单直接的方法是重写 foo 函数,如下所示

foo <- function(x) {
  power <- 1:4
  ifelse(x==1,max(power),x*(x**(max(power))-1)/(x-1))
}

这给出了

> foo(c(1,10))
[1]     4 11110

这个有效:

foo <- function(x, power = 1:4){
  
  ind <- 1 + seq_along(power)
  power <- matrix(rep(power, length(x)), nrow = length(x), byrow = T)
  x <- as.matrix(x)
  
  m <- cbind(x, power)
  m <- m[, 1]^m[, ind]
  v <- rowSums(m)
  
  return(v)
  
}

foo(x = c(1, 10))
## [1]     4 11110

运行速度比使用 sapply(x foo) 快约 8.5 倍(当 foo 是长度为 == 1,000,000 的向量时)。来晚了,不知道各位能不能再优化一下内部结构