首页 > 解决方案 > 如何使用第二个向量作为决胜局对向量进行排名?

问题描述

我需要为数字向量实现排名算法。我不知道是否可以使用 R 中的 rank()、order() 或 sort() 等函数来实现,或者我是否应该对其进行硬编码。无论哪种方式,我都做不到。

该算法的工作原理如下:

设 x = (x_1,x_2...,x_n) 和 y = (y_1,y_2,...y_n) 是两个向量。我们需要以这种方式构建由 x 的排序元素组成的向量 z:

  1. If x_i < x_j then z_i < z_j

  2. If x_i = x_j then

    • z_i < z_j if y_i < y_j
    • z_i > z_j if y_i > y_j
    • z_i = z_j if y_i = y_j
  3. If x_i is NA (missing) then

    • z_i > z_j if z_j is not NA
    • z_i = z_j if z_j is NA

例如,如果 x = (30,15,27,49,15) 且 y = (12,11,10,9,8),则 z = (4,2,3,5,1)

我想我可以使用order(order(x,y, na.last=T)),事实上,只要 x 中的关系也不与 y 相关,它就可以工作。如果是这种情况,那么order()将按照出现的顺序对它们进行排名,而不是让它们并列。

例如,如果 x = (30,15,27,49,15) 和 y = (12,8,10,9,8) 那么order(order(x,y, na.last=T))将输出 z = (4,1,3,5,2) 而不是 z = (4,1,3,5,1) 或另一个尊重步骤 2 的 z(例如 (3,1,2,4,1))。

我无法逃避。我该如何进行?

标签: rsortingranking

解决方案


tl; dr:我认为版本 1 是最好的。第 2 版和第 3 版是不太好的早期想法,但我将它们留在这里以防它们对任何人有用。


不幸的是rank,它没有提供使用第二个向量来打破平局的能力(一个有用的能力,order并且sort 确实允许)。

版本 1

但是,library(data.table)提供frank()了很好的工作。

x = c(30,15,27,49,15) 
y = c(12,11,10,9,8) 
frank(list(x,y), ties.method = "min")
# [1] 4 2 3 5 1

x = c(30,15,27,49,15) 
y = c(12,8,10,9,8)
frank(list(x,y), ties.method = "min")
# [1] 4 1 3 5 1

请注意,frank它还提供了另一个选项,ties.method = "dense"对于某些用途可能更好,因为它不会跳过排名(即,当两个值被赋予排名 1 时,下一个最大的值获得排名 2,而不是 3) - 请参见下面的示例

frank(list(x,y), ties.method = "dense")
[1] 3 1 2 4 1

版本 2

如果您想坚持使用基数 R,一种简单的解决方法是 rank x * K + y,其中 K 是任何足够大的数字,将最大的数字y加到 anyx*K不能改变顺序:

ranky = function(x,y) {
  K = 1 +  max(y) / min(diff(sort(unique(x))))
  rank(x*K + y, ties.method = 'min')
}

ranky(c(30,15,27,49,15), c(12,11,10,9,8) )
# [1] 4 2 3 5 1    
ranky(c(30,15,27,49,15), c(12,8,10,9,8))
# [1] 4 1 3 5 1

版本 3

同样在基础 R 中,您可以将每个固定宽度的字符串表示粘贴在一起,然后对组合的字符向量进行排名。

rank(paste(
      formatC(x, width = 15, flag = "0"), 
      formatC(y, width = 15, flag = "0")), 
     ties.method = 'min')

推荐阅读