I want to paste together some columns with some text where they are combined only if at least one is not NA and the current solution I have works, but is cumbersome. So I am wondering if there is a neater way to do this (to create the "combine" column below). I would like to have used tidyr but there doesn't seem to be a way to specify how to treat missing values in unite()
Thanks and I hope I haven't missed something obvious.
df = data.frame(num=c(1,2,NA,NA),place=c("Rome",NA,"Paris",NA))
df$combine[!is.na(df$num)|!is.na(df$place)] =
paste(df$num[!is.na(df$num)|!is.na(df$place)],
"days in",df$place[!is.na(df$num)|!is.na(df$place)])
# df
# num place combine
# 1 1 Rome 1 days in Rome
# 2 2 <NA> 2 days in NA
# 3 NA Paris NA days in Paris
# 4 NA <NA> <NA>
Whenever you find yourself computing the same thing (here: index) again, try to store it and reuse that object to avoid redundant computation. For your example, you could compute the non-NA index as follows:
idx <- rowSums(!is.na(df)) > 0
Then, you can use that to paste the relevant rows together:
df[idx, "combine"] <- with(df[idx, ], paste(num, "days in", place))
We can use mutate
with ifelse
from dplyr
library(dplyr)
df %>%
mutate(combine = ifelse(rowSums(!is.na(.))>0, paste(num, "days in", place), NA))
# num place combine
#1 1 Rome 1 days in Rome
#2 2 <NA> 2 days in NA
#3 NA Paris NA days in Paris
#4 NA <NA> <NA>
Or using data.table
library(data.table)
setDT(df)[df[, !Reduce(`&`, lapply(.SD, is.na))], combine := paste(num, "days in", place)]
df
# num place combine
#1: 1 Rome 1 days in Rome
#2: 2 NA 2 days in NA
#3: NA Paris NA days in Paris
#4: NA NA NA
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With