让我们考虑以下三个数据框:
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))
Run Code Online (Sandbox Code Playgroud)
以下时间:
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
Run Code Online (Sandbox Code Playgroud)
迭代大数据帧的两个命令要慢一些.那些循环只是在内存中写入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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
R 3.1更快,但我们仍然有一些减速; 同样代表数据表.
编辑2:使用功能集
R 3.1.0上的数字相同,使用"set"函数而不是"[]"运算符
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
Run Code Online (Sandbox Code Playgroud)
这完全解决了性能问题.
您的代码很慢,因为[.<-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
Run Code Online (Sandbox Code Playgroud)
要解决此问题,您最好的操作是仅修改一次数据框:
untracemem(toto.big)
system.time({
toto.big[1:100, 2] <- 5
})
user system elapsed
0.02 0.00 0.02
Run Code Online (Sandbox Code Playgroud)
在那些在循环(或lapply)中计算值更方便的情况下,您可以在循环中对向量执行计算,然后在一个向量化分配中分配到数据帧中:
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
Run Code Online (Sandbox Code Playgroud)
您可以<-.data.frame通过`<-.data.frame`在控制台中键入来查看代码.
| 归档时间: |
|
| 查看次数: |
627 次 |
| 最近记录: |