我刚刚开始学习 r 中的 data.table 和
library(data.table)
data(iris)
iris[Species == 'setosa']
Run Code Online (Sandbox Code Playgroud)
上面的代码不会过滤数据集中物种为 setosa 的行,它只是打印满足条件的行。
iris <- iris[Species == 'setosa']
Run Code Online (Sandbox Code Playgroud)
上面的代码有效,但我想知道在什么样的情况下我需要为操作分配一个新对象才能有效,而不仅仅是打印结果。另外,在同一对象上分配是否有任何风险?
从根本上说,在 R 中通过引用修改列要容易得多,因为列是列表元素,并且列表元素不是连续存储在内存中。
通过引用删除列只是意味着取消分配其分配的内存并删除关联的指针
相比之下,删除一些行要困难得多,而且不能真正通过引用来完成——一些复制是不可避免的。考虑具有两列的表的这种简化表示,A并且B:
1 2 3 4 5
A: [ ][ ][ ][ ][ ]
B: [ ][ ][ ][ ][ ]
Run Code Online (Sandbox Code Playgroud)
A作为大小为 的数组存储在连续内存中5*sizeof(A)。例如,如果A是integer,则每个单元格给定 4 个字节。numeric每个单元格 8 个字节。
B从内存的角度来看,删除很容易:只需告诉 R/您的系统您不再需要该内存:
1 2 3 4 5
A: [ ][ ][ ][ ][ ]
B: [x][x][x][x][x]
Run Code Online (Sandbox Code Playgroud)
A的内存分配不受影响。
相比之下,请考虑从表中删除一些行(即同时删除A和B):
1 2 3 4 5
A: [ ][x][x][ ][ ]
B: [ ][x][x][ ][ ]
Run Code Online (Sandbox Code Playgroud)
如果我们简单地释放这 4 个单元格的内存,我们的表格就会被破坏——它的组成内存已经被分割,2*sizeof(A)第一行和第四行之间的-size 差距。
我们能做的最好的事情是尝试通过移动第 4 行和第 5 行来尽量减少复制,并保留第 1 行:
1 2 3<-4<-5
A: [ ][x][x][ ][ ]
B: [ ][x][x][ ][ ]
1 4 5
A: [ ][ ][ ]
B: [ ][ ][ ]
Run Code Online (Sandbox Code Playgroud)
在链接的答案中,马特提到了一个非常具体的情况,在这种情况下,按引用方法可以工作——当要添加/删除的行最后出现时。希望插图能清楚地说明为什么这样做更容易。
这个技术难点就是为什么链接的功能请求很难填写的原因。如图所示复制许多列的数据说起来容易做起来难,需要很多技巧才能使其正常工作并从 C 正确传达回 R。