Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return highest values in a vector with multiple conditionals

Tags:

r

dplyr

summary

I have these example data

Data <- structure(list(IndID = structure(c(1L, 1L, 2L, 2L, 3L, 3L, 4L, 
4L, 5L, 5L, 6L, 6L, 7L, 7L, 8L, 8L, 9L, 9L, 10L, 10L), .Label = c("1", 
"2", "3", "4", "5", "56", "58", "59", "60", "63"), class = "factor"), 
    Species = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
    1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), .Label = c("BHS", 
    "MTG"), class = "factor"), Season = structure(c(1L, 2L, 1L, 
    2L, 2L, 1L, 1L, 2L, 2L, 1L, 2L, 1L, 1L, 2L, 1L, 2L, 1L, 2L, 
    1L, 2L), .Label = c("Summer", "Winter"), class = "factor"), 
    Percent = c(0.992, 0.992, 0.996, 0.976, 0.995, 0.871, 0.996, 
    0.996, 0.916, 0.875, 0.652, 0.802, 0.964, 0.673, 0.956, 0.879, 
    0.972, 0.782, 0.968, 0.832)), .Names = c("IndID", "Species", 
"Season", "Percent"), row.names = c(NA, -20L), class = "data.frame")

Which look like this

> head(Data)
  IndID Species Season Percent
1     1     BHS Summer   0.992
2     1     BHS Winter   0.992
3     2     BHS Summer   0.996
4     2     BHS Winter   0.976
5     3     BHS Winter   0.995
6     3     BHS Summer   0.871

There are 10 unique individuals that belong to one of two species (BHS or MTG). For each individual (IndID), there is a Percent value for each Season (Winter and Summer).

For each Species, I want to select the two individuals that have the highest average Percent value.

EDIT Also see my note below. I did not post a specific outcome because there are multiple that would work for my needs. Because I need a measure Percent for each Season, I thought taking the average of the Percent would be the best approach to select the top individuals. Percent was measured for each season, but I want to select the highest rank IndID. I could also rank IndID by the sum of Percent (rather than average).

In addition to the 2nd chunk of code posted by @akrun, a vector of 4 IndIDs (the two top ranked for each species) would also have been a fine output.

Thanks in advance for your help.

like image 724
B. Davis Avatar asked Sep 16 '26 02:09

B. Davis


1 Answers

Assuming that you would like a dplyr solution (from the tag), we group the data by 'Species', order 'Percent' column in descending (arrange) and use slice to get the first two rows per each 'Species'

library(dplyr)
Data %>%
      group_by(Species) %>%
      arrange(desc(Percent)) %>%
      slice(1:2)
#    IndID Species Season Percent
#1     2     BHS Summer   0.996
#2     4     BHS Summer   0.996
#3    60     MTG Summer   0.972
#4    63     MTG Summer   0.968

An expected output would have been easier. If this is based on average percentage, we group by 'Species' and 'IndID', create a new column 'AvgPercent' based on the mean of 'Percent', we group by 'Species', order the 'AvgPercent' column in descending order and get the 1st two 'IndID'

 Data %>%
      group_by(Species, IndID) %>%
      mutate(AvgPercent=mean(Percent))  %>%
      group_by(Species) %>% 
      arrange(desc(AvgPercent)) %>% 
      slice(1:4) %>% 
      select(-AvgPercent) %>%
      filter(!duplicated(IndID))
 #   IndID Species Season Percent
 #1     4     BHS Summer   0.996
 #2     1     BHS Summer   0.992
 #3    59     MTG Summer   0.956
 #4    63     MTG Summer   0.968
like image 153
akrun Avatar answered Sep 17 '26 15:09

akrun



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!