Если кто-то хочет заполнить отсутствующие значения переменной на основе предыдущего / апостериорного наблюдения, отличного от NA, в группе, команда data.table будет
setkey(DT,id,date)
DT[, value_filled_in := DT[!is.na(value), list(id, date, value)][DT[, list(id, date)], value, roll = TRUE]]
Что довольно сложно. Жаль, поскольку roll
- очень быстрый и мощный вариант (особенно по сравнению с применением такой функции, как zoo::na.locf
в каждой группе)
Я могу написать удобную функцию для заполнения недостающих значений
fill_na <- function(x , by = NULL, roll =TRUE , rollends= if (roll=="nearest") c(TRUE,TRUE)
else if (roll>=0) c(FALSE,TRUE)
else c(TRUE,FALSE)){
id <- seq_along(x)
if (is.null(by)){
DT <- data.table("x" = x, "id" = id, key = "id")
return(DT[!is.na(x)][DT[, list(id)], x, roll = roll, rollends = rollends, allow.cartesian = TRUE])
} else{
DT <- data.table("x" = x, "by" = by, "id" = id, key = c("by", "id"))
return(DT[!is.na(x)][DT[, list(by, id)], x, roll = roll, rollends = rollends, allow.cartesian = TRUE])
}
}
А затем напишите
setkey(DT,id, date)
DT[, value_filled_in := fill_na(value, by = id)]
Это не совсем удовлетворительно, так как хотелось бы написать
setkey(DT,id, date)
DT[, value_filled_in := fill_na(value), by = id]
Однако на это уходит очень много времени. И для конечного пользователя сложно узнать, что fill_na
следует вызывать с параметром by
, а не использовать с data.table
by
. Есть ли здесь элегантное решение?
Некоторый тест скорости
N <- 2e6
set.seed(1)
DT <- data.table(
date = sample(10, N, TRUE),
id = sample(1e5, N, TRUE),
value = sample(c(NA,1:5), N, TRUE),
value2 = sample(c(NA,1:5), N, TRUE)
)
setkey(DT,id,date)
DT<- unique(DT)
system.time(DT[, filled0 := DT[!is.na(value), list(id, date, value)][DT[, list(id, date)], value, roll = TRUE]])
#> user system elapsed
#> 0.086 0.006 0.105
system.time(DT[, filled1 := zoo::na.locf.default(value, na.rm = FALSE), by = id])
#> user system elapsed
#> 5.235 0.016 5.274
# (lower speed and no built in option like roll=integer or roll=nearest, rollend, etc)
system.time(DT[, filled2 := fill_na(value, by = id)])
#> user system elapsed
#> 0.194 0.019 0.221
system.time(DT[, filled3 := fill_na(value), by = id])
#> user system elapsed
#> 237.256 0.913 238.405
Почему бы мне просто не использовать na.locf.default
? Несмотря на то, что разница в скорости на самом деле не важна, та же проблема возникает для других типов команд data.table (тех, которые полагаются на слияние по переменной в "by") - стыдно систематически игнорировать их, чтобы получить более простой синтаксис. Еще мне очень нравятся все варианты рулонов.
2 ответа
Теперь существует собственный data.table
способ заполнения пропущенных значений (начиная с 1.12.4
).
Этот вопрос породил проблему на github, которая недавно была закрыта созданием функций nafill
и setnafill
. Теперь вы можете использовать
DT[, value_filled_in := nafill(value, type = "locf")]
Также возможно заполнить NA
постоянным значением или следующим переносом наблюдения.
Одно отличие от подхода в вопросе заключается в том, что эти функции в настоящее время работают только с NA
, а не с NaN
, тогда как is.na
является TRUE
для NaN
- это планируется исправить в следующем выпуске с помощью дополнительного аргумента.
Я не участвую в проекте, но я видел, что, хотя здесь есть ссылка на проблему с github, другой ссылки не было, поэтому я отвечаю от имени будущих посетителей.
Обновление: по умолчанию NaN
теперь обрабатывается так же, как NA
.
Вот несколько более быстрый и компактный способ сделать это (версия 1.9.3+):
DT[, filled4 := DT[!is.na(value)][DT, value, roll = T]]
DT[!is.na(value)]
, другой через X[Y]
), что было бы проблематично для типичного широкого набора данных. Не так ли (по крайней мере, для DT[!is.na(value)]
)?
(DT[, filled4 := DT[!is.na(value), list(date,id,value)][DT, value, roll = T]]
быстрее, чем ваш ответ в широкой базе данных
data.table 1.12.3
и образцами данных OP, возникают ошибки (Error in vecseq(f__, len__, if (allow.cartesian || notjoin || !anyDuplicated(f__, :
). Ты знаешь почему? Ваше здоровье
Похожие вопросы
Связанные вопросы
Новые вопросы
r
R — это бесплатный язык программирования с открытым исходным кодом и программная среда для статистических вычислений, биоинформатики, визуализации и общих вычислений. Пожалуйста, используйте минимально воспроизводимые примеры, которые другие могут запустить с помощью копирования и вставки. Показать желаемый результат. Используйте dput() для данных и укажите все небазовые пакеты с помощью library(). Не вставляйте изображения для данных или кода, вместо этого используйте блоки кода с отступом. Для вопросов по статистике используйте https://stats.stackexchange.com.
na.locf
сравнивается с этим решением с точки зрения скорости?dplyr::mutate
) не вариант?::
в зоопарке, для меня это будет примерно на 30% быстрее. то есть вызовитеna.locf.default
вместоzoo::na.locf.default
::
— это функция, и с этим дополнительным вызовом функции связаны накладные расходы.