In einem data.frame (oder einer data.table) möchte ich NAs mit dem nächsten vorherigen Nicht-NA-Wert "vorwärts füllen". Ein einfaches Beispiel für die Verwendung von Vektoren (anstelle von a data.frame
) ist das folgende:
> y <- c(NA, 2, 2, NA, NA, 3, NA, 4, NA, NA)
Ich möchte eine Funktion fill.NAs()
, mit der ich Folgendes konstruieren kann yy
:
> yy
[1] NA NA NA 2 2 2 2 3 3 3 4 4
Ich muss diesen Vorgang für viele (insgesamt ~ 1 TB) kleine data.frame
s (~ 30-50 Mb) wiederholen , bei denen eine Zeile NA ist und alle ihre Einträge sind. Was ist ein guter Weg, um das Problem anzugehen?
Die hässliche Lösung, die ich mir ausgedacht habe, verwendet diese Funktion:
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
}
Die Funktion fill.NAs
wird wie folgt verwendet:
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]
}
Ausgabe
> y
[1] NA 2 2 2 2 3 3 3 4 4 4
... was zu funktionieren scheint. Aber Mann, ist es hässlich? Irgendwelche Vorschläge?
fill
inR
tidyr::fill()
.
roll=TRUE
indata.table
.