何时使用应用函数
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++等低级语言慢。所以如果可能的话,使用这些嵌入了二进制代码或字节代码的函数,将节省
假设我有类似的东西:
# 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++等低级语言慢。所以如果可能的话,使用这些嵌入了二进制代码或字节代码的函数,将节省