'Looping a function/analysis in R by unique column values

I am trying to sort people in my dataset into three body-size categories (Small, Medium, Large). Consider the toy example below:

library(ggplot2)
library(dplyr)

# Toy dataset
Data<-data.frame(Age=c(40,40,40,41,41,41,42,42,42),
                 Height=c(180,179,178,177,176,175,174,173,172),
                 Weight=c(84,83,82,81,80,79,78,77,76))

# Classify people as Small, Medium, or Large
Data$Size<-Data$Height+Data$Weight
Data$Sizerank<-rank(Data$Size)
Data$Sizegroup<-as.numeric(cut_number(Data$Sizerank,3))
Data$CohortL<-ifelse(Data$Sizegroup==3,"Large",NA)
Data$CohortM<-ifelse(Data$Sizegroup==2,"Medium",NA)
Data$CohortS<-ifelse(Data$Sizegroup==1,"Small",NA)
temp1<-as.vector(Data$CohortL)
temp2<-as.vector(Data$CohortM)
temp3<-as.vector(Data$CohortS)
temp4<-data.frame(temp1,temp2,temp3)
temp5<-temp4%>%mutate(Cohort=coalesce(temp1,temp2,temp3))
Data$Cohort<-temp5$Cohort
Data<-data.frame(Data$Age,
                 Data$Height,
                 Data$Weight,
                 Data$Cohort)
colnames(Data)<-c("Age","Height","Weight","Cohort")

# Remove temporary files from workspace
rm(temp1,
   temp2,
   temp3,
   temp4,
   temp5)

# Print Data
Data

This code quantifies whether people are "Small" (bottom 1/3rd), "Medium" (middle 1/3rd), or "Large" (top 1/3rd), as compared to the whole dataset.

I would like to expand this code to perform the size ranking/grouping separately for each age group. So for example, ranking all 40-year-olds as to whether they are Small, Medium, or Large compared to other 40-year-olds, not the population at large. Ranking separately for each age group would clearly change the Cohort membership, in this case from Large/Large/Large/Medium/Medium/Medium/Small/Small/Small to Large/Medium/Small/Large/Medium/Small/Large/Medium/Small

If I only had three age groups then I would just run this analysis manually, but I have a much wider age range than this in practice, so I think that I need some sort of looping function, maybe a for loop or one of the apply() functions?

Any help or insights would be greatly appreciated. Thank you very much.

P.S. I am also aware that my method of contructing the "Cohort" column is cumbersome, so if anybody knows of a more elegant approach to this then I would be very happy to learn about it.



Solution 1:[1]

How about this:

library(dplyr)

Data %>% 
  group_by(Age) %>% 
  mutate(size = gtools::quantcut(I(Height + Weight), 
                                 q=3, 
                                 labels=c("Small", "Medium", "Large")))
#> # A tibble: 9 × 5
#> # Groups:   Age [3]
#>     Age Height Weight Cohort size  
#>   <dbl>  <dbl>  <dbl> <chr>  <fct> 
#> 1    40    180     84 Large  Large 
#> 2    40    179     83 Large  Medium
#> 3    40    178     82 Large  Small 
#> 4    41    177     81 Medium Large 
#> 5    41    176     80 Medium Medium
#> 6    41    175     79 Medium Small 
#> 7    42    174     78 Small  Large 
#> 8    42    173     77 Small  Medium
#> 9    42    172     76 Small  Small

Solution 2:[2]

I dont know if i understand exactly... But, try this.

Obs: You need to install Hmisc package.

Data2 <- Data %>%
      mutate(Size = Height + Weight) %>%
      group_by(Age) %>%
      mutate(Cohort_groups = as.numeric(Hmisc::cut2(Size, g=3))) %>%
      mutate(Cohort = case_when(
        Cohort_groups  == 3 ~ "Large",
        Cohort_groups == 2 ~ "Medium",
        Cohort_groups == 1 ~ "Small")) %>%
      select(-Cohort_groups)
      
   Data2

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 DaveArmstrong
Solution 2