为什么中位数会使data.table出现问题(整数与双精度)?

37

我有一个名为enc.per.day的数据表,其中记录了每天的就诊情况。它有2403行,指定了服务日期和当天看诊患者人数。我想查看任何类型工作日看诊患者数量的中位数。

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

这行代码报错了

[.data.table(enc.per.day, , list(patient.encounters = median(n)), : 每组计算结果的列类型不一致:第四组的结果中,第1列类型为 'integer' 而期望类型为 'double'

以下所有代码都能正常运行

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)

返回 "整数"。此外,数据表中没有任何NA值。
1个回答

55

简述:将medianas.double()包裹。

data.table在处理median()时会出现问题,因为即使只传递整数向量,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 可以累积结果直到进行分组计算的结束,然后根据需要执行类型转换,但这将需要大量额外的性能降低开销;相反,它只报告发生了什么,并让您解决问题。在第一组运行之后,并且它知道结果的类型之后,它会分配一个结果向量,该向量的类型与分组数一样长,然后填充它。如果它后来发现某些组返回多个项,则会根据需要增加(即重新分配)该结果向量的大小。尽管如此,在大多数情况下,data.table 对于结果的最终大小的第一次猜测是正确的(例如,每组1行结果),因此速度很快。

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

(顺便说一句,您使用round()的版本之所以有效,是因为它始终返回“double”类型的值,如您可以通过键入typeof(round(median(1:2))); typeof(round(median(1:3)))看到。)


1
@Matthew Dowle -- 感谢您添加有关data.table如何初始化和分配结果向量空间的详细信息。 - Josh O'Brien
是否可能拥有与值相同类型的中位数?因此,即使我有像=1,1,1,2,2,2,2这样的值,它也不应该导致中位数为1.5,而应该显示中位数为2。 - lony
作为上面建议的一个例子,可以这样做: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")] - Bhoom Suktitipat
1
@JoshO'Brien 1. 我无法在 data.table v 1.10.4.3 中重现这个错误。在 [, (), by=] 之前,patients是整数,然后带有 typeof 的 double 类型。2. 通过取整数值的最大值,我创建了类似的错误,确保整数值的最大值是整数...我想发布一个问题,但不确定是否会被标记为重复。3. 结果 -Inf 是 R 中的double类型而不是整数值, 所以这里有一些微妙的地方,但我无法表达清楚。 - AdamO
正如相关问题所记录的那样,as.double(median(x)) 并不总是有效。我发现如果我将初始列类型指定为 double(即使它是一系列整数),那么它就可以工作了。 - user3386170
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接