Reputation: 8427
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
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
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
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
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