让我们考虑以下三个数据框:
toto.small <- data.frame(col1=rep(1,850), col2=rep(2,850))
toto.medium <- data.frame(col1=rep(1,85000), col2=rep(2,85000))
toto.big <- data.frame(col1=rep(1,850000), col2=rep(2,850000))
下面的时间安排:
system.time(for(i in 1:100) { toto.small[i,2] <- 3 })
user system elapsed
0.004 0.000 0.006
system.time(for(i in 1:100) { toto.medium[i,2] <- 3 })
user system elapsed
0.088 0.000 0.087
system.time(for(i in 1:100) { toto.big[i,2] <- 3 })
user system elapsed
2.248 0.000 2.254
在小数据框架上迭代两个命令要慢一些。 那些循环只是在内存中写入100个预先分配的元素;时间不应该取决于数据帧的总长度。
有谁知道这个的原因?
我仍然会在数据表和应用函数方面获得类似的时差。
编辑1:R 3.0.2对比R 3.1
对于那些好奇的人来说,data.table和data.frame的时间安排为R v.3.1和3.0.2(我每次测量3次):
R 3.0.2
type size time1 time2 time3
data frame small 0.005 0.005 0.005
data frame medium 0.074 0.077 0.075
data frame big 3.184 3.373 3.101
data table small 0.048 0.048 0.047
data table medium 0.073 0.068 0.066
data table big 0.615 0.621 0.593
R 3.1
type size time1 time2 time3
data frame small 0.004 0.004 0.004
data frame medium 0.021 0.020 0.022
data frame big 0.221 0.207 0.243
data table small 0.055 0.055 0.055
data table medium 0.076 0.076 0.076
data table big 0.705 0.699 0.663
R 3.1更快,但我们仍然有些减速;同样代表数据表。
编辑2:使用功能设置
R 3.1.0上的相同数字,使用函数&#34; set&#34;而不是&#34; []&#34;操作
type size time1 time2 time3
data frame small 0.0249999999 0.0020000000 0.0009999999
data frame medium 0.0010000000 0.0009999999 0.0010000000
data frame big 0.0010000000 0.0000000000 0.0009999999
data table small 0.0009999999 0.0209999999 0.0000000000
data table medium 0.0009999999 0.0009999999 0.0010000000
data table big 0.0000000000 0.0029999999 0.0009999999
这完全解决了性能问题。
答案 0 :(得分:5)
您的代码很慢,因为每次修改对象时,函数[.<-data.frame
都会复制基础对象。
如果跟踪内存使用情况,则会变得清晰:
tracemem(toto.big)
system.time({
for(i in 1:100) { toto.big[i,2] <- 3 }
})
tracemem[0x000000001d416b58 -> 0x000000001e08e9f8]: system.time
tracemem[0x000000001e08e9f8 -> 0x000000001e08eb10]: [<-.data.frame [<- system.time
tracemem[0x000000001e08eb10 -> 0x000000001e08ebb8]: [<-.data.frame [<- system.time
tracemem[0x000000001e08ebb8 -> 0x000000001e08e7c8]: system.time
tracemem[0x000000001e08e7c8 -> 0x000000001e08e758]: [<-.data.frame [<- system.time
tracemem[0x000000001e08e758 -> 0x000000001e08e800]: [<-.data.frame [<- system.time
....
tracemem[0x000000001e08e790 -> 0x000000001e08e838]: system.time
tracemem[0x000000001e08e838 -> 0x000000001e08eaa0]: [<-.data.frame [<- system.time
tracemem[0x000000001e08eaa0 -> 0x000000001e08e790]: [<-.data.frame [<- system.time
user system elapsed
4.31 1.01 5.29
要解决此问题,您的最佳操作是仅修改一次数据框:
untracemem(toto.big)
system.time({
toto.big[1:100, 2] <- 5
})
user system elapsed
0.02 0.00 0.02
在循环(或lapply
)中计算值更方便的情况下,您可以在循环中对向量执行计算,然后在一个向量化分配中分配到数据帧中: / p>
system.time({
newvalues <- numeric(100)
for(i in 1:100)newvalues[i] <- rnorm(1)
toto.big[1:100, 2] <- newvalues
})
user system elapsed
0.02 0.00 0.02
您可以在控制台中输入<-.data.frame
来查看`<-.data.frame`
的代码。