【问题标题】:Missing values when using which.max in R data.table with NAs在带有 NA 的 R data.table 中使用 which.max 时缺少值
【发布时间】:2018-10-10 20:17:57
【问题描述】:

我在使用 R data.table 进行分组和 which.max 时遇到了问题,我不确定这是否是一个错误,或者我没有正确理解 data.table 中的分组结构.我有一个解决方法,我只是想了解为什么我最初的尝试失败了。

我正在查看一个包含时间序列的表,我想获取 (a) 感兴趣事件发生的时间,或 (b) 时间序列中的最终时间戳。如果事件未发生,则列标记 events 为“NA”,如果发生,则为“1”。

这是重现问题的最小示例:

dt <- data.table(t = seq(9), event = c(NA, NA, NA, NA, 1, NA, 1, NA, NA), t_id = c(rep('A', 3), rep('B', 3), rep('C', 3)))
dt[, ifelse(is.null(which.max(event)), max(t), t[which.max(event)]), by=t_id]

这会返回

t_id    V1
   A    NA
   B    5
   C    7

“A”组的值为 NA(我天真地期望它为 3)。如果我在没有 ifelse 函数的情况下运行它

dt[, t[which.max(event)], by=t_id]

“A”的行完全丢失(which.max 返回 NULL)。但是如果我运行

dt[, is.null(which.max(event)), by=t_id]

我明白了

t_id    V1
   A    FALSE
   B    FALSE
   C    FALSE

我错过了什么?

【问题讨论】:

  • 那么您究竟希望从is.null(which.max(event)) 得到什么?你见过which.max返回NULL吗?如果我是你,我会首先尝试从内到外调试。例如,值得检查您从is.null(which.max(NA)) 获得的信息。解决这个问题的一种方法是dt[, if(all(is.na(event))) max(t) else t[which.max(event)], by = t_id]
  • 它不是 NULL,但它不是我能识别的其他任何东西——类是“整数”,而且我看不到恢复值的方法,而且 is.nan(which.max( NA)) 和 is.na(which.max(NA)) 返回没有值的逻辑。
  • 您可以使用all(is.na(event))。并且,不惜一切代价,尽量避免ifelse 在不必要的时候(比如这种情况)
  • 一般情况下,当你想每组选择一行时,你可以排序然后使用unique,我猜在这种情况下......unique(dt[order(t_id, !is.na(event), t)], by="t_id", fromLast=TRUE)?顺便说一句,您应该只使用 TRUE/FALSE 记录事件发生,而不是非标准的 1/NA,因为大多数 R 语法都可以很好地使用前者。
  • @Frank,我实际上提供了比我仍在使用 ifelse 的解决方法更清洁的解决方案。我的应用程序有 NA 和 0 表示没有事件,这就是我使用 max 的原因。

标签: r data.table


【解决方案1】:

这行得通吗:

library(data.table)
dt <- data.table(t = seq(9), 
                 event = c(NA, NA, NA, NA, 1, NA, 1, NA, NA), 
                 t_id = c(rep('A', 3), rep('B', 3), rep('C', 3)))
dt[, ifelse(length((na.omit(event)))==0, which.max(t), t[which.max(event)] ), by=t_id]


> dt[, ifelse(length((na.omit(event)))==0, which.max(t), t[which.max(event)] ), by=t_id]
   t_id V1
1:    A  3
2:    B  5
3:    C  7

您的方法的问题是 which.max() 不返回 NULL 对象:

> is.null(which.max(c(NA,NA,NA)))
[1] FALSE

但如果你尝试length(),你会得到预期的结果:

> length(which.max(c(NA,NA,NA))) == 0
[1] TRUE

我还了解 event 列可能包含 1 和 NA 以外的值。喜欢:

dt <- data.table(t = seq(9), event = c(NA, NA, NA, NA, 1,3, 5, 2, NA, 2, 1, NA, NA), t_id = c(rep('A', 3), rep('B', 6), rep('C', 4)))
dt[, ifelse(length((na.omit(event)))==0, which.max(t), t[which.max(event)] ), by=t_id]

在这种情况下,数据表如下所示:

> dt
    t event t_id
 1: 1    NA    A
 2: 2    NA    A
 3: 3    NA    A
 4: 4    NA    B
 5: 5     1    B
 6: 6     3    B
 7: 7     5    B
 8: 8     2    B
 9: 9    NA    B
10: 1     2    C
11: 2     1    C
12: 3    NA    C
13: 4    NA    C

结果:

> dt[, ifelse(length((na.omit(event)))==0, which.max(t), t[which.max(event)] ), by=t_id]
   t_id V1
1:    A  3
2:    B  7
3:    C  1

如果事件列只能包含NAs1s,那么解决方案会简单得多。

另一个注意事项(请参阅下面的讨论):对于这种情况, ifelse(na.omit()) 可能不是最有效的 - 可以在 cmets 中找到一些建议。

【讨论】:

  • ifelsena.omit 都很慢,有意外行为,在这种情况下完全没有必要
  • 这个练习的重点是突出原始代码中的问题并解释为什么它不起作用。我不同意 ifelse() 很慢。如果使用得当,那就没问题了。这段代码能否进一步优化——当然!但问题是为什么原始代码不起作用,我试图解释为什么以及如何使它起作用。
  • 好吧,你可以不同意but it is a fact。此外,在标量上运行 ifelse 没有任何意义,它不是为它设计的。你可以只是我们if。此外,它不仅速度慢,而且还具有不可预测的行为(如果没有阅读文档中的所有细节)。你说的这个“练习”是什么?如果您想向 OP 解释不该做什么,那很好,但教他们其他不应该做的事情就没有那么多了。
  • @DavidArenburg 我同意 if() 将更清晰的函数应用于标量。至于 ifelse() 很慢,我很想看到在以下示例中使用它的更好方法而不会失去清晰度:x 0, T, F) .您在此处发布的链接探讨了 ifelse(is.na()) 组合的具体案例。
  • 只做x&gt;0?我提供的链接与 ifelse(is.na()) 的具体案例完全无关
猜你喜欢
  • 1970-01-01
  • 2021-03-13
  • 2017-11-20
  • 2017-09-02
  • 1970-01-01
  • 1970-01-01
  • 2012-09-20
  • 2015-05-06
  • 1970-01-01
相关资源
最近更新 更多