何时应该在 data.table 中使用 := 运算符?

91

data.table对象现在拥有一个:=运算符。这个运算符与所有其他赋值运算符不同的是什么?还有,它有什么用途,速度比其他赋值运算符快多少,以及在什么情况下应该避免使用它?

1个回答

98

这里有一个例子,展示了10分钟被缩短到1秒钟(来自首页的新闻)。它就像是对data.frame进行子分配,但每次不会复制整个表格。

m = matrix(1,nrow=100000,ncol=100)
DF = as.data.frame(m)
DT = as.data.table(m)

system.time(for (i in 1:1000) DF[i,1] <- i)
     user  system elapsed 
  287.062 302.627 591.984 

system.time(for (i in 1:1000) DT[i,V1:=i])
     user  system elapsed 
    1.148   0.000   1.158     ( 511 times faster )

j中的:=这样放置可以使用更多的习语:

DT["a",done:=TRUE]   # binary search for group 'a' and set a flag
DT[,newcol:=42]      # add a new column by reference (no copy of existing data)
DT[,col:=NULL]       # remove a column by reference
and :
DT[,newcol:=sum(v),by=group]  # like a fast transform() by group

我想不出有什么理由避免使用:=!除了在for循环内部。由于:=出现在DT[...]中,它带来了[.data.table方法的小开销;例如S3分配和检查参数的存在和类型,例如ibynomatch等。因此,在for循环内部,有一个低开销、直接版本的:=,称为set。请参见?set以获取更多详细信息和示例。 set的缺点包括必须是行号(没有二进制搜索)和不能与by结合使用。通过这些限制,set可以大大减少开销。

system.time(for (i in 1:1000) set(DT,i,"V1",i))
     user  system elapsed 
    0.016   0.000   0.018

28
感谢开发这个包。我有一种感觉,我将会修改很多我的代码来使用这个包。 - Iterator
5
@MatthewDowle 想要加入一个说明,即何时不使用:=而改用set()吗? - Ari B. Friedman
2
@MatthewDowle 如果可以的话,我会再点赞一次。 - Ari B. Friedman
1
@jabberwocky 不用担心,好的让我们看看。set() 的第三个参数只是一个列名(如 ?set 中所定义)。您可能希望这是字面值(例如 "V1")或保存在变量中(例如 colName,它可以包含 "V1""colA" 或其他列名)。DT[,] 内部的第二个参数始终是在数据表范围内计算的表达式。DT[,V1] 是最简单的情况,但像 DT[,V1*V2]DT[,sum(V1)] 这样的东西更常见。这有帮助吗? - Matt Dowle
3
@jabberwocky 没问题。set(DT, i, "V1", i) 会设置 "V1" 列,而 set(DT, i, colVar, i) 会设置 colVar 变量中包含的列名(例如,如果之前执行了 colVar = "V1")。引号表示字面上采用列名,而不是查找变量。 - Matt Dowle
显示剩余10条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接