12

我在列表中有一堆 data.tables。我想应用unique()到列表中的每个 data.table,但这样做会破坏我所有的 data.table 键。

这是一个例子:

A <- data.table(a = rep(c("a","b"), each = 3), b = runif(6), key = "a")
B <- data.table(x = runif(6), b = runif(6), key = "x")

blah <- unique(A)

在这里,blah还有一把钥匙,世间一切都对了:

key(blah)

# [1] "a"

但是,如果我将 data.tables 添加到 list 并使用lapply(),则键会被破坏:

dt.list <- list(A, B)

unique.list <- lapply(dt.list, unique) # Keys destroyed here

lapply(unique.list, key) 

# [[1]]
# NULL

# [[2]]
# NULL

这可能与我没有真正理解“通过引用”分配键的含义有关,因为我遇到了键消失的其他问题。

所以:

  • 为什么 lapply 不保留我的密钥?
  • 说“通过引用”分配键是什么意思?
  • 我什至应该将 data.tables 存储在列表中吗?
  • 如何安全地存储/操作 data.tables 而不必担心丢失我的密钥?

编辑:

对于它的价值,可怕的for循环也可以正常工作:

unique.list <- list()

for (i in 1:length(dt.list)) {
  unique.list[[i]] <- unique(dt.list[[i]])
}

lapply(unique.list, key)

# [[1]]
# [1] "a"

# [[2]]
# [1] "x"

但这是 R,for循环是邪恶的。

4

2 回答 2

9

有趣的是,请注意这两个不同结果之间的差异

lapply(dt.list, unique) 
lapply(dt.list, function(x) unique(x)) 

如果你使用后者,结果如你所料。


看似意外的行为是由于第一个lapply语句正在调用unique.data.frame(即 from {base})而第二个语句正在调用unique.data.table

于 2013-02-18T02:00:16.057 回答
6

好问题。事实证明,它记录在?lapply(见注释部分):

由于历史原因,由 lapply 创建的调用未被评估,并且已经编写了依赖于此的代码(例如 bquote)。这意味着录制的呼叫始终采用 FUN(X[[0L]], ...) 的形式,其中 0L 替换为当前整数索引。这通常不是问题,但如果 FUN 使用 sys.call 或 match.call 或者它是使用调用的原始函数,则可能会出现问题。这意味着使用包装器调用原始函数通常更安全,因此在 R 2.7.1 中需要例如 lapply(ll, function(x) is.numeric(x)) 以确保 is.numeric 的方法调度发生正确。

于 2013-02-18T09:21:58.157 回答