Calculate rank with ties based on more than one variable

前端 未结 2 689
星月不相逢
星月不相逢 2020-12-21 17:14

I\'m trying to compute a medal table for a sports event.

My data looks like this:

test <- data.frame(\"ID\" = c(\"1_1\", \"1_2\", \"1_3\", \"1_4\         


        
相关标签:
2条回答
  • 2020-12-21 17:59

    A base R solution would be:

    test <- data.frame("ID"=c("1_1", "1_2", "1_3", "1_4","1_5","1_6"), 
                       "gold"=c(10,4,1,7,7,1), 
                       "silver"=c(1,3,2,19,19,2), 
                       "bronze"=c(1,8,2,0,0,2))
    
    (test_ordered<-with(test, test[order(-gold,-silver,-bronze),]))
    
    roll.any.greater <- function (mat) {
      mat.lead <- head(mat, -1)
      mat.lag <- tail(mat, -1)
      result <- rep(1, nrow(mat.lead) + 1)
      for (i in (2:length(result))) {
        result[i] <- ifelse(any(as.logical(abs(mat.lead[i-1, ] - mat.lag[i-1, ]))) != FALSE,
                            i, result[i-1])
      }
      return(result)
    }
    (want <- cbind(test_ordered,
                   rank =
                   roll.any.greater(test_ordered[colnames(test_ordered) %in% c("gold", "silver", "bronze")])))
    
    0 讨论(0)
  • 2020-12-21 18:00

    You may use the data.table equivalent of base::rank, frank. A nice feature with frank is that it accepts, not only vectors (as in rank), but also a data.frame or a data.table as input. For these types of objects, the rank may be based on several columns.

    Using your original data.frame:

    test$rank <- data.table::frank(test, -gold, -silver, -bronze, ties.method = "min")
    

    Or if you want to go all in with data.table functions:

    setDT(test)[ , rank := frank(test, -gold, -silver, -bronze, ties.method = "min")]
    setorder(test, rank)
    
    0 讨论(0)
提交回复
热议问题