Ответ 1
TL; DR wrap median
с as.double()
median()
'trip up' data.table, потому что --- даже когда только переданные целочисленные векторы --- median()
иногда возвращает целочисленное значение и иногда возвращает double.
## 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 жалуется, потому что после проверки значения первой группы, подлежащей обработке, он пришел к выводу, что, OK, эти результаты будут иметь тип "целое число". Но сразу же (или в вашем случае в группе 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)))
.)