准确理解何时 data.table 是对另一个 data.table 的引用(而不是其副本)

2024-04-23

我在理解传递引用属性时遇到了一些困难data.table。有些操作似乎“破坏”了引用,我想确切地了解发生了什么。

关于创建一个data.table来自另一个data.table (via <-,然后通过更新新表:=,原来的表也被改变了。这是预期的,根据:

?data.table::copy and stackoverflow:通过引用传递数据表包中的运算符 https://stackoverflow.com/questions/8030452/pass-by-reference-the-operator-in-the-data-table-package

这是一个例子:

library(data.table)

DT <- data.table(a=c(1,2), b=c(11,12))
print(DT)
#      a  b
# [1,] 1 11
# [2,] 2 12

newDT <- DT        # reference, not copy
newDT[1, a := 100] # modify new DT

print(DT)          # DT is modified too.
#        a  b
# [1,] 100 11
# [2,]   2 12

但是,如果我插入一个非:=之间基于修改<-作业和:=上面的行,DT现在不再修改:

DT = data.table(a=c(1,2), b=c(11,12))
newDT <- DT        
newDT$b[2] <- 200  # new operation
newDT[1, a := 100]

print(DT)
#      a  b
# [1,] 1 11
# [2,] 2 12

所以看来newDT$b[2] <- 200线路以某种方式“破坏”了参考。我猜测这会以某种方式调用副本,但我想完全了解 R 如何处理这些操作,以确保我不会在代码中引入潜在的错误。

如果有人可以向我解释这一点,我将非常感激。


是的,这是 R 中的子分配,使用<- (or = or ->)复制一份whole目的。你可以使用追踪tracemem(DT) and .Internal(inspect(DT)), 如下。这data.table特征:= and set()通过引用分配给它们传递的任何对象。因此,如果该对象之前已被复制(通过子分配<-或明确的copy(DT)) 那么它就是通过引用修改的副本。

DT <- data.table(a = c(1, 2), b = c(11, 12)) 
newDT <- DT 

.Internal(inspect(DT))
# @0000000003B7E2A0 19 VECSXP g0c7 [OBJ,NAM(2),ATT] (len=2, tl=100)
#   @00000000040C2288 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 1,2
#   @00000000040C2250 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 11,12
# ATTRIB:  # ..snip..

.Internal(inspect(newDT))   # precisely the same object at this point
# @0000000003B7E2A0 19 VECSXP g0c7 [OBJ,NAM(2),ATT] (len=2, tl=100)
#   @00000000040C2288 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 1,2
#   @00000000040C2250 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 11,12
# ATTRIB:  # ..snip..

tracemem(newDT)
# [1] "<0x0000000003b7e2a0"

newDT$b[2] <- 200
# tracemem[0000000003B7E2A0 -> 00000000040ED948]: 
# tracemem[00000000040ED948 -> 00000000040ED830]: .Call copy $<-.data.table $<- 

.Internal(inspect(DT))
# @0000000003B7E2A0 19 VECSXP g0c7 [OBJ,NAM(2),TR,ATT] (len=2, tl=100)
#   @00000000040C2288 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 1,2
#   @00000000040C2250 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 11,12
# ATTRIB:  # ..snip..

.Internal(inspect(newDT))
# @0000000003D97A58 19 VECSXP g0c7 [OBJ,NAM(2),ATT] (len=2, tl=100)
#   @00000000040ED7F8 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 1,2
#   @00000000040ED8D8 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 11,200
# ATTRIB:  # ..snip..

请注意,即使a矢量已被复制(不同的十六进制值表示矢量的新副本),即使a没有改变。甚至整个b被复制,而不仅仅是更改需要更改的元素。对于大数据来说,避免这一点很重要,为什么:= and set()被介绍给data.table.

现在,用我们复制的newDT我们可以参考修改:

newDT
#      a   b
# [1,] 1  11
# [2,] 2 200

newDT[2, b := 400]
#      a   b        # See FAQ 2.21 for why this prints newDT
# [1,] 1  11
# [2,] 2 400

.Internal(inspect(newDT))
# @0000000003D97A58 19 VECSXP g0c7 [OBJ,NAM(2),ATT] (len=2, tl=100)
#   @00000000040ED7F8 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 1,2
#   @00000000040ED8D8 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 11,400
# ATTRIB:  # ..snip ..

请注意,所有 3 个十六进制值(列点向量和 2 列中的每一列)保持不变。所以它确实是通过参考修改的,根本没有任何副本。

或者,我们可以修改原来的DT引用 :

DT[2, b := 600]
#      a   b
# [1,] 1  11
# [2,] 2 600

.Internal(inspect(DT))
# @0000000003B7E2A0 19 VECSXP g0c7 [OBJ,NAM(2),ATT] (len=2, tl=100)
#   @00000000040C2288 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 1,2
#   @00000000040C2250 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 11,600
#   ATTRIB:  # ..snip..

这些十六进制值与我们看到的原始值相同DT多于。类型example(copy)有关更多示例,请使用tracemem和比较data.frame.

顺便说一句,如果你tracemem(DT) then DT[2,b:=600]您将看到报告的一份副本。这是前 10 行的副本print方法确实如此。当包裹着invisible()或者在函数或脚本中调用时,print方法未被调用。

所有这些也适用于函数内部; IE。,:= and set()即使在函数内,也不要在写入时复制。如果需要修改本地副本,请调用x=copy(x)在函数的开始处。但要记住data.table适用于大数据(以及小数据的更快编程优势)。我们故意不想复制大对象(永远)。因此,我们不需要考虑通常的 3* 工作记忆因子经验法则。我们尝试只需要一列那么大的工作记忆(即工作记忆系数为 1/ncol 而不是 3)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

准确理解何时 data.table 是对另一个 data.table 的引用(而不是其副本) 的相关文章

  • 在 R 中绘制非常大的数据集

    如何在 R 中绘制非常大的数据集 我想使用箱线图 小提琴图或类似的图 内存中无法容纳所有数据 我可以逐步读入并计算制作这些图所需的摘要吗 如果是这样怎么办 作为对我的评论的补充德米特里回答 https stackoverflow com q
  • data.frame 不会破坏列名

    有没有办法使用 data frame 而不破坏列名 我有以下结构 Canon PowerShot 1 9 997803e 01 9 997318e 01 3 327920e 01 3 327920e 01 9 988220e 01 6 4
  • 将 R 包函数导出到 R 包内的并行集群

    有一些功能 比如function1 在我正在开发的 R 包中 它依赖于辅助函数 例如h function1 and h function2 在我的包裹里 我正在并行化重复调用function1在我的包中的另一个函数中 目前 在我的包中我正在
  • 读取 CSV 文件单列的更快方法

    我正在尝试阅读一个列CSV文件至R尽快 我希望将标准方法将列放入 RAM 所需的时间减少 10 倍 我的动机是什么 我有两个文件 一个叫Main csv这是 300000 行和 500 列 其中一个称为Second csv即 300000
  • 如何识别 R 中行的镜像重复项

    在下面的SO帖子中如何识别 R 中行的部分重复项 https stackoverflow com questions 54661129 how to identify partial duplicates of rows in r 5466
  • 如何为每个分组元素选择随机的非连续日期?

    我目前正在尝试为每个分组列选择非连续日期 换句话说 我有以下数据框 我基本上想group by Site 然后为每个分组站点仅保留 3 个随机非连续日期 例如 如果 HP37P1B 的日期对应于 3 月 12 日 3 月 13 日 3 月
  • 在 R 闪亮应用程序中接受 HTTP 请求

    我制作了一个闪亮的应用程序 需要从另一台服务器获取其数据 即打开闪亮的应用程序时 另一台服务器向闪亮的应用程序发送请求以打开应用程序并向其提供所需的数据 为了模拟这一点 当我在 Firefox 中打开 R闪亮应用程序时 我可以将以下内容发送
  • R chron times() 函数不起作用

    我正在尝试将时间转换为自午夜以来的秒数 我很难从 chron 包中获取 times 函数来工作 我的使用方法如下 gt library chron gt 24 24 60 times 50 Error in 24 24 60 times 5
  • 多维数组到数据框

    R 中的以下问题对你们中的许多人来说可能看起来很简单 但由于我对此相对较新 如果您能帮助我 那将非常有帮助 我想本质上编写一个多维 3 个维度 数组作为我可以更轻松地操作的数据框 我正在处理 1891 年 1 月 1 日至 2015 年 1
  • R 对等证书无法使用给定的 CA 证书进行身份验证,Windows

    当尝试使用导入谷歌工作表时gs read 函数 我收到以下错误消息 在curl curl fetch memory url handle handle 中出错 对等 无法使用给定的 CA 证书对证书进行身份验证 我正在关注这个vignett
  • 数据表到 JSON [重复]

    这个问题在这里已经有答案了 我最近需要将数据表序列化为 JSON 我现在仍然使用 Net 2 0 因此我无法在 Net 3 5 中使用 JSON 序列化器 我想这肯定是以前做过的 所以我上网查了一下found http www codepr
  • 在 R 闪亮应用程序中评级星星

    我正在尝试向我闪亮的应用程序添加一些元素 以使其看起来更好 因此 我正在使用新的shiny semantic包允许以简单的方式添加语义 UI 元素 人们可以在这里找到闪亮的语义元素的示例 http demo appsilondatascie
  • ShinyApp:由对等方重置连接

    我之前构建的闪亮应用程序在我的旧笔记本电脑上运行良好 最近我买了一台装有Windows10的新笔记本电脑 设置完所有内容后 我尝试运行该应用程序 但浏览器立即打开并关闭 并出现错误 正在收听http 127 0 0 1 5004 http
  • 线性回归并将结果存储在数据框中[重复]

    这个问题在这里已经有答案了 我正在对数据框中的某些变量进行线性回归 我希望能够通过分类变量对线性回归进行子集化 对每个分类变量运行线性回归 然后将 t 统计数据存储在数据框中 如果可能的话 我想在没有循环的情况下执行此操作 这是我正在尝试做
  • ANEW 字典可以用于 Quanteda 中的情感分析吗?

    我正在尝试找到一种方法来实施英语单词情感规范 荷兰语 以便使用 Quanteda 进行纵向情感分析 我最终想要的是每年的 平均情绪 以显示任何纵向趋势 在数据集中 所有单词均由 64 名编码员按照 7 分李克特量表在四个类别上进行评分 这提
  • 向数据集中选定的一组列名称添加后缀

    我想向数据集 CTDB 中的一组列添加后缀 例如 我有以下列 我想在末尾添加 Child 该子集是包含 100 多列的较大数据集的一部分 我不想重写每个列名称 9 SCARED BREATHE 10 SCARED HEADACHE SCHO
  • 如果为 null 则替换为 0,否则在同一列中使用默认值

    在SparkR shell 1 5 0中 创建了一个示例数据集 df test lt createDataFrame sqlContext data frame mon c 1 2 3 4 5 year c 2011 2012 2013 2
  • 为什么链接生命周期仅与可变引用相关?

    前几天 有一个问题 https stackoverflow com questions 32089410 lifetimes and references to objects containing references有人对包含借用数据本
  • 如果满足条件,如何对连续行进行子集化

    我正在使用 R 来分析多个时间序列 1951 2013 其中包含每日最高和最低温度值 数据具有以下结构 YEAR MONTH DAY MAX MIN 1985 1 1 22 8 9 4 1985 1 2 28 6 11 7 1985 1 3
  • 当行数变化时如何绑定向量和矩阵

    在迭代算法中 我在每个步骤中确定要考虑的一行 几行或不考虑进一步计算 为了存储感兴趣的行 我必须绑定两个变量 X id 和 X val 我目前使用 cbind X id X val 当 X id 和 X val 都是矩阵时 它工作得很好 X

随机推荐