【问题标题】:data.table "list" versus ":=" in dealing with NaNdata.table "list" 与 ":=" 处理 NaN
【发布时间】:2015-12-04 05:57:31
【问题描述】:

注意到 data.table 的一些奇怪行为,希望有人比我能解释的更了解 data.table。

假设我有这个data.table:

library(data.table)
DT <- data.table(
  C1 = c(rep("A", 4), rep("B",4), rep("C", 4)),
  C2 = c(rep("a", 3), rep("b",3), rep("c",3), rep("d",3)),
  Val = c(1:5, NaN, NaN, 8,9,10,NaN,12))

DT
    C1 C2 Val
 1:  A  a   1
 2:  A  a   2
 3:  A  a   3
 4:  A  b   4
 5:  B  b   5
 6:  B  b NaN
 7:  B  c NaN
 8:  B  c   8
 9:  C  c   9
10:  C  d  10
11:  C  d NaN
12:  C  d  12

现在,在我看来,以下两种方法应该会产生相同的结果,但它们不会。

TEST1 <- DT[, agg := min(Val, na.rm = TRUE), by = c('C1', 'C2')]
TEST1 <- data.table(unique(TEST1[, c('C1','C2','agg'), with = FALSE]))

TEST2 <- DT[, list(agg = min(Val, na.rm = TRUE)), by = c('C1', 'C2')]

TEST1
   C1 C2 agg
1:  A  a   1
2:  A  b   4
3:  B  b   5
4:  B  c   8
5:  C  c   9
6:  C  d  10


TEST2
   C1 C2 agg
1:  A  a   1
2:  A  b   4
3:  B  b   5
4:  B  c NaN
5:  C  c   9
6:  C  d  10

如您所见,使用“:=”为 (C1 = B, C2 = c) 生成 8 的最小值。而 list 命令生成 NaN。 有趣的是,对于也有 NaN 的 (C1 = B,C2 = b) 和 (C1 = C, C2 = d),list 命令确实会产生一个值。 我相信这是因为在 NaN 首先在给定 C1 C2 组合的值之前的情况下,NaN 结果。而在其他两个示例中,NaN 位于值之后。

为什么会这样?

我注意到,如果将 NaN 替换为 NA,则生成的值没有问题。

【问题讨论】:

  • 不知道,但DT[, list(agg = min(.SD$Val, na.rm = TRUE)), by = c('C1', 'C2')] 也可以使用
  • 或者DT[, list(agg=min(c(Val), na.rm=TRUE)), by = .(C1, C2)]有点奇怪,但是dplyr中的等效步骤在转换为data.frame之后可以工作。
  • 你绝对应该报告一个错误。我怀疑这是由于 data.table min 函数的“内部”实现。在data.table 操作中,一些函数(如minmaxsum)被更快的data.table 版本替换。如果您显式调用base 函数,您会得到正确的输出:DT[, list(agg = base::min(Val, na.rm = TRUE)), by = c('C1', 'C2')]。不知道为什么data.table:= 结合使用时似乎恢复为base::min
  • 是的,这是data.table的min优化版本的一个bug,应该报告。要关闭该行为,请使用options(datatable.optimize=1)。修复后,我确信其中一位 data.table 的作者会在这里发布答案,就像他们上次一样 stackoverflow.com/q/27987424/1191259
  • 尼古拉在现场。请提交为错误。 @nicola,你最后一句话是什么意思?

标签: r data.table


【解决方案1】:

修复了这个问题,#1461 刚刚在开发中,v1.9.7 和commit 2080

require(data.table) # v1.9.7, commit 2080+
DT <- data.table(
     C1 = c(rep("A", 4), rep("B",4), rep("C", 4)),
     C2 = c(rep("a", 3), rep("b",3), rep("c",3), rep("d",3)),
     Val = c(1:5, NaN, NaN, 8,9,10,NaN,12))

DT[, list(agg = min(Val, na.rm = TRUE)), by = c('C1', 'C2')]
#    C1 C2 agg
# 1:  A  a   1
# 2:  A  b   4
# 3:  B  b   5
# 4:  B  c   8
# 5:  C  c   9
# 6:  C  d  10

【讨论】:

    猜你喜欢
    • 2014-01-04
    • 2023-01-26
    • 1970-01-01
    • 2018-09-02
    • 2017-05-27
    • 2019-08-15
    • 1970-01-01
    • 2018-01-25
    • 1970-01-01
    相关资源
    最近更新 更多