Ограничить na.locf в пакете зоопарка

Я хотел бы сделать последнее наблюдение, перенесенное для переменной, но не более двух наблюдений. То есть, для пробелов в данных 3 или более NA, я бы перенес только последнее наблюдение для следующих 2 наблюдений, а остальные оставил как NA.

Если я делаю это с zoo::na.locf, параметр maxgap означает, что если зазор больше 2, NA не заменяется. Даже не последние 2. Есть ли альтернатива?

x <- c(NA,3,4,5,6,NA,NA,NA,7,8)
zoo::na.locf(x, maxgap = 2) # Doesn't replace the first 2 NAs of after the 6 as the gap of NA is 3. 
Desired_output <- c(NA,3,4,5,6,6,6,NA,7,8)

person user3507584    schedule 13.09.2018    source источник


Ответы (2)


Решение с использованием базы R:

ave(x, cumsum(!is.na(x)), FUN = function(i){ i[1:pmin(length(i), 3)] <- i[1]; i })
# [1] NA  3  4  5  6  6  6 NA  7  8

cumsum(!is.na(x)) группирует каждый прогон NA с самым последним значением, отличным от NA.

function(i){ i[1:pmin(length(i), 3)] <- i[1]; i } преобразует первые два NA каждой группы в ведущее не NA значение этой группы.

person mt1022    schedule 13.09.2018
comment
Хороший. Небольшим упрощением можно было бы использовать это как УДОВОЛЬСТВИЕ: function(x) ifelse(seq_along(x) <= 2+1, x[1], NA) - person G. Grothendieck; 13.09.2018
comment
@ G.Grothendieck, хорошее предложение. Моя первоначальная функция довольно неуклюжая. - person mt1022; 13.09.2018
comment
Я считаю очень элегантным иметь одинарный вкладыш, хотя я не очень хорошо знаком с ave и pmin. Как вы могли сделать перенос назад? @ mt1022 @ Г.Гротендик - person user3507584; 13.09.2018
comment
@ user3507584, Возможный способ: 1) перевернуть вектор; 2) преобразовать обратный вектор с текущими ответами; 3) инвертировать преобразованные значения. - person mt1022; 14.09.2018
comment
@ mt1022 Спасибо за руководство, думаю, я понял [используя предложение @Grothendieck для функции]: rev(ave(rev(x), cumsum(!is.na(rev(x))), FUN = function(z) ifelse(seq_along(z) <= 3, z[1], NA))) - person user3507584; 14.09.2018

Сначала примените na.locf0 с maxgap = 2, чтобы получить x0, и определите переменную группировки g, используя rleid из пакета data.table. Для каждой такой группы используйте ave, чтобы применить keeper, который, если группа состоит из всех NA, заменяет ее на c (1, 1, NA, ..., NA), а в противном случае выводит все единицы. Умножьте на это na.locf0(x).

library(data.table)
library(zoo)

mg <- 2
x0 <- na.locf0(x, maxgap = mg)
g <- rleid(is.na(x0))
keeper <- function(x) if (all(is.na(x)))  ifelse(seq_along(x) <= mg, 1, NA) else 1
na.locf0(x) * ave(x0, g, FUN = keeper)
## [1] NA  3  4  5  6  6  6 NA  7  8
person G. Grothendieck    schedule 13.09.2018
comment
Спасибо! Можно ли узнать, что rleid, ave и keeper делают в этом случае? - person user3507584; 13.09.2018
comment
rleid создает вектор той же длины, что и его входные данные, так что он присваивает 1 первому прогону, 2 - второму прогону и так далее. keeper описано в ответе. ave разбивает первый аргумент на группы, определенные вторым аргументом, применяет указанную функцию к каждой группе, а затем помещает все вместе. Используйте help для получения дополнительной информации. - person G. Grothendieck; 13.09.2018