46

I have the following data frame, and am trying to merge the two columns into one, while replacing NA's with the numeric values.

ID    A     B
1     3     NA
2     NA    2
3     NA    4
4     1     NA

The result I want is:

ID    New
1     3
2     2
3     4
4     1

Thanks in advance!

m0nhawk
  • 22,980
  • 9
  • 45
  • 73
yongkornz
  • 461
  • 1
  • 4
  • 3

7 Answers7

36

This probably didn't exist when the answers were written, but since I came here with the same question and found a better solution, here it is for future googlers:

What you want is the coalesce() function from dplyr:

y <- c(1, 2, NA, NA, 5)
z <- c(NA, NA, 3, 4, 5)
coalesce(y, z)

[1] 1 2 3 4 5
jzadra
  • 4,012
  • 2
  • 26
  • 46
16

You can also do: with(d,ifelse(is.na(A),B,A))

where d is your data frame.

User7598
  • 1,658
  • 1
  • 15
  • 28
16

Another very simple solution in this case is to use the rowSums function.

df$New<-rowSums(df[, c("A", "B")], na.rm=T)
df<-df[, c("ID", "New")]

Update: Thanks @Artem Klevtsov for mentioning that this method only works with numeric data.

Hao
  • 7,476
  • 1
  • 38
  • 59
  • Also be careful that if both "A" and "B" columns have NAs then a 0 will be returned in "New". Not a problem in the test case . – thisisrg Oct 31 '16 at 02:38
15

You can use unite from tidyr:

library(tidyr)

df[is.na(df)] = ''
unite(df, new, A:B, sep='')
#  ID new
#1  1   3
#2  2   2
#3  3   4
#4  4   1
Colonel Beauvel
  • 30,423
  • 11
  • 47
  • 87
9

You could try

New <- do.call(pmax, c(df1[-1], na.rm=TRUE))

Or

New <-  df1[-1][cbind(1:nrow(df1),max.col(!is.na(df1[-1])))]
d1 <- data.frame(ID=df1$ID, New)
d1
#  ID New
#1  1   3
#2  2   2
#3  3   4
#4  4   1
akrun
  • 874,273
  • 37
  • 540
  • 662
6

Assuming either A or B have a NA, that would work just fine:

# creating initial data frame (actually data.table in this case)
library(data.table)
x<- as.data.table(list(ID = c(1,2,3,4), A = c(3, NA, NA, 1), B = c(NA, 2, 4, NA)))
x
#   ID  A  B
#1:  1  3 NA
#2:  2 NA  2
#3:  3 NA  4
#4:  4  1 NA


#solution
y[,New := na.omit(c(A,B)), by = ID][,c("A","B"):=NULL]
y
#   ID New
#1:  1   3
#2:  2   2
#3:  3   4
#4:  4   1
Krome
  • 371
  • 2
  • 10
4

This question's been around for a while, but just to add another possible approach that does not depend on any libraries:

df$new = t(df[-1])[!is.na(t(df[-1]))]

#   ID  A  B new
# 1  1  3 NA   3
# 2  2 NA  2   2
# 3  3 NA  4   4
# 4  4  1 NA   1
dww
  • 30,425
  • 5
  • 68
  • 111