TheMP
TheMP

Reputation: 8427

Merge multiple columns into one

I have an R data.frame (simplified case, in fact there is dozens of TRUE/FALSE columns):

 name = c("ball", "pen", "box") 
 red = c(TRUE, FALSE, FALSE) 
 green = c(TRUE, TRUE, FALSE) 
 blue = c(TRUE, TRUE, FALSE) 
 df = data.frame(name, red, green, blue)

name   red green  blue
1 ball  TRUE  TRUE  TRUE
2  pen FALSE  TRUE  TRUE
3  box FALSE FALSE FALSE

I want to append a column to df containing concatenation of all colors marked TRUE into one:

name   red green  blue   color
1 ball  TRUE  TRUE  TRUE red,green,blue
2  pen FALSE  TRUE  TRUE green, blue
3  box FALSE FALSE FALSE na

Is there a way to do this without writing a cumbersome load of ifelse/paste statements?

Upvotes: 1

Views: 249

Answers (4)

moodymudskipper
moodymudskipper

Reputation: 47350

With tidyverse (here tidyr + dplyr) you could do:

library(tidyverse)
df %>% gather(,,-1) %>%
  filter(value) %>%
  group_by(name) %>%
  summarise(color=paste(key,collapse=",")) %>%
  right_join(df) # left_join(df,.) to preserve your column order

# # A tibble: 3 x 5
#     name          color   red green  blue
#   <fctr>          <chr> <lgl> <lgl> <lgl>
# 1   ball red,green,blue  TRUE  TRUE  TRUE
# 2    pen     green,blue FALSE  TRUE  TRUE
# 3    box           <NA> FALSE FALSE FALSE

Upvotes: 1

C. Braun
C. Braun

Reputation: 5211

There may be a more efficient way to do it without using dplyr, but you can calculate this for each row using rowwise and do:

rowwise(df) %>% do({
    result = as.data.frame(.)
    result$color = paste(names(result)[result == TRUE], collapse = ',')
    result
})

# Source: local data frame [3 x 5]
# Groups: <by row>
# 
# # A tibble: 3 x 5
#   name  red   green blue  color         
# * <fct> <lgl> <lgl> <lgl> <chr>         
# 1 ball  TRUE  TRUE  TRUE  red,green,blue
# 2 pen   FALSE TRUE  TRUE  green,blue    
# 3 box   FALSE FALSE FALSE "" 

Upvotes: 1

Maurits Evers
Maurits Evers

Reputation: 50738

We can use base R's toString in the following way:

df$color <- apply(df[, -1], 1, function(x) toString(names(df[, -1])[x]));
df;
#  name   red green  blue            color
#1 ball  TRUE  TRUE  TRUE red, green, blue
#2  pen FALSE  TRUE  TRUE      green, blue
#3  box FALSE FALSE FALSE

Upvotes: 5

erocoar
erocoar

Reputation: 5923

E.g. this way

library(tidyverse)
df %>% mutate(color = apply(df[, -1], 1, function(x) colnames(df)[-1][x]))

  name   red green  blue            color
1 ball  TRUE  TRUE  TRUE red, green, blue
2  pen FALSE  TRUE  TRUE      green, blue
3  box FALSE FALSE FALSE            

Upvotes: 0

Related Questions