How to check elements in vector for true/false and create new values based on results

Viewed 38

I have a dataframe structured similarly to below (but much longer and with many more groups):

df <- data.frame(Color = c("Green", "Green" ," Green", "Red", "Red", "Red", "Blue", "Blue", "Blue"), Occurrences = c(1,27,59,2,3,6,8,4,200))

> df
   Color Occurrences
1  Green           1
2  Green          27
3  Green          59
4    Red           2
5    Red           3
6    Red           6
7   Blue           8
8   Blue           4
9   Blue         200

and another dataframe with quartiles derived from a larger dataset of colors and occurrences

dfQuar <- data.frame(Color = c("Green", "Red", "Blue"), 
                     X25. = c(10,2,5), 
                     X50. = c(20,4,10), 
                     X75. = c(30,6,15))

> dfQuar
  Color X25. X50. X75.
1 Green   10   20   30
2   Red    2    4    6
3  Blue    5   10   15

My objective is to add another column to df called size where if the occurrences of the color falls into one of the quartiles, I label it either small, medium, large, or extra large. For example, df would look like this:

   Color Occurrences        Size
1  Green           1       Small
2  Green          27       Large
3  Green          59 Extra Large
4    Red           2       Small
5    Red           3      Medium
6    Red           6       Large
7   Blue           8      Medium
8   Blue           4       Small
9   Blue         200 Extra Large

I attempted this by doing the following:

colors <- unique(df$Color)
dfSized <- data.frame()

for(i in 1:length(colors)) {
  tempProj <- subset(df, Color == colors[i])
  tempQuar <- subset(dfQuar, Color == colors[i])
  if(tempProj$Occurrences <= tempQuar$X25.[1]) {
    tempProj$Size <- "Small"
  } else if (tempProj$Occurrences <= tempQuar$X50.[1]) {
    tempProj$Size <- "Medium"
  } else if (tempProj$Occurrences <= tempQuar$X75.[1]) {
    tempProj$Size <- "Large"
  } else {
    tempProj$Size <- "Extra Large"
  }
  dfSized <- bind_rows(dfSized, tempProj)
}

However I keep getting the message the condition has length > 1 and only the first element will be used

How do I avoid this by analyzing each element in the vector rather than just the first element? I'm totally open to avoid doing this by for loop or lists of if else statements if there's something more efficient.

1 Answers

We could join the two datasets by 'Color' (left_join), create the 'Size' with a comparison operators in case_when on the 'Occurrences' and the columns 'X25.', 'X75.' etc

library(dplyr)
df %>%
  left_join(dfQuar) %>%
   transmute(Color, Occurrences,
      Size = case_when(Occurrences <= X25. ~ 'Small', 
              Occurrences > X25. & Occurrences <= X75. ~ 'Large', 
              TRUE ~ 'Extra Large'))

-output

#  Color Occurrences        Size
#1 Green           1       Small
#2 Green          27       Large
#3 Green          59 Extra Large
#4   Red           2       Small
#5   Red           3       Large
#6   Red           6       Large
#7  Blue           8       Large
#8  Blue           4       Small
#9  Blue         200 Extra Large
Related