spore234
spore234

Reputation: 3650

fill column with previous column if NA

I have a data frame like this

df <- data.frame(v1 = 10:14, v2 = c(NA, 1, NA, 3, 6), v3 = c(1, NA, NA, 9, 4))

  v1 v2 v3
1 10 NA  1
2 11  1 NA
3 12 NA NA
4 13  3  9
5 14  6  4

I now want to fill the NAs with the value of the previous column, so it looks like this:

  v1 v2 v3
1 10 10  1
2 11  1  1
3 12 12 12
4 13  3  9
5 14  6  4

I know how to do this manually, like this:

df$v2 <- ifelse(is.na(df$v2), df$v1, df$v2)

How can I automate this for a full data frame with many columns?

Upvotes: 8

Views: 1383

Answers (5)

acylam
acylam

Reputation: 18701

You can do this with fill from tidyr:

library(dplyr)
library(tidyr)

data.frame(t(df)) %>%
  fill(., names(.)) %>%
  t()

Result:

   v1 v2 v3
X1 10 10  1
X2 11  1  1
X3 12 12 12
X4 13  3  9
X5 14  6  4

Note:

Basically, I transposed df, filled every column downward, then transposed it back to the original orientation

Upvotes: 8

BENY
BENY

Reputation: 323396

By using zoo na.locf

data.frame(t(apply(df,1,function(x) na.locf(x))))
  v1 v2 v3
1 10 10  1
2 11  1  1
3 12 12 12
4 13  3  9
5 14  6  4

Upvotes: 3

d.b
d.b

Reputation: 32558

You could use apply but note that the output will be a matrix

t(apply(df, 1, function(x){
    replace(x, is.na(x), x[cumsum(!is.na(x))][is.na(x)])
}))
#     v1 v2 v3
#[1,] 10 10  1
#[2,] 11  1  1
#[3,] 12 12 12
#[4,] 13  3  9
#[5,] 14  6  4

Upvotes: 3

akuiper
akuiper

Reputation: 215137

Another option using Reduce with ifelse:

df[] <- Reduce(function(x, y) ifelse(is.na(y), x, y), df, accumulate = TRUE)

df
#  v1 v2 v3
#1 10 10  1
#2 11  1  1
#3 12 12 12
#4 13  3  9
#5 14  6  4

Upvotes: 5

Max Candocia
Max Candocia

Reputation: 4385

for (i in 2:ncol(df))
  df[,i] = ifelse(is.na(df[,i]), df[,i-1],df[,i])

This will propagate values across streaks of NA columns. If you don't want this, just reverse the order of the indexes in the for loop declaration.

Upvotes: 5

Related Questions