【问题标题】:Calculate rank with ties based on more than one variable基于多个变量计算平局排名
【发布时间】:2017-08-28 11:03:46
【问题描述】:

我正在尝试计算体育赛事的奖牌表。

我的数据如下所示:

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), ]))

然后计算最终的奖牌排名。这就是最终排名列的样子:

(test_ordered$rank<-c(1, 2, 2, 4, 5, 5))

 #    ID gold silver bronze rank
 # 1 1_1   10      1      1    1
 # 4 1_4    7     19      0    2
 # 5 1_5    7     19      0    2
 # 2 1_2    4      3      8    4
 # 3 1_3    1      2      2    5
 # 6 1_6    1      2      2    5

由于 ID“1_4”和“1_5”赢得了相同的奖牌组合,他们将共享排名 2,例如

我使用rank(也是dplyr::min_ranked)的两个以上条件的尝试失败了:

with(test, rank(-gold, -silver, -bronze, ties.method = "min")) 
# (...) unused argument (-bronze)

还有interaction 没有成功:

as.numeric(interaction(gl(-test$gold), gl(-test$silver), gl(-test$bronze), lex.order = TRUE))

任何想法如何根据多个变量计算排名?


用henrik的思路解决了:

as.data.frame(setDT(test)[ , rank := frank(test, -gold, -silver, -bronze, ties.method = "min")]; setorder(test, rank))

【问题讨论】:

  • 如果你对最大奖牌数量有一个很好的了解,你可以做类似test_ordered$rank &lt;- with(test_ordered,rank(-10000*gold-100*silver-bronze, ties.method = "min"))
  • 好主意,有点粗糙,但也有效。

标签: r ranking


【解决方案1】:

您可以使用data.table 等效于base::rankfrankfrank 的一个很好的特性是它不仅接受向量(如rank),还接受data.framedata.table 作为输入。对于这些类型的对象,排名可能基于几列。

使用您原来的data.frame

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

或者,如果您想使用data.table 函数:

setDT(test)[ , rank := frank(test, -gold, -silver, -bronze, ties.method = "min")]
setorder(test, rank)

【讨论】:

    【解决方案2】:

    基本的 R 解决方案是:

    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")])))
    

    【讨论】:

      猜你喜欢
      • 2023-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-18
      • 1970-01-01
      相关资源
      最近更新 更多