为啥中位数跳闸 data.table (整数与双精度)?

Posted

技术标签:

【中文标题】为啥中位数跳闸 data.table (整数与双精度)?【英文标题】:Why does median trip up data.table (integer versus double)?为什么中位数跳闸 data.table (整数与双精度)? 【发布时间】:2012-08-20 23:02:44 【问题描述】:

我有一个名为 enc.per.day 的 data.table 用于每天的遭遇。它有 2403 行,其中指定了服务日期和当天就诊的患者人数。我想查看在任何类型的工作日看到的患者的中位数。

enc.per.day[,list(patient.encounters=median(n)),by=list(weekdays(DOS))]

该行给出错误

[.data.table(enc.per.day, , list(patient.encounters = median(n)), 中的错误: j 的列不评估为每个组的一致类型:第 4 组的结果具有列 1 类型“整数”但期望类型“双”

以下都运行良好

tapply(enc.per.day$n,weekdays(enc.per.day$DOS),median)
enc.per.day[,list(patient.encounters=round(median(n))),by=list(weekdays(DOS))]
enc.per.day[,list(patient.encounters=median(n)+0),by=list(weekdays(DOS))]

发生了什么?我花了很长时间才弄明白为什么我的代码不起作用。

顺便说一下,底层向量 enc.per.day$n 是一个整数

storage.mode(enc.per.day$n)

返回“整数”。此外,data.table 中的任何地方都没有 NA。

【问题讨论】:

【参考方案1】:

TL;DR 用 median 包裹 as.double()

median() 'trips up' data.table 因为 --- 即使只传递整数向量 --- median() 有时会返回一个整数值,有时会返回一个双精度值。

## median of 1:3 is 2, of type "integer" 
typeof(median(1:3))
# [1] "integer"

## median of 1:2 is 1.5, of type "double"
typeof(median(1:2))
# [1] "double"

用一个最小的例子重现你的错误信息:

library(data.table)
dt <- data.table(patients = c(1:3, 1:2), 
                 weekdays = c("Mon", "Mon", "Mon", "Tue", "Tue"))

dt[,median(patients), by=weekdays]
# Error in `[.data.table`(dt, , median(patients), by = weekdays) : 
#   columns of j don't evaluate to consistent types for each group: 
#   result for group 2 has column 1 type 'double' but expecting type 'integer'

data.table 抱怨,因为在检查了要处理的第一个组的值之后,它得出的结论是,好的,这些结果将是“整数”类型。但是马上(或者在你的第 4 组中),它被传递了一个“double”类型的值,它不适合它的“整数”结果向量。


data.table 可以将结果累积到分组计算结束,然后在必要时执行类型转换,但这将需要大量额外的降低性能的开销;相反,它只是报告发生的事情并让您解决问题。在第一个组运行后,它知道结果的类型,它分配一个该类型的结果向量,只要组的数量,然后填充它。如果它稍后发现某些组返回超过 1 个项目,它将根据需要增长(即重新分配)该结果向量。但在大多数情况下,data.table 对结果最终大小的第一次猜测是第一次正确(例如,每组 1 行结果),因此速度很快。

在这种情况下,使用as.double(median(X)) 代替median(X) 提供了一个合适的解决方法。

(顺便说一句,您使用 round() 的版本可以正常工作,因为它始终返回“double”类型的值,您可以通过输入 typeof(round(median(1:2))); typeof(round(median(1:3))) 看到。)

【讨论】:

@Matthew Dowle -- 感谢您添加有关 data.table 如何为结果向量初始化和分配空间的详细信息。 是否可以有与值相同类型的中位数?因此,即使我有像 =1,1,1,2,2,2,2 这样的值,它也不应该导致中值 = 1.5,而是应该显示中值 = 2。 作为上述建议的示例,执行此操作 DT[ , c(as.double(lapply(.SD,median)) , .N),by=x, .SDcols=c(" x", "y", "z")] 而不是 DT[ , c(lapply(.SD,median) , .N),by=x, .SDcols=c("x", "y", "z ")] @JoshO'Brien 1. 我无法在 data.table v 1.10.4.3 中重现此错误。患者在[, (), by=] 之前是整数,然后是双精度的typeof。 2. 我通过取整数值的max 创建了类似的错误,肯定整数值的最大值是整数。我会发布一个问题,但不确定它是否会被标记为重复。 3. 原来-Inf是R中的double值而不是整数值,所以这里有一些微妙的地方,但我说不清楚。 @AdamO -- 在您的 (1) 上,我怀疑这与 data.table 现在将在内部优化对 median() 的调用有关,使用什么包作者致电_GForce_。 (有关详细信息,请参阅?datatable.optimize。)作为这项工作的一部分,他们一定已经处理了这里讨论的不合理之处。您的数字 (3) 是一个有趣的观察结果,我不知道 (2)。干杯。

以上是关于为啥中位数跳闸 data.table (整数与双精度)?的主要内容,如果未能解决你的问题,请参考以下文章

R data.table 控制打印位数

在 data.table 中按组划分的分位数

R data.table 滑动窗口

为啥 `data.table::unique` 不起作用?

求圆面积

单精度与双精度