Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use if/ifelse on dplyr's group_by

Tags:

r

dplyr

Is there anyway to apply a conditional group_by? For example (code DOESN'T work btw but its just to show the iris dataset so you get the gist):

iris$Sepal.Width.r <- round(iris$Sepal.Width)
for(i in 1:2){
test <- iris %>% 
  ifelse(i == 1, group_by(Species), group_by(Sepal.Width.r)) %>% #****
  summarise(avgLWdiff = (mean(Petal.Length) - mean(Petal.Width)))
  print(test)
}

The starred line #**** is my very rough (and wrong) guess on what it should look like. I think the questions I've seen from others so far ask about the if statement within the summarise/mutate line but I haven't seen anyone ask about the group_by line. Also, the contents within my summarise takes up a few lines.

My desired output is:

when i==1:

Species    avgLWdiff 
<fct>          <dbl> 
1 setosa         1.22 
2 versicolor      2.93 
3 virginica       3.53

when i == 2:

Sepal.Width.r avgLWdiff
<dbl>     <dbl>
1             2      2.76
2             3      2.76
3             4      1.54
like image 579
eyy Avatar asked Nov 05 '25 16:11

eyy


2 Answers

You can do this using if, not ifelse. Remember that if is the one to use for control flow, which is what you want.

iris %>% 
   {if(i == 1) group_by(., Species) else group_by(., Sepal.Width.r)} %>% 
   summarise(avgLWdiff = (mean(Petal.Length) - mean(Petal.Width)))

Here I've put the if clause in {}, because otherwise the pipe would try to put iris in as the test. By using the {} the magrittr pipe looks deeper for the dot.

Doing this with the base pipe is harder, because it's less flexible. I think you need to define a small helper function to get it to work:

 f <- function(d){if(i == 1) group_by(d, Species) else group_by(d, Sepal.Width.r)}
 iris |> f() |>
   summarise(avgLWdiff = (mean(Petal.Length) - mean(Petal.Width)))
like image 192
user2554330 Avatar answered Nov 07 '25 11:11

user2554330


Here is one possible way to solve your problem. I am using the pipe from dplyr but you can replace it with the built-in pipe and you will get the same result.

for(i in 1:2){
  test <- iris %>% 
    group_by(across(all_of(if(i==1) "Species" else "Sepal.Width.r"))) %>%  
    summarise(avgLWdiff = (mean(Petal.Length) - mean(Petal.Width)))
  print(test)
}

# # A tibble: 3 x 2
#   Species    avgLWdiff
#   <fct>          <dbl>
# 1 setosa          1.22
# 2 versicolor      2.93
# 3 virginica       3.53

# # A tibble: 3 x 2
#   Sepal.Width.r avgLWdiff
#           <dbl>     <dbl>
# 1             2      2.76
# 2             3      2.76
# 3             4      1.54
like image 31
B. Christian Kamgang Avatar answered Nov 07 '25 10:11

B. Christian Kamgang



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!