3

通过常规方式(例如ll["name"] <- NULL)从列表中删除元素会导致整个列表被复制。通常,这并不明显,直到数据集变得很大。

我有一个包含十几个元素的列表,每个元素的大小在 0.25 ~ 2 GB 之间。从这个列表中删除三个元素大约需要十分钟才能执行(在相对较快的机器上)。

有没有办法就地从列表中删除元素?


我尝试了以下方法:

TEST <- list(A=1:20,  B=1:5)

TEST[["B"]] <- NULL
TEST["B"] <- NULL
TEST <- TEST[c(TRUE, FALSE)]
data.table::set(TEST, "B", value=NULL) # ERROR

输出内存信息:

cat("\n\n\nATTEMPT 1\n")
TEST <- list(A=1:20,  B=1:5)
.Internal(inspect(TEST))
TEST[["B"]] <- NULL
.Internal(inspect(TEST))

cat("\n\n\nATTEMPT 2\n")
TEST <- list(A=1:20,  B=1:5)
.Internal(inspect(TEST))
TEST["B"] <- NULL
.Internal(inspect(TEST))

cat("\n\n\nATTEMPT 3\n")
TEST <- list(A=1:20,  B=1:5)
.Internal(inspect(TEST))
TEST <- TEST[c(TRUE, FALSE)]
4

2 回答 2

2

我不知道如何在不复制矢量的情况下缩短矢量。下一个最好的事情是将元素设置为缺少NANULL

根据?Extract,您必须指定TEST[i] <- list(NULL)将元素设置为NULL。我的测试表明它i必须是一个整数或逻辑向量。

> TEST <- list(A=1:20,  B=1:5); .Internal(inspect(TEST))
@27d2c60 19 VECSXP g0c2 [NAM(1),ATT] (len=2, tl=0)
  @27dd9e0 13 INTSXP g0c6 [] (len=20, tl=0) 1,2,3,4,5,...
  @2805c98 13 INTSXP g0c3 [] (len=5, tl=0) 1,2,3,4,5
ATTRIB:
  @1f38be8 02 LISTSXP g0c0 [] 
    TAG: @d3f478 01 SYMSXP g1c0 [MARK,LCK,gp=0x4000] "names" (has value)
    @2807430 16 STRSXP g0c2 [] (len=2, tl=0)
      @dc2628 09 CHARSXP g1c1 [MARK,gp=0x61] [ASCII] [cached] "A"
      @dc25f8 09 CHARSXP g1c1 [MARK,gp=0x61] [ASCII] [cached] "B"
> TEST[2] <- list(NULL); .Internal(inspect(TEST)); TEST
@27d2c60 19 VECSXP g0c2 [MARK,NAM(1),ATT] (len=2, tl=0)
  @27dd9e0 13 INTSXP g0c6 [MARK] (len=20, tl=0) 1,2,3,4,5,...
  @d3fb78 00 NILSXP g1c0 [MARK,NAM(2)] 
ATTRIB:
  @1f38be8 02 LISTSXP g0c0 [MARK] 
    TAG: @d3f478 01 SYMSXP g1c0 [MARK,LCK,gp=0x4000] "names" (has value)
    @2807430 16 STRSXP g0c2 [MARK] (len=2, tl=0)
      @dc2628 09 CHARSXP g1c1 [MARK,gp=0x61] [ASCII] [cached] "A"
      @dc25f8 09 CHARSXP g1c1 [MARK,gp=0x61] [ASCII] [cached] "B"
$A
 [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20

$B
NULL
于 2013-10-22T22:03:16.613 回答
1

正如@JoshO'Brien 在他的评论中所建议的那样,使用它environments而不是lists在内存中存储大对象更有效。以我的经验,Environments赋予显着的时间和内存优势(对于大型对象存储):

元素查找时间。

您是否注意到访问列表末尾的对象可能很慢(几秒钟)?那是因为lists不知道每个元素在内存中的位置,他们必须通过搜索list(我认为)找到每个元素。

另一方面,访问环境中的变量是即时的(它只需要搜索存储在环境中的变量名称列表)。当您的列表元素很大时,这很明显!

就地改造。

在环境中修改(或删除)变量时,仅复制单个对象。当您修改列表时,整个列表将在此过程中复制。

使用环境

  1. 定义新环境: TEST <- new.env()
  2. 投射到环境: TEST <- as.environment(TEST)
  3. 元素删除: rm(A, envir=TEST)
  4. 元素创建: TEST$A <- 1:20
  5. 元素访问: TEST$A
  6. 列出存储的对象:( ls(pos=TEST)这相当于names(TEST)
于 2013-10-23T00:13:34.777 回答