何时使用应用函数

When to use the apply function

假设我有类似的东西:

# Create some data:
treatment <- round(runif(20, min = 0, max = 1),0)
d2 <- round(runif(20, min = 0, max = 1),0)
bxd2 <- treatment * d2
infection <- round(runif(20, min = 0, max = 100),0) 
lung <- round(runif(20, min = 0, max = 100),0) 
head <- round(runif(20, min = 0, max = 100),0) 

df <- data.frame(treatment, d2, bxd2, infection, lung, head)

rm(treatment, d2, bxd2, infection, lung, head)


reg_func <- function(i,data){
form <- paste(colnames(df)[i+3], c("treatment + d2 + bxd2"), sep = "~") 
form <- as.formula(form)
print(lm(form, data = data))
}

for (i in 1:3) {
name <- paste0("reg", i)
assign(name, reg_func(i, df))
}

现在这按照我想要的方式工作,我最终在工作区中分配了 reg1,...,regN(坏习惯,但适用于计量经济学)。

我现在的问题是:为什么我要将(类似于上面的内容)变成应用实例? for 循环看起来很简单,但我经常听到人们说“......你真的应该使用 [X]apply”。

并没有快多少:

> a <- seq(300)
> system.time(replicate(1000, sapply(a ,mean)))
   user  system elapsed 
  2.215   0.000   2.216 
> v <- c()
> system.time(replicate(1000, for(i in a){v <- c(v,mean(i))}))
   user  system elapsed 
  2.315   0.000   2.315 

但它可以防止这种情况发生:

> i <- 1
> for(i in a) mean(i)
> i
[1] 300

它让一切保持整洁:

> sapply(a ,mean)
> ls()
[1] "a"  
> for(i in a) mean(i)
> ls()
[1] "a"    "i"    

简短的回答是不用担心使用循环。使用 apply 的主要原因是,首先,在某些情况下它可以更高效,其次,它使代码更简洁。

但有时它并不能使代码更清晰。例如,如果您真的想要一堆名为 reg1 reg2 等的变量,而不是名为 reg 的列表,那么您的版本会更简洁。由于每次循环都在进行回归,因此性能差异将很小,因为无论您如何编码,大部分工作都在回归而不是循环中。

现在,出于很多原因,我认为名为 reg 的列表是存储这些结果的更有用的方法。例如,如果你想遍历它们,你可以只做 reg[[i]] 而不是粘贴字符串。但听起来您已经考虑过这个问题并出于某种原因决定这样命名变量。

是的,apply()真的不能再快了:

> mat <- matrix(rnorm(1000 * 1000), nrow = 1000)
> system.time({
+     v <- numeric(1000)
+     for (i in 1:1000) v[i] <- mean(mat[i, ])
+ })
## user  system elapsed 
## 0.021   0.001   0.023 
>
> system.time(apply(mat, 1, mean))
## user  system elapsed 
## 0.021   0.001   0.022

对于矩阵,如果你取什么意思,这样会更好:

> system.time(rowMeans(mat))
## user  system elapsed 
## 0.003   0.000   0.003 

但对于列表和数据框,lapply()sapply() 可能更快:

> system.time({
+     v <- numeric(1000)
+     for (i in 1:1000) v[i] <- mean(df[[i]])
+ })
## user  system elapsed 
## 0.015   0.000   0.016 
>
> system.time(sapply(df, mean))
## user  system elapsed 
## 0.008   0.000   0.008

因为R是一种脚本语言,速度通常比C++等低级语言慢。所以如果可能的话,使用这些嵌入了二进制代码或字节代码的函数,将节省