为什么这么慢?(循环在DF行与独立向量)

not*_*tuo 6 performance r

我有一段代码,总耗时约为30秒,下面的代码大约是27秒.我将违规代码缩小到这个:

d$dis300[i] <- h
Run Code Online (Sandbox Code Playgroud)

所以我换到另一件,现在工作得非常快(正如预期的那样).

我的问题是为什么这对第二个太慢了.数据DF约为7500x18变量

第一:( 27秒过去了)

d$dis300 <- 0
for (i in 1:netot) {
  h <- aaa[d$ent[i], d$dis[i]]
  if (h == 0) writeLines(sprintf("ERROR. ent:%i dis:%i", d$ent[i], d$dis[i]))
  d$dis300[i] <- h
}
Run Code Online (Sandbox Code Playgroud)

第二:(0.2秒过去了)

d$dis300 <- 0
for (i in 1:netot) {
  h <- aaa[d$ent[i], d$dis[i]]
  if (h == 0) writeLines(sprintf("ERROR. ent:%i dis:%i", d$ent[i], d$dis[i]))
  foo[i] <- h
}
d$foo <- foo
Run Code Online (Sandbox Code Playgroud)

你可以看到两者都是"相同的",但有一个人有这个DF而不是一个向量.

任何评论都非常感谢.我来自另一种语言,这让我疯了一会儿.至少我有解决方案,但我希望将来能够防止这类问题.

谢谢你的时间,

Tom*_*mmy 10

原因是d$dis300[i] <- h电话$<-.data.frame.

这是一个相当复杂的功能,你可以看到:

`$<-.data.frame`
Run Code Online (Sandbox Code Playgroud)

你没有说是什么foo,但如果它是一个原子向量,该$<-函数是用C实现的.

不过,我希望你声明foo如下:

foo <- numeric(netot)
Run Code Online (Sandbox Code Playgroud)

这将确保您不需要为循环中的每个赋值重新分配向量:

foo <- 0 # BAD!
system.time( for(i in 1:5e4) foo[i] <- 0 ) # 4.40 secs
foo <- numeric(5e4) # Pre-allocate
system.time( for(i in 1:5e4) foo[i] <- 0 ) # 0.09 secs
Run Code Online (Sandbox Code Playgroud)

使用*apply家庭而不是担心:

d$foo <- vapply(1:netot, function(i, aaa, ent, dis) {
  h <- aaa[ent[i], dis[i]]
  if (h == 0) writeLines(sprintf("ERROR. ent:%i dis:%i", ent[i], dis[i]))
  h
}, numeric(1), aaa=aaa, ent=d$ent, dis=d$dis)
Run Code Online (Sandbox Code Playgroud)

...在这里我也提取d$entd$dis在循环之外,这应该改善一些事情.由于您没有提供可重现的数据,因此无法自行运行.但这是一个类似的例子:

d <- data.frame(x=1)
system.time( vapply(1:1e6, function(i) d$x, numeric(1)) )         # 3.20 secs
system.time( vapply(1:1e6, function(i, x) x, numeric(1), x=d$x) ) # 0.56 secs
Run Code Online (Sandbox Code Playgroud)

...但最后它似乎都可以减少为(除非您的错误检测代码):

d$foo <- aaa[cbind(d$ent, d$dis)]
Run Code Online (Sandbox Code Playgroud)

  • 看到隐藏在泥沼中的单线程的+3互联网. (4认同)