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

SO问题What is the best way to avoid passing a data frame around?涉及到此主题,但其措词避免直接询问通过引用问题,而获胜的答案基本上是:“是的,通过值是R的工作方式”。这实际上不是100%准确的。 R环境支持按引用传递语义,并且诸如proto之类的OO框架广泛使用此功能。例如,当原型(prototype)对象作为函数参数传递时,而其“魔术包装”按值传递时,语义则是按引用传递给R开发人员的。

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

如果没有可用的东西,我的方法将是创建一个包装数据框的原型(prototype)对象。我很高兴看到有关应添加到此对象以使其有用的语法糖的指针,例如,重载$和[[运算符,以及我应注意的所有陷阱。我不是R专家。

类型无关的按引用解决方案的加分项,该解决方案与R可以很好地集成在一起,尽管我的需求完全是数据帧。

最佳答案

问题的前提是(部分)不正确。 R的作用是无条件传递,并且仅当随着 promise 的进行对数据帧进行进一步分配和更改时,才会按照您概述的方式重复复制。因此,副本数将不是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's dataframe package

关于performance - R:通过引用传递数据帧,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11207497/

10-12 17:23
查看更多