Pipes, String and arguments and if_else - Conditional pipes

Apologies for not using reprex but i am getting and error message
*"Error in get_result(output = out, options) : *

  • callr subprocess failed: could not start R, exited with non-zero status, has crashed or was killed"*

How do I use arguments within pipes

#Apply certain functions conditionally without leaving the pipe-flow

Liberties taken with a previous examples posted here

hairdo <- tribble(~ hair, ~length,
"Longish Hair", "Little Long",
"Short Hair ", "Short",
"Bob", "Very Short",
"Weave", "Long",
"Long Hair", "Long",
"Longer Hair", "Very Long",
" Another Bob", "Short")

hairdo$hair %>% str_replace_all("Long","XX") #works

hairdo <- hairdo %>% mutate(colour = ifelse(grepl("Long.", hair),"Blond", "Brunette")) ##works

hairdo <- hairdo %>% mutate(colour = ifelse(hair == ("Long."),"Blond", "Brunette")) # does not work

hairdo$hair %>% str_to_lower() %>% str_squish() %>% if_else(str_detect("long"), "Blond", "Brunette") # does not work

hairdo %>% mutate(colour = case_when(hair %in% ("Long.") ~ "Blond", "Brunette")) # does not work

hairdo %>% {if ( (hairdo$hair %in% "Long.") == TRUE) filter(.,"Blond") else "Brunette"} # does not work

Where am I going wrong?

Is this what you are trying to do?

library(tidyverse)

hairdo <- tribble(~ hair, ~length,
                  "Longish Hair", "Little Long",
                  "Short Hair ", "Short",
                  "Bob", "Very Short",
                  "Weave", "Long",
                  "Long Hair", "Long",
                  "Longer Hair", "Very Long",
                  " Another Bob", "Short")

hairdo %>% mutate(colour = ifelse(str_detect(hair, "Long."), "Blond", "Brunette"))
#> # A tibble: 7 x 3
#>   hair           length      colour  
#>   <chr>          <chr>       <chr>   
#> 1 "Longish Hair" Little Long Blond   
#> 2 "Short Hair "  Short       Brunette
#> 3 "Bob"          Very Short  Brunette
#> 4 "Weave"        Long        Brunette
#> 5 "Long Hair"    Long        Blond   
#> 6 "Longer Hair"  Very Long   Blond   
#> 7 " Another Bob" Short       Brunette

Created on 2020-05-19 by the reprex package (v0.3.0)

Thanks Siddharth - That is what I set out to do and then entered a rabbit hole of trying to understand why various things did not work.

If you can guide me to wherever this is stated or explain it that will be great. if I am using pipes from a data frame, do i specifically need to mention the variable like hairdo$hair OR is it not necessary?

Is there a generic rule?

Why did this not work - hairdo$hair %>% str_to_lower() %>% str_squish() %>% if_else(str_detect("long"), "Blond", "Brunette")

Thanks a ton

The clue is in the error message.

hairdo$hair %>% str_to_lower() %>% str_squish() %>% if_else(str_detect("long"), "Blond", "Brunette")
#> Error: `condition` must be a logical vector, not a character vector

A good way to diagnose errors is by looking at the call stack.

rlang::last_error()
<error/rlang_error>
`condition` must be a logical vector, not a character vector
Backtrace:
  1. hairdo$hair
  1. stringr::str_to_lower(.)
  1. stringr::str_squish(.)
  9. dplyr::if_else(., str_detect("long"), "Blond", "Brunette")
 10. dplyr:::bad_args("condition", "must be a logical vector, not {friendly_type_of(condition)}")
 11. dplyr:::glubort(fmt_args(args), ..., .envir = .envir)
Run `rlang::last_trace()` to see the full context.

You can see on line 10 that problematic arguments were passed to the last function called i.e. if_else(). The first parameter in if_else() is condition which must be a logical vector. Here it is ..

Remember that %>% passes the object on the LHS as the first argument to the function on the right, Here your LHS is hairdo$hair which is a character vector. That's what caused the error.

Generally speaking, you should pass data frames into %>% rather than vectors extracted from those data frames as most tidyverse functions are designed to work with the former. Tidy evaluation then allows you to refer to variables within those objects directly.

Your call for example could be re-written as follows:

hairdo %>% 
  mutate(hair = str_to_lower(hair)) %>% 
  mutate(hair = str_squish(hair)) %>% 
  mutate(colour = if_else(str_detect(hair, "long"), "Blond", "Brunette"))
# A tibble: 7 x 3
  hair         length      colour  
  <chr>        <chr>       <chr>   
1 longish hair Little Long Blond   
2 short hair   Short       Brunette
3 bob          Very Short  Brunette
4 weave        Long        Brunette
5 long hair    Long        Blond   
6 longer hair  Very Long   Blond   
7 another bob  Short       Brunette

Thank you Siddharth for talking the time to respond. You explanation was very clear and to the point using the very same example so much easier to understand.

Follow up response using case_when instead of ifelse

hairdo %>% mutate(colour = case_when(hair == "Long" ~ "Blond", TRUE ~ "Brunette")) # does not work

This is because the variable 'hair' has strings which are not exactly equal to "Long" and I am not aware of using wildcards in R other than the following two methods

  1. Using grepl(pattern, input vector) works like so detecting any combination of "long" within hair

    hairdo <- hairdo %>% mutate(colour = case_when(grepl("Long", hair) ~ "Blond",TRUE ~ "Brunette"))

  2. As @siddharthprabhu pointed out in his responses using str_detect(input vector, pattern) also works

    hairdo <- hairdo %>% mutate(colour = case_when(str_detect(hair, "Long") ~ "Blond",TRUE ~ "Brunette"))

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.