在R中无for循环的就地列表修改
我想知道是否有一种方法可以在不使用在R中无for循环的就地列表修改,r,R,我想知道是否有一种方法可以在不使用for循环的情况下就地修改列表中的对象。例如,如果列表中的单个对象较大且复杂,因此我们希望避免创建整个对象的临时副本,那么这将非常有用。作为一个例子,考虑下面的代码,该代码创建三个数据帧的列表,然后计算数据的一列的所有三个数据帧的最大值向量,然后将该向量分配给每个原始数据帧。(在ggplot2中对齐绘图时需要这样的代码。) data\u listBase R数据结构通过共享进行复制和修改。以具有三个数字列的data.frame为例。每个data.frame都是一
for
循环的情况下就地修改列表中的对象。例如,如果列表中的单个对象较大且复杂,因此我们希望避免创建整个对象的临时副本,那么这将非常有用。作为一个例子,考虑下面的代码,该代码创建三个数据帧的列表,然后计算数据的一列的所有三个数据帧的最大值向量,然后将该向量分配给每个原始数据帧。(在ggplot2中对齐绘图时需要这样的代码。)
data\u listBase R数据结构通过共享进行复制和修改。以具有三个数字列的data.frame为例。每个data.frame都是一个长度为3的“list”向量,每个都包含对基础列的数字向量的引用。如果修改/替换第一列,R将创建一个新的length 3 data.frame“list”,其中包含对新(ly-modified)列和其他两个未修改列的引用
让我们看看如何使用address
函数*
set.seed(1)
data_list <- lapply(1:3, function(x) data.frame(x=rnorm(10), y=rnorm(10), z=rnorm(10)))
before <- rapply(data_list,address)
这意味着您不必像想象的那样担心对大型数据结构进行更改。通常,只需替换数据结构的修改部分和骨架。在本例中,无论如何都必须创建max_x
向量,因此唯一的开销是创建一个新的3单元data.frame“list”,并用3个引用填充它**。但是,如果您迭代地“敲打”更改或使用子向量而不是整个列,那么这可能会变得效率低下。这些是不适用于本例的data.table
的用例
*此处使用的address
函数是从data.table
包导出的
**当然,在本例中,包含3个data.frames的3个单元格外部列表“list”本身。是什么让你认为整个对象都在复制?@MichaelChirico循环中的第一个赋值似乎是复制:库(data.table);对于(i in 1:length(data_list)){print(address(data_list));data_list[[i]]]$x@Claus-Wilke:for
循环使用有什么不对?R将只复制列表结构(3个单元格)这包括data.frame和修改后的列。未修改的列不需要复制--它们是共享的。也就是说,y
和z
列将不会被复制:library(data.table);for(i in 1:length(data_list)){print(address(data_list[i]$y));data_list[[i]$x不带for循环:sapply(1:3,函数(y){data_list[[y]]$x值得注意的是,x
列在被更改之前只有与max\ux
相同的地址。然后显然必须进行复制。直到它们再次被更改?示例是更改为max\ux
,因此无需复制,只需更改对max\ux
的引用。如果没有其他指向ol的话dx
列,然后它们将接受垃圾收集。我的意思是:x
set.seed(1)
data_list <- lapply(1:3, function(x) data.frame(x=rnorm(10), y=rnorm(10), z=rnorm(10)))
before <- rapply(data_list,address)
max_x <- do.call(pmax, lapply(data_list, function(d){d$x}))
data_list <- lapply(data_list,`[<-`,"x",value=max_x)
after <- rapply(data_list,address)
address(max_x)
[1] "05660600"
cbind(before,after)
before after
x "0565F530" "05660600"
y "0565F400" "0565F400"
z "05660AC0" "05660AC0"
x "05660A28" "05660600"
y "05660990" "05660990"
z "05660860" "05660860"
x "056607C8" "05660600"
y "05660730" "05660730"
z "05660698" "05660698"