R 数据表列删除速度
假设我有一个叫做“数据”的大表。我想删除变量cI中引用的列 这很快:R 数据表列删除速度,r,data.table,R,Data.table,假设我有一个叫做“数据”的大表。我想删除变量cI中引用的列 这很快: data = data[, eval(cI) := NULL] 这很慢: data[, eval(cI) := NULL] 这两种方法都有效(第二次使用不会打印(或返回)完整的表格。引擎盖下发生了什么事情使得第二种方法变慢了?显然,需要表格副本,但为什么 谜团加深了。我试着测量系统时间,第二种方法有很大的不同,这取决于我计时的方式: > system.time(data <- data[, eval(dropI
data = data[, eval(cI) := NULL]
这很慢:
data[, eval(cI) := NULL]
这两种方法都有效(第二次使用不会打印(或返回)完整的表格。引擎盖下发生了什么事情使得第二种方法变慢了?显然,需要表格副本,但为什么
谜团加深了。我试着测量系统时间,第二种方法有很大的不同,这取决于我计时的方式:
> system.time(data <- data[, eval(dropI) := NULL])
user system elapsed
0.004 0.000 0.003
> system.time(data[, eval(dropI) := NULL])
user system elapsed
0.004 0.000 0.003
> date(); data[, eval(dropI) := NULL]; date()
[1] "Wed Jan 15 12:31:51 2014"
[1] "Wed Jan 15 12:31:58 2014"
> date(); data <- data[, eval(dropI) := NULL]; date()
[1] "Wed Jan 15 12:32:26 2014"
[1] "Wed Jan 15 12:32:26 2014"`
>系统时间(数据系统时间(数据[,评估(dropI):=NULL])
用户系统运行时间
0.004 0.000 0.003
>日期();数据[,评估(下降):=NULL];日期()
[1] “2014年1月15日星期三12:31:51”
[1] “2014年1月15日星期三12:31:58”
>date();data没有证据表明运行时间存在差异:
set.seed(41)
dt <- data.table( a = rnorm(1000000), b = rnorm(1000000), c = rnorm(1000000) )
library( microbenchmark )
library( ggplot2 )
mb <- microbenchmark(
m1 = { x <- copy( dt ); x[ , c:= NULL ] },
m2 = { x <- copy( dt ); x = x[ , c:= NULL ] },
times = 500
)
# plot
qplot( data = mb, x = expr, y = time, geom = "boxplot", ylab="time [ns]", xlab = "approach" )
# show evidence
t.test( time ~ expr, data = mb )
及
[从Matt编辑时间]这些时间包括复制(dt)
的时间,这似乎是为了重复删除列。请参见如何复制(dt)
出现在上面的m1
和m2
定义中。这就是为什么时间变化如此之大,甚至最好的时间也非常缓慢的原因。简言之,这个基准似乎有缺陷。如果copy(dt)
被排除在基准之外,您应该会发现删除列的时间几乎总是无法测量的(即0.00s)对于m1
和m2
两种方法。这个答案是正确的,即m1
和m2
之间没有区别,但是一旦定时copy(dt)
被隔离,图表应该在0.00s处显示一条平线
为了澄清这一点,@eddi和@joran在评论中的观点是正确的
以下各项之间绝对没有速度差:
data = data[, eval(cI) := NULL]
及
因为,两者都立即执行,一致性(0.000s)。另一个答案是计时copy(dt)
,请参见此处的编辑
顺便说一句,您不需要eval
,只需括号即可:
data = data[, (cI) := NULL]
或
发生的情况是,您正在控制台上键入这些命令。由于第一个命令是赋值,因此值data
以不可见的方式返回,而R不打印它。R打印第二个方法的结果
就像data.frame
一样,键入DT
与print(DT)
在速度上有巨大差异:
在这个问题上,你的结论是复印件被拿走了,你是对的。但是通过打印,而不是删除列
可能是因为DF
打印整个DF
,速度太慢了,在开始将整个DF
转换为字符形式之前,没有人注意到R也复制了DF
。由于默认情况下DT
打印表的顶部和底部,这非常快,您会注意到R需要多长时间来复制是啊,反正是这样的
我不知道这到底是为什么,但这已经是众所周知的一段时间了。在R的当前开发版本中有一些减少拷贝的变化,我希望这些变化将减少被称为自动打印的拷贝
同时,调用print(DT)
明确地说,为了节省内存,打印!请提供一些证据,证明第二种方法速度较慢。经过一点快速的实验,我至少看不到它。奇怪的是,它对我来说非常慢。由于许多原因,我无法提供数据帧,这似乎与数据帧有关。谜团加深了。我试图测量系统时间,第二种方法根据我计时的方式有很大的不同:>system.TIME(数据系统时间(数据[,eval(dropI):=NULL])用户系统运行时间0.004 0.000 0.003>date();data[,eval(dropI):=NULL];date()[1]“Wed Jan 15 12:31:51 2014”[1]“Wed Jan 15 12:31:58”>date();数据我可以很容易地复制您的观察结果,而且我相当肯定这与@eddi是同一个问题,这是一个很好的观点;我没有说得很清楚;所谓“隐式调用print()”,我指的是在控制台键入和按enter键以及调用print()之间的区别这是一个很好的研究,但请看我对原始帖子的补充:根据观察结果,行为似乎有所不同(海森堡效应!)@rimorob事实上,这个答案是有缺陷的。@MattDowle如果一种方法比另一种方法慢,这将导致大量重复的运行时的平均值发生显著变化(当然,假设copy(dt)
的运行时为H0)。我没有说,显示的运行时是由于列的删除。我说没有显著差异,这是最初的假设。@Beasterfield,但这些时间完全由copy(dt)控制
。它们与列删除无关。用任何其他快速任务替换“列删除”,你会得出相同的结论。你只需要计算列删除的时间。@MattDowle无意冒犯,但恐怕我不同意:如果迭代次数足够多,你不必只计算列删除的时间。以下是一个最小值问题模拟:rrontime,但重点是避免打印。事实上,没有打印发生(在date()块内)@rimorob那么我现在完全糊涂了!我认为你关于打印的看法是对的,尽管这只是一种预感:我认为当你使用一个没有明显函数的数据帧时,它会打印到某个地方。在代码块内,例如date();df[,];date(),它可能打印到某个空缓冲区,但没有意识到它无论如何都不会被显示——有点像perl@rimorob哦,我明白了。是的,很可能就是这样。
data[, eval(cI) := NULL]
data = data[, (cI) := NULL]
data[, (cI) := NULL]
> DT # very slow. R copies the whole of DT for some reason
> print(DT) # very fast. R doesn't copy DT.