我写了一段R代码,但由于我不是专家,我觉得我的代码不是最优的,而且处理时间太长...... 如何改进此代码?
这是代码:
for (k in 1 : length(df_3L)) {
vec <- c()
for(i in 1 : dim(df_3L[[k]])[1]) {
for(j in 1 : dim(df_3L[[k]])[1] - 1) {
if (df_3L[[k]][i] == df_3L[[k]][j + 1]) {
vec <- c(vec, 1)
} else {
vec <- c(vec, 0)
}
}
}
assign(paste0("vec_3L", k), vec)
}
有关详细信息,for循环中的k
是主题数(40); df_3L
文件是500行的向量。
答案 0 :(得分:3)
您的代码运行缓慢,因为您正在循环中生成向量。这是典型的反模式,例如this article by Andrew Barr,参见无数其他模式。
解决方案是(1)预分配矢量并在特定索引处分配值,或者(2)放弃循环并使用列表函数(例如lapply
)创建矢量。在你的情况下,由于嵌套循环而变得更难(尽管不是不可能)。因此,变体(1)开箱即可轻松实现:
替换
vec <- c()
与
vec = vector("numeric", dim(df_3kL[[k]])[1] * (dim(df_3kL[[k]])[1] - 1))
用
替换整个内循环if
vec[i] = if (df_3kL[[k]][i] == df_3kL[[k]][j + 1]) 1 else 0
现在,这不是好的代码。通过矢量化来改进它是留给读者的练习。
此外,您可以通过一致使代码立即可读:不要混合样式(例如<-
vs =
赋值,seq
vs :
...)中间代码。
答案 1 :(得分:1)
您的代码运行缓慢,因为您正在执行紧密的内部循环,而不是依赖于矢量化函数。
使用模拟数据计时原始实现表明它确实很慢:
df_3L <- replicate(10, matrix(runif(200), nrow = 200), simplify = FALSE)
system.time({
for (k in 1 : length(df_3L)) {
vec <- c()
for(i in 1 : dim(df_3L[[k]])[1]) {
for(j in 1 : dim(df_3L[[k]])[1] - 1) {
if (df_3L[[k]][i] == df_3L[[k]][j + 1]) {
vec <- c(vec, 1)
} else {
vec <- c(vec, 0)
}
}
}
assign(paste0("vec_3L", k), vec)
}
})
## user system elapsed
## 21.270 0.008 21.599
任何时候你在R中的if .. else
循环中看到for
,你就可以确定它会变慢。解决方案是认识到我们可以一次完成比较而不是一次比较。这使我们可以摆脱整个内部循环,并大大加快代码速度:
system.time({
for (k in 1 : length(df_3L)) {
vec <- c()
for(i in 1 : dim(df_3L[[k]])[1]) {
vec <- c(vec, as.numeric(df_3L[[k]][i] == df_3L[[k]]))
}
assign(paste0("vec_3L", k), vec)
}
})
## user system elapsed
## 0.114 0.000 0.114
事实上,我们甚至不需要i
循环,为方便起见,我们可以使用lapply
代替k
循环。最终的惯用和快速实现可能如下所示:
system.time({
vecs <- lapply(df_3L, function(x) {
x <- x[, 1]
as.numeric(do.call(`==`, expand.grid(x, x)))
})
})
## user system elapsed
## 0.016 0.000 0.016