Home > Blockchain >  Mutate, case_when, paste in R
Mutate, case_when, paste in R

Time:09-16

apple banana orange fruits_name
1 0 1 apple orange
1 0 0 apple
1 0 1 apple orange
1 1 1 apple banana orange

I want to create and mutate the column "frutis_name" if the rest of the columns get 1. As an example, apple and orange got 1 then "frutis_name will be apple space banana.

CodePudding user response:

Using purrr::map_chr() :

df <- data.frame(apple = c(1,1),    banana = c(0,0),    orange = c(1,0))

df$fruit_name <- purrr::pmap_chr(df, ~ paste(names(df)[as.logical(c(...))], collapse = " "))
df
#>   apple banana orange   fruit_name
#> 1     1      0      1 apple orange
#> 2     1      0      0        apple

CodePudding user response:

Perhaps not the easiest solution but one that works, based on the idea of recasting column names as values, which is done by pivot_longer:

library(tidyverse)
df %>%
  # create row ID:
  mutate(row = row_number()) %>%
  # cast longer so that fruit names become values:
  pivot_longer(-row, names_to = "fruits") %>%
  # for each combination of `row` and `value`...
  group_by(row, value) %>%
  # ... combine fruit names if `value == 1`:
  mutate(fruits = ifelse(value == 1, str_c(fruits, collapse = " "), fruits)) %>%
  # remove obsolete rows:
  filter(value == 1 & !duplicated(fruits)) %>%
  # deactivate grouping:
  ungroup() %>%
  # remove unnecessary columns:
  select(-c(value, row)) %>%
  # bind original `df` together with new `fruit` column:
  bind_cols(df, .)
  apple banana orange              fruits
1     1      0      1        apple orange
2     1      0      0               apple
3     1      0      1        apple orange
4     1      1      1 apple banana orange

CodePudding user response:

df$fruits_name <- 
  apply(df, 1, \(x) paste(names(df)[as.logical(x)], collapse = " "))

#   apple banana orange         fruits_name
# 1     1      0      1        apple orange
# 2     1      0      0               apple
# 3     1      0      1        apple orange
# 4     1      1      1 apple banana orange

Same logic but more efficient

library(data.table)
df$fruits_name <- 
  vapply(transpose(df), \(x) paste(names(df)[as.logical(x)], collapse = " "), character(1L))

Reproducible data

df <- data.frame(
  apple  = 1,    
  banana = c(0,0,0,1),   
  orange = c(1,0,1,1)
)

CodePudding user response:

You can use apply to do it:

 x <- data.frame(apple = c(1,0,1), banana = c(0,0,1), orange = c(1,0,0))
 x$fruits_name <- apply(x, 1, function(y) paste(colnames(x)[y==1], collapse=" "), simplify = TRUE)
 x
 apple banana orange         fruits_name
 1     1      0      1 apple orange
 2     0      0      0              
 3     1      1      0 apple banana

EDIT: I replaced the sep parameter with collapse and now it produces a vector, not a list

  • Related