【问题标题】:split data.table拆分数据表
【发布时间】:2013-02-05 08:16:33
【问题描述】:

我有一个 data.table,我想将它一分为二。我这样做如下:

dt <- data.table(a=c(1,2,3,3),b=c(1,1,2,2))
sdt <- split(dt,dt$b==2)

但如果我想像这样作为下一步

sdt[[1]][,c:=.N,by=a]

我收到以下警告消息。

警告消息:在 [.data.table(sdt[[1]], , :=(c, .N), by = a) 中: 检测到无效的 .internal.selfref 并通过复制 整个表,以便 := 可以通过引用添加此新列。晒黑 早些时候,这个data.table已经被R复制了。避免key

只是想知道是否有更好的方法来拆分表格以提高效率(并且不会收到此消息)?

【问题讨论】:

  • 一开始为什么要拆分data.table?拆分我们创建一个列表,因此警告处​​理复制发生的原因
  • 我正在根据时间划分为我的实验创建两组。
  • 我很好奇.N 在这种情况下是什么意思?
  • @SimonO101 .N 只是组的行数。
  • 在 1.9.7 中,data.table 有自己的split 方法,您的代码可以在上面正常运行。

标签: r data.table


【解决方案1】:

这适用于 v1.8.7(也可能适用于 v1.8.6):

> sdt = lapply(split(1:nrow(dt), dt$b==2), function(x)dt[x])
> sdt
$`FALSE`
   a b
1: 1 1
2: 2 1

$`TRUE`
   a b
1: 3 2
2: 3 2

> sdt[[1]][,c:=.N,by=a]     # now no warning
> sdt
$`FALSE`
   a b c
1: 1 1 1
2: 2 1 1

$`TRUE`
   a b
1: 3 2
2: 3 2

但是,正如@mnel 所说,这是低效的。请尽可能避免拆分。

【讨论】:

  • 我不太明白为什么它说invalid .internal.selfref 就像我写attributes(sdt[[1]])$.internal.selfref 时一样,该值似乎与dt 的值相同(dt2 &lt;- copy(dt) 上的值相同) ..有什么想法吗?
  • @Arun 没错,这就是它无效的原因。它应该在有效时指向自身。如果您查看.Internal(inspect(sdt[[1]])),您应该会看到它的指针地址不同(已复制)。这就是.internal.selfref 旨在检测的内容。复制的问题不在于复制本身,而是当 R 进行复制时,它不会维护列指针的过度分配向量。因此,当:= 尝试添加新列(它必须再次过度分配)时会发出警告,以防您有两个绑定到同一个对象。一切正确且有意。
  • @Arun 所以警告试图说:不要base::split 找到其他方式,比如我的回答,来进行拆分。
  • @Arun 还有data.table:::selfrefok(sdt[[1]]) 检查.internal.selfref 是否有效。返回 0/1。故意不导出,因为它只是用于调试/检查。
【解决方案2】:

我正在寻找某种方法来拆分 data.table,但遇到了这个老问题。

有时你想要做的是拆分,而 data.table "by" 方法并不方便。

实际上,您可以使用仅 data.table 指令轻松地手动拆分,并且它的工作效率非常高:

SplitDataTable <- function(dt,attr) {
  boundaries=c(0,which(head(dt[[attr]],-1)!=tail(dt[[attr]],-1)),nrow(dt))
  return(
    mapply(
      function(start,end) {dt[start:end,]},
      head(boundaries,-1)+1,
      tail(boundaries,-1),
      SIMPLIFY=F))
}

【讨论】:

  • 好主意,但这比在我的数据上使用 split() 慢(nrow=25000,很多组)
【解决方案3】:

如上所述(@jangorecki),包data.table 已经有自己的拆分功能。在这种简化的情况下,我们可以使用:

> dt <- data.table(a = c(1, 2, 3, 3), b = c(1, 1, 2, 2))
> split(dt, by = "b")
$`1`
   a b
1: 1 1
2: 2 1

$`2`
   a b
1: 3 2
2: 3 2

对于更困难/具体的情况,我建议使用 by reference 函数 :=set 在 data.table 中创建一个新变量,然后调用函数 split .如果您关心性能,请确保始终保留在 data.table 环境中,例如 dt[, SplitCriteria := (...)],而不是在外部计算拆分变量。

【讨论】:

    猜你喜欢
    • 2013-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-24
    • 1970-01-01
    相关资源
    最近更新 更多