在 R 中的循环之前初始化列表的最有效内存方法是什么?
What is the most memory efficient way to initialize a list before a loop in R?
我想知道如果要在循环中使用该列表来存储结果,那么在 R 中初始化列表的内存效率最高的方法是什么。我知道在循环中增长对象会严重影响计算效率,所以我尽量避免这种情况。
我的问题如下。我有几组数据要单独处理。我的代码的要点是我有一个循环,一次一个地运行每个组,进行一些 t 检验,然后 returns 仅统计显着的结果(因此每个组的可变长度结果)。到目前为止,我正在初始化一个 length(groups)
的列表来存储每次迭代的结果。
我的主要问题是我应该如何初始化列表,以便对象不会在循环中增长。
- 初始化
list = vector(mode = "list", length=length(groups))
是否足够好?
- 我对此持怀疑态度,因为它只是创建了一个
length(groups)
的列表,但每个条目都等于 NULL
。我担心的是,在循环的每次迭代中,当我将数据存储到列表中时,它会在每次条目从 NULL
到我的结果向量时重新复制对象,在这种情况下初始化列表并没有多大用处。但是,我不知道 list
的内部结构是如何工作的,所以它可能只存储对存储在列表中的向量的引用,这意味着不需要重新复制。
- 另一种选择是将列表的每个元素初始化为结果可能具有的最大可能长度的向量。
- 这不是什么大问题,因为可能的有效结果的最大数量是已知的。如果我采用这种方法,我将只用循环内的结果向量覆盖每个向量。由于已经保留了最大内存量,因此希望不会出现 recopying/growth。但是,如果没有必要并且上面的第一个选项足够好,我不想采用这种方法。
下面是一些描述我的问题的伪代码
#initialize variables
results = vector(mode="list", length=length(groups)) #the line of code in question
y=1
tTests = vector(length = length(singleGroup))
#perform analysis on each group in groups
for(group in groups)
{
#returns a vector of p values with one entry per element in group
tTests = tTestFunction(group)
results[[y]] = tTests<=0.05
y=y+1
}
您的代码不起作用,所以它是一个错误的例子。考虑一下:
x <- vector("list", length = 4)
tracemem(x) ## trace memory copies of "x"
for (i in 1:4) x[[i]] <- rnorm(4)
更新期间没有额外复制x
。所以没有什么可担心的。
按照@lmo的建议,即使你使用x <- list()
初始化这个列表,也不会产生内存复制。
评论
我回答的目的是让您参考 tracemem
的用法,当您想跟踪代码执行期间所做的(可能的)内存副本时。如果你知道这个功能,你就不会在这里问我们了。
是我的另一个答案,与使用 tracemem
有关。不过,这是在不同的背景下。在那里,您可以看到 tracemem
在进行内存复制时 return 会发生什么。
我想知道如果要在循环中使用该列表来存储结果,那么在 R 中初始化列表的内存效率最高的方法是什么。我知道在循环中增长对象会严重影响计算效率,所以我尽量避免这种情况。
我的问题如下。我有几组数据要单独处理。我的代码的要点是我有一个循环,一次一个地运行每个组,进行一些 t 检验,然后 returns 仅统计显着的结果(因此每个组的可变长度结果)。到目前为止,我正在初始化一个 length(groups)
的列表来存储每次迭代的结果。
我的主要问题是我应该如何初始化列表,以便对象不会在循环中增长。
- 初始化
list = vector(mode = "list", length=length(groups))
是否足够好?- 我对此持怀疑态度,因为它只是创建了一个
length(groups)
的列表,但每个条目都等于NULL
。我担心的是,在循环的每次迭代中,当我将数据存储到列表中时,它会在每次条目从NULL
到我的结果向量时重新复制对象,在这种情况下初始化列表并没有多大用处。但是,我不知道list
的内部结构是如何工作的,所以它可能只存储对存储在列表中的向量的引用,这意味着不需要重新复制。
- 我对此持怀疑态度,因为它只是创建了一个
- 另一种选择是将列表的每个元素初始化为结果可能具有的最大可能长度的向量。
- 这不是什么大问题,因为可能的有效结果的最大数量是已知的。如果我采用这种方法,我将只用循环内的结果向量覆盖每个向量。由于已经保留了最大内存量,因此希望不会出现 recopying/growth。但是,如果没有必要并且上面的第一个选项足够好,我不想采用这种方法。
下面是一些描述我的问题的伪代码
#initialize variables
results = vector(mode="list", length=length(groups)) #the line of code in question
y=1
tTests = vector(length = length(singleGroup))
#perform analysis on each group in groups
for(group in groups)
{
#returns a vector of p values with one entry per element in group
tTests = tTestFunction(group)
results[[y]] = tTests<=0.05
y=y+1
}
您的代码不起作用,所以它是一个错误的例子。考虑一下:
x <- vector("list", length = 4)
tracemem(x) ## trace memory copies of "x"
for (i in 1:4) x[[i]] <- rnorm(4)
更新期间没有额外复制x
。所以没有什么可担心的。
按照@lmo的建议,即使你使用x <- list()
初始化这个列表,也不会产生内存复制。
评论
我回答的目的是让您参考 tracemem
的用法,当您想跟踪代码执行期间所做的(可能的)内存副本时。如果你知道这个功能,你就不会在这里问我们了。
tracemem
有关。不过,这是在不同的背景下。在那里,您可以看到 tracemem
在进行内存复制时 return 会发生什么。