Removing cells from rows with NA

Viewed 86

I have the following data ( with variable number of columns)

> df1<-data.frame(F1=c(1,5,"NA",9),F2=c(2,5,"a","NA"),F3=c(1,"NA","o","NA"))
> df1
  F1 F2 F3
1  1 2  1
2  5  5 NA
3 NA  a  o
4  9 NA NA

and I want to remove the NA cells from the rows and shrink the columns only to the cells with information in it.

> df2
  F1  F2  F3
1  1  2   1
2  5  5 
3  a  o
4  9 

Thanks!

4 Answers

Firstly, you can use this function to move all non-NA cells to the left:

df1 <- data.frame(F1=c(1,5,NA,9),F2=c(2,5,"a",NA),F3=c(1,NA,"o",NA))
df1 <- as.data.frame(t(apply(df1,1, function(x) { return(c(x[!is.na(x)],x[is.na(x)]) )} )))
colnames(df1) <- c("F1", "F2", "F3")

Output:

> print(df1)
  F1   F2   F3
1  1    2    1
2  5    5 <NA>
3  a    o <NA>
4  9 <NA> <NA>

Secondly, in order to apply blank cells instead of NA-observations, you could try:

df1 <- sapply(df1, as.character)
df1[is.na(df1)] <- " "
df1 <- as.data.frame(df1)

Output:

> print(df1)
  F1 F2 F3
1  1  2  1
2  5  5   
3  a  o   
4  9    

Note: I changed your string "NA" to simply NA in order to detect the observations better. I'm not sure if you actually want the NA values to be observed as strings.

We can try the code below

df1[] <- t(apply(
  df1,
  1,
  function(v) {
    v[order(v == "NA")]
  }
))

which gives

> df1
  F1 F2 F3
1  1  2  1
2  5  5 NA
3  a  o NA
4  9 NA NA

Based on your preference I chose to complete each row after the omission of "NA" values, with "" as a sort of blank values. But you could choose to fill them with real NA values:

library(dplyr)
library(purrr)

df1 %>%
  pmap_dfr(~ {x <- c(...)[c(...) != "NA"]
  setNames(c(x, rep("", ncol(df1) - length(x))), 
           names(df1))})

# A tibble: 4 x 3
  F1    F2    F3   
  <chr> <chr> <chr>
1 1     "2"   "1"  
2 5     "5"   ""   
3 a     "o"   ""   
4 9     ""    ""   

First convert you data frame to character (else this will be an issue if you have both numeric and characters), then row apply, shift the values, pad with NAs

df2=sapply(df1,as.character)

t(
  sapply(1:nrow(df1),function(i){
    tmp=df1[i,df1[i,]!="NA"]
    if (length(tmp)<ncol(df1)) {
      tmp=c(tmp,rep("NA",ncol(df1)-length(tmp)))
    }
    tmp
  })
)

     F1  F2   F3  
[1,] "1" "2"  "1" 
[2,] "5" "5"  "NA"  
[3,] "a" "o"  "NA"  
[4,] "9" "NA" "NA"
Related