R 数据表列删除速度

R 数据表列删除速度,r,data.table,R,Data.table,假设我有一个叫做“数据”的大表。我想删除变量cI中引用的列 这很快: data = data[, eval(cI) := NULL] 这很慢: data[, eval(cI) := NULL] 这两种方法都有效(第二次使用不会打印(或返回)完整的表格。引擎盖下发生了什么事情使得第二种方法变慢了?显然,需要表格副本,但为什么 谜团加深了。我试着测量系统时间,第二种方法有很大的不同,这取决于我计时的方式: > system.time(data <- data[, eval(dropI

假设我有一个叫做“数据”的大表。我想删除变量cI中引用的列

这很快:

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.