habana
habana

Reputation: 317

How do I replace NA's in dataframe rows where rows is not all NA's

I have dataframe that looks like this:

df <- data.frame(matrix(c(1,351,NA,1,0,2,585,0,1,1,3,321,NA,0,1,4,964,NA,NA,NA,5,556,0,1,NA), ncol = 5, byrow = TRUE))
colnames(df) <- c('id','value','v1','v2','v3')

Now I want to replace all NA's in the subset c('v1', 'v2', 'v3') with 0 (zero) for all rows that are not all NA's.

So I want this:

R> df
  id value v1 v2 v3
1  1   351 NA  1  0
2  2   585  0  1  1
3  3   321 NA  0  1
4  4   964 NA NA NA
5  5   556  0  1 NA

to end up like this:

R> df
  id value v1 v2 v3
1  1   351  0  1  0
2  2   585  0  1  1
3  3   321  0  0  1
4  4   964 NA NA NA
5  5   556  0  1  0

Note that df[4, ] still have NA's for c('v1', 'v2', 'v3').

Upvotes: 4

Views: 69

Answers (5)

Shinobi_Atobe
Shinobi_Atobe

Reputation: 1983

A simple dplyr solution:

library(tidyverse)

df %>% 
  mutate_at(vars(v1:v3), ~ifelse(is.na(v1) & is.na(v2) & is.na(v3), NA, replace_na(., 0)))

Upvotes: 1

tmfmnk
tmfmnk

Reputation: 40171

With dplyr, you can try:

cols <- c("v1", "v2", "v3")

df %>%
 mutate(row_na = rowSums(is.na(select(., one_of(cols)))) == length(cols)) %>%
 mutate_at(vars(one_of(cols)), ~ ifelse(!row_na, replace(., is.na(.), 0), .)) %>%
 select(-row_na)

  id value v1 v2 v3
1  1   351  0  1  0
2  2   585  0  1  1
3  3   321  0  0  1
4  4   964 NA NA NA
5  5   556  0  1  0

Upvotes: 1

indubitably
indubitably

Reputation: 297

As simple as possible:

df[ !(is.na(df$v1) & is.na(df$v2) & is.na(df$v3)) & is.na(df) ] <- 0

Upvotes: 0

Ronak Shah
Ronak Shah

Reputation: 389325

In base R , here is one way

#columns to check for NA
cols <- c("v1", "v2", "v3")
#rows which needs to be replaced
rows <- which(rowSums(is.na(df[cols])) != length(cols))
#Replace values which are NA to 0
df[rows, cols] <- replace(df[rows, cols], is.na(df[rows, cols]), 0)
df
#  id value v1 v2 v3
#1  1   351  0  1  0
#2  2   585  0  1  1
#3  3   321  0  0  1
#4  4   964 NA NA NA
#5  5   556  0  1  0

Upvotes: 2

Chelmy88
Chelmy88

Reputation: 1116

Here is a solution with good old loop:

for (r in 1:nrow(df))
{
  # check that not the all row is na but that there are some na
  if(!all(is.na(df[r,3:5])) && sum(is.na(df[r,3:5]>0)))
  {
    df[r,which(is.na(df[r,3:5]))+2]=0
  }  
}

Upvotes: 2

Related Questions