Замена NA с последним значением не-NA - PullRequest
118 голосов
/ 12 октября 2011

В data.frame (или data.table) я бы хотел "заполнить" NA с ближайшим предыдущим значением, не являющимся NA.Простым примером использования векторов (вместо data.frame) является следующий:

> y <- c(NA, 2, 2, NA, NA, 3, NA, 4, NA, NA)

Я хотел бы функцию fill.NAs(), которая позволяет мне построить yy такой, что:

> yy
[1] NA NA NA  2  2  2  2  3  3  3  4  4

Мне нужно повторить эту операцию для многих (всего ~ 1 Тб) небольших data.frame с (~ 30-50 Мб), где строка является NA, все ее записи.Какой хороший способ подойти к проблеме?

Уродливый раствор, который я приготовил, использует эту функцию:

last <- function (x){
    x[length(x)]
}    

fill.NAs <- function(isNA){
if (isNA[1] == 1) {
    isNA[1:max({which(isNA==0)[1]-1},1)] <- 0 # first is NAs 
                                              # can't be forward filled
}
isNA.neg <- isNA.pos <- isNA.diff <- diff(isNA)
isNA.pos[isNA.diff < 0] <- 0
isNA.neg[isNA.diff > 0] <- 0
which.isNA.neg <- which(as.logical(isNA.neg))
if (length(which.isNA.neg)==0) return(NULL) # generates warnings later, but works
which.isNA.pos <- which(as.logical(isNA.pos))
which.isNA <- which(as.logical(isNA))
if (length(which.isNA.neg)==length(which.isNA.pos)){
    replacement <- rep(which.isNA.pos[2:length(which.isNA.neg)], 
                                which.isNA.neg[2:max(length(which.isNA.neg)-1,2)] - 
                                which.isNA.pos[1:max(length(which.isNA.neg)-1,1)])      
    replacement <- c(replacement, rep(last(which.isNA.pos), last(which.isNA) - last(which.isNA.pos)))
} else {
    replacement <- rep(which.isNA.pos[1:length(which.isNA.neg)], which.isNA.neg - which.isNA.pos[1:length(which.isNA.neg)])     
    replacement <- c(replacement, rep(last(which.isNA.pos), last(which.isNA) - last(which.isNA.pos)))
}
replacement
}

Функция fill.NAs используется следующим образом:

y <- c(NA, 2, 2, NA, NA, 3, NA, 4, NA, NA)
isNA <- as.numeric(is.na(y))
replacement <- fill.NAs(isNA)
if (length(replacement)){
which.isNA <- which(as.logical(isNA))
to.replace <- which.isNA[which(isNA==0)[1]:length(which.isNA)]
y[to.replace] <- y[replacement]
} 

Вывод

> y
[1] NA  2  2  2  2  3  3  3  4  4  4

... который, кажется, работает.Но это ужасно!Есть предложения?

Ответы [ 15 ]

2 голосов
/ 11 ноября 2016

Существует множество пакетов, предлагающих функции na.locf (NA Последнее наблюдение перенесено):

  • xts - xts::na.locf
  • zoo -zoo::na.locf
  • imputeTS - imputeTS::na.locf
  • spacetime - spacetime::na.locf

А также другие пакеты, в которых эта функция названа по-другому.

0 голосов
/ 24 апреля 2019
fill.NAs <- function(x) {is_na<-is.na(x); x[Reduce(function(i,j) if (is_na[j]) i else j, seq_len(length(x)), accumulate=T)]}

fill.NAs(c(NA, 2, 2, NA, NA, 3, NA, 4, NA, NA))

[1] NA  2  2  2  2  3  3  4  4  4

Reduce - это хорошая концепция функционального программирования, которая может быть полезна для подобных задач.К сожалению, в R это примерно в 70 раз медленнее, чем repeat.before в приведенном выше ответе.

0 голосов
/ 22 марта 2018

Вот модификация решения @ AdamO.Этот работает быстрее, потому что он обходит функцию na.omit.Это перезапишет NA значения в векторе y (кроме ведущих NA с).

   z  <- !is.na(y)                  # indicates the positions of y whose values we do not want to overwrite
   z  <- z | !cumsum(z)             # for leading NA's in y, z will be TRUE, otherwise it will be FALSE where y has a NA and TRUE where y does not have a NA
   y  <- y[z][cumsum(z)]
0 голосов
/ 13 января 2017

Это сработало для меня, хотя я не уверен, является ли оно более эффективным, чем другие предложения.

rollForward <- function(x){
  curr <- 0
  for (i in 1:length(x)){
    if (is.na(x[i])){
      x[i] <- curr
    }
    else{
      curr <- x[i]
    }
  }
  return(x)
}
0 голосов
/ 27 октября 2016

Я попробовал следующее:

nullIdx <- as.array(which(is.na(masterData$RequiredColumn)))
masterData$RequiredColumn[nullIdx] = masterData$RequiredColumn[nullIdx-1]

nullIdx получает номер idx, где когда-либо masterData $ RequiredColumn имеет значение Null / NA.В следующей строке мы заменим его соответствующим значением Idx-1, то есть последним хорошим значением перед каждым NULL / NA

...