Tie breaking mode with values in a second column -R

Viewed 104

I'd like to create a variable that contains the most frequent observation of a factor. In the case that there is a tie in the mode, I want to use the value of a second column to break the tie.

So for example:

person <- c("X", "Y", "Z", "Y", "Y", "Z")
id<-c(0,1,0,1,1,1)
year<-c("2019", "2019", "2020", "2019", "2020", "2020")
value<-(c(1, 2, 3, 4, 5, 6))
test <- data.frame(person, id, year, value)
  person id year value
      X  0 2019     1
      Y  1 2019     2
      Z  0 2020     3
      Y  1 2019     4
      Y  1 2020     5
      Z  1 2020     6

Here's what I get when I calculate the mode, where NA is currently used to denote a tie:

mode <- function(x) {
  ux <- unique(na.omit(x))
  tx <- tabulate(match(x, ux))
  if(length(ux) != 1 & sum(max(tx) == tx) > 1) {
    if (is.character(ux)) return(NA_character_) else return(NA_real_)
  }
  max_tx <- tx == max(tx)
  return(ux[max_tx])
}

idmode<-test%>%group_by(person, year)%>%dplyr::summarise(Mode =mode(id))

  person year     Mode
  <chr>  <chr>   <dbl>
 X      2019        0
 Y      2019        1
 Y      2020        1
 Z      2020       NA

I'd like to replace the NA with the id that has the highest value in each person/year group. The desired output:

  person year     Mode
  <chr>  <chr>   <dbl>
 X      2019        0
 Y      2019        1
 Y      2020        1
 Z      2020        1

The id for Z in 2020 is now 1 because id=1 had a higher value (6) than the value for id=0(3)

1 Answers

We can replace the NA with the 'id' that corresponds to max value (which.max)

library(dplyr)
library(tidyr)
test%>%
   group_by(person, year)%>%
   dplyr::summarise(Mode =replace_na(mode(id), 
          id[which.max(value)]), .groups = 'drop')
Related