R 为data.table对象编写函数(过程)
在《数据分析软件:用R编程》一书中,约翰·钱伯斯强调,编写函数通常不应考虑其副作用;相反,函数应该在不修改其调用环境中的任何变量的情况下返回值。相反,使用data.table对象编写好的脚本应该特别避免使用对象赋值R 为data.table对象编写函数(过程),r,data.table,R,Data.table,在《数据分析软件:用R编程》一书中,约翰·钱伯斯强调,编写函数通常不应考虑其副作用;相反,函数应该在不修改其调用环境中的任何变量的情况下返回值。相反,使用data.table对象编写好的脚本应该特别避免使用对象赋值是的,添加、修改和删除数据中的列。tables是通过引用完成的。从某种意义上说,这是一件好事,因为data.table通常包含大量数据,每次对其进行更改时都重新分配这些数据将非常耗费内存和时间。另一方面,这是一件坏事,因为它违背了默认情况下R试图通过使用传递值来推广的无副作用函数式编程
是的,添加、修改和删除数据中的列。table
s是通过引用完成的。从某种意义上说,这是一件好事,因为data.table
通常包含大量数据,每次对其进行更改时都重新分配这些数据将非常耗费内存和时间。另一方面,这是一件坏事,因为它违背了默认情况下R试图通过使用传递值来推广的无副作用
函数式编程方法。由于编程没有副作用,因此在调用函数时无需担心:您可以放心,您的输入或环境不会受到影响,您可以只关注函数的输出。它很简单,因此很舒服
当然,如果你知道自己在做什么,就可以无视约翰·钱伯斯的建议。关于写“好”DATA表,这里有几个我会考虑的规则,如果我是你,作为一种限制复杂性和副作用数量的方法:
- 一个函数不应修改多个表,即修改该表应是唯一的副作用
- 如果函数修改表,则将该表作为函数的输出。当然,您不想重新分配它:只需运行
do.something.to(table)
而不是table文档可以改进(非常欢迎您的建议),但下面是目前的内容。也许它应该说“即使在职能范围内”
在?“:=”
:
data.tables不会在更改时通过:=、setkey或任何其他set*函数进行复制。见副本
通过引用修改DT,并返回新值。如果您需要副本,请先复制一份(使用DT2=copy(DT))。回想一下,此软件包适用于大型数据(混合列类型,具有多列键),其中通过引用进行更新比复制整个表快很多数量级
在?copy
(但我意识到这在setkey中是混乱的):
输入通过引用修改,并返回(不可见),以便
用于复合语句;e、 g.,设定键(DT,a)[J(“foo”)]。如果你
需要一份拷贝,先拷贝一份(使用DT2=copy(DT))。复制()可以吗
有时在以下情况下也很有用:=用于通过
参考资料。看到了吗?收到。请注意,setattr也位于包位中。二者都
包仅在C级别公开R的内部setAttrib函数,但是
返回值不同。位::setattr将NULL(不可见)返回给
提醒您该功能是用于其副作用。
setattr返回已更改的对象(不可见),以便在中使用
复合语句
有趣的是,关于bit::setattr
的最后两句话与flodel的第2点有关
另请参见以下相关问题:
我非常喜欢你问题的这一部分:
这使得为data.table对象编写过程成为可能,
结合data.table的速度和
函数
是的,这绝对是我们的意图之一。考虑数据库是如何工作的:许多不同的用户/程序通过引用(插入/更新/删除)数据库中的一个或多个(大)表而改变。这在数据库领域工作得很好,更像data.table的想法。因此,主页上的svSocket视频,以及对插入和删除的渴望(通过引用,仅动词,副作用函数)。修改参数在某些圈子中不受重视,但在另一些圈子中,它不被视为副作用(让它指修改不在参数列表中的内容)。也就是说,我对这种行为很好奇。函数没有注意到这一点[.data.table正在修改参数?或者可能只有实际赋值触发局部变量的创建。@MatthewLundberg我将添加一个答案,但基本上是数据。table
故意偏离R的写时复制。数据。table
不是写时复制,即使在函数中也是如此。如果您真的想复制20GB的data.table,您需要将x=copy(x)
放在函数的开头,或者在函数内部写入x=copy(x)[,y:=V1*V2]
。@MatthewLundberg我认为这在大多数循环中被认为是一种副作用。@hadley这与我写的内容并不矛盾。在C代码中,一个修改过的参数被认为是正常活动(查看标准库中的数百个示例)C++消除了对这些构造的需要,但是,C仍然被使用,并且非const参数仍然通过。@ hadley Matthew说,IIUC,将某个东西传递到一个要被引用修改的函数与在它的范围之外的函数和修改它没有通过的东西略有不同。后者绝对是SI。de effect.在C中,这可能会更改一个全局变量,在R中,在.GlobalEnv中创建或更改一个变量。有些人会说修改显式传入的参数比这更安全,并且不使用副作用来描述,其他人会这样做。很好的建议。我关心的是第2点,返回修改后的表,这会向scr发送垃圾邮件即使是在交互模式下的大表。但不用担心,它不会打印全部内容。data.table开发者们很荣幸。+1回答得很好,flodel。不过,您能否详细说明一下为什么运行table+1也是个坏主意。但我不明白为什么修改多个表是不好的。快速I
> require(data.table)
> x1 <- CJ(1:2, 2:3)
> x1
V1 V2
1: 1 2
2: 1 3
3: 2 2
4: 2 3
> proc1 <- function(x){
+ x[,y:= V1*V2]
+ NULL
+ }
> proc1(x1)
NULL
> x1
V1 V2 y
1: 1 2 2
2: 1 3 3
3: 2 2 4
4: 2 3 6
>
> x1 <- CJ(1:2000, 1:500)
> x1[, paste0("V",3:300) := rnorm(1:nrow(x1))]
> proc1 <- function(x){
+ x[,y:= V1*V2]
+ NULL
+ }
> system.time(proc1(x1))
user system elapsed
0.00 0.02 0.02
> x1 <- CJ(1:2000, 1:500)
> system.time(x1[,y:= V1*V2])
user system elapsed
0.03 0.00 0.03