Michael
Michael

Reputation: 7377

Replace row of NAs with previous row in R

I was wondering if anyone had a quick and dirty solution to the following problem, I have a matrix that has rows of NAs and I would like to replace the rows of NAs with the previous row (if it is not also a row of NAs).

Assume that the first row is not a row of NAs

Thanks!

Upvotes: 3

Views: 1518

Answers (6)

andrekos
andrekos

Reputation: 2882

Here is a straightforward and conceptually perhaps the simplest one-liner:

x <- data.frame(a=c(1, 2, NA, 3, NA, NA), b=c(4, 5, NA, 6, NA, 7))

   a  b
1  1  4
2  2  5
3 NA NA
4  3  6
5 NA NA
6 NA  7

x1<-t(sapply(1:nrow(x),function(y) ifelse(is.na(x[y,]),x[y-1,],x[y,])))

     [,1] [,2]
[1,] 1    4   
[2,] 2    5   
[3,] 2    5   
[4,] 3    6   
[5,] 3    6   
[6,] NA   7 

To put the column names back, just use colnames(x1)<-colnames(x)

Upvotes: 0

IRTFM
IRTFM

Reputation: 263332

Matthew's example:

x <- data.frame(a=c(1, 2, NA, 3, NA, NA), b=c(4, 5, NA, 6, NA, 7))
 na.rows <- which( apply( x , 1, function(z) (all(is.na(z)) ) ) )
 x[na.rows , ] <- x[na.rows-1, ]
 x
#---
   a b
1  1 4
2  2 5
3  2 5
4  3 6
5  3 6
6 NA 7

Obviously a first row with all NA's would present problems.

Upvotes: 0

Matthew Lundberg
Matthew Lundberg

Reputation: 42639

Adapted from an answer to this question: Idiomatic way to copy cell values "down" in an R vector

f <- function(x) {
  idx <- !apply(is.na(x), 1, all)
  x[idx,][cumsum(idx),]
}

x <- data.frame(a=c(1, 2, NA, 3, NA, NA), b=c(4, 5, NA, 6, NA, 7))

> x
   a  b
1  1  4
2  2  5
3 NA NA
4  3  6
5 NA NA
6 NA  7

> f(x)
     a b
1    1 4
2    2 5
2.1  2 5
4    3 6
4.1  3 6
6   NA 7

Upvotes: 4

Jim Crozier
Jim Crozier

Reputation: 1418

You can always use a loop, here assuming that 1 is not NA as indicated:

fill = data.frame(x=c(1,NA,3,4,5))
for (i in 2:length(fill)){
  if(is.na(fill[i,1])){ fill[i,1] = fill[(i-1),1]}
 }

Upvotes: 1

Tyler Rinker
Tyler Rinker

Reputation: 109864

Trying to think of times you may have two all NA rows in a row.

#create a data set like you discuss (in the future please do this yourself)
set.seed(14)
x <- matrix(rnorm(10), nrow=2)
y <- rep(NA, 5)
v <- do.call(rbind.data.frame, sample(list(x, x, y), 10, TRUE))

One approach:

NArows <- which(apply(v, 1, function(x) all(is.na(x))))          #find all NAs
notNA <- which(!seq_len(nrow(v)) %in% NArows)                    #find non NA rows
rep.row <- sapply(NArows, function(x) tail(notNA[x > notNA], 1)) #replacement rows
v[NArows, ] <- v[rep.row, ]                                      #assign
v                                                                #view              

This would not work if your first row is all NAs.

Upvotes: 1

Theodore Lytras
Theodore Lytras

Reputation: 3965

If m is your matrix, this is your quick and dirty solution:

sapply(2:nrow(m),function(i){ if(is.na(m[i,1])) {m[i,] <<- m[(i-1),] } })

Note it uses the ugly (and dangerous) <<- operator.

Upvotes: 0

Related Questions