24

R 具有按值传递的语义,可以最大限度地减少意外的副作用(一件好事)。但是,当代码被组织成许多函数/方法以实现可重用性/可读性/可维护性时,以及当代码需要通过例如大数据帧、通过一系列转换/操作来操作大型数据结构时,传递值语义会​​导致大量的数据复制和大量的堆颠簸(一件坏事)。例如,在作为函数参数传递的堆上占用 50Mb 的数据帧将至少复制与函数调用深度相同的次数,并且调用堆栈底部的堆大小将为 N* 50MB。如果函数从调用链的深处返回一个转换/修改的数据帧,那么复制会增加另一个 N。

SO问题避免传递数据框的最佳方法是什么?涉及这个主题,但措辞方式避免直接询问传递引用问题,而获胜的答案基本上是说:“是的,传递值是 R 的工作方式”。这实际上并不是 100% 准确的。R 环境支持按引用传递语义,而诸如proto之类的 OO 框架广泛使用此功能。例如,当一个 proto 对象作为函数参数传递时,它的“魔法包装器”是按值传递的,对于 R 开发人员来说,语义是按引用传递的。

似乎通过引用传递大数据框将是一个常见问题,我想知道其他人是如何处理它的,以及是否有任何库可以实现这一点。在我的搜索中,我没有发现一个。

如果没有可用的东西,我的方法是创建一个包装数据框的原型对象。我会很感激有关应该添加到该对象以使其有用的语法糖的指针,例如,重载 $ 和 [[ 运算符,以及我应该注意的任何陷阱。我不是 R 专家。

与 R 很好地集成的与类型无关的按引用传递解决方案的加分点,尽管我的需求完全是数据帧。

4

1 回答 1

31

问题的前提(部分)不正确。R 以传递承诺的方式工作,只有在传递承诺时对数据帧进行进一步分配和更改时,才会以您概述的方式重复复制。因此,副本的数量将不是 N*size,其中 N 是堆栈深度,而是其中 N 是进行分配的级别数。但是,您是对的,环境可能很有用。我看到你已经找到了'proto'包的链接。还有一个相对较新的“参考类”,有时称为“R5”,其中 R/S3 是在 R 中复制的 S3 的原始类系统,而 R4 将是最近的类系统,似乎主要支持BioConductor 软件包开发。

以下是 Steve Lianoglou 的一个示例链接(在讨论引用类优点的线程中),该示例将环境嵌入到 S4 对象中以避免复制成本:

https://stat.ethz.ch/pipermail/r-help/2011-September/289987.html

Matthew Dowle 的 'data.table' 包创建了一个新的数据对象类,其使用“[”的访问语义与常规 R data.frames 的访问语义不同,它实际上是作为传递引用工作的。它具有卓越的访问和处理速度。它也可以依靠数据框语义,因为在后来的几年中,这些对象现在继承了“data.frame”类。

您可能还想调查Hesterberg 的数据框包

于 2012-06-26T12:53:06.543 回答