R语言rank函数详细解析

1.rank函数是什么

rank相关文档[1]可以译为"返回原数组(?)中各个元素排序(?)后的秩次(?)",表面上看确实可以得到次序,但对数组、排序、秩次交待不清。

2.rank函数使用情景

比如,在100米赛跑中,甲乙丙三人的成绩为6.8s, 8.1s, 7.2s,那么用rank函数排序获得名次

> rank(t <- c(6.8, 8.1, 7.2))
[1] 1 3 2

再如,甲乙丙三人考试得分为74,92,85,用同样方法取得名次会适得其反。当然,我们可以认为执行

> rank(-(s <- c(74, 92, 85)))
[1] 3 1 2

可以达到目的,但这并未改变rank函数的排序机制。

3.rank函数排序类型

rank(x, na.last = TRUE,
     ties.method = c("average", "first", "random", "max", "min"))

> t <- c(4, NaN, 4, 7, 8, 2, NaN, 9, 9, 7, NaN, 5, 2, 2, 1)
#同时对相应元素做好标记
> names(t) <- letters[1 : length(t)]

通过以上方法进行排序,得出

Result
  a b c d e f g h i j k l m n o
original 4 NaN 4 7 8 2 NaN 9 9 7 NaN 5 2 2 1
average 5.5 13.0 5.5 8.5 10.0 3.0 14.0 11.5 11.5 8.5 15.0 7.0 3.0 3.0 1.0
first 5 13 6 8 10 2 14 11 12 9 15 7 3 4 1
random (1) 6 13 5 9 10 2 14 11 12 8 15 7 3 4 1
random (2) 5 13 6 8 10 2 14 11 12 9 15 7 4 3 1
max 6 13 6 9 10 4 14 12 12 9 15 7 4 4 1
min 5 13 5 8 10 2 14 11 11 8 15 7 2 2 1

我们发现,标签"b","g","k"的次序并未发生改变,可推断ties.method作用在于处理非缺失值的顺序

不妨参考rank的实现代码

function (x, na.last = TRUE, ties.method = c("average", "first",
    "random", "max", "min"))
{
    nas <- is.na(x) #得到与x相同长度的boolean型数组,用来标记相应位是否为缺失值
    nm <- names(x)  #获取数组中元素所对应的标签  #names函数暗示了该方法的设计初衷是对一维数组即列向量进行排序,虽然x为矩阵也会得出结果,但nm的作用已经失效,结果不具有意义  
    ties.method <- match.arg(ties.method)
    if (is.factor(x))
        x <- as.integer(x) #若x为因子,则对元素"归类",并按"类的大小"进行整数元素编码,具体请见[说明1]
    x <- x[!nas] #剔除x中的缺失值

  #average\min\max采用了相应的.Internal(rank(x, length(x), ties.method)),具体请见[说明2]  #first采用了sort.list(sort.list(x)),具体请见[说明3]  #random采用了sort.list(order(x, stats::runif(sum(!nas)))),具体请见[说明4]
    y <- switch(ties.method, average = , min = , max = .Internal(rank(x,
        length(x), ties.method)), first = sort.list(sort.list(x)),
        random = sort.list(order(x, stats::runif(sum(!nas)))))

  #下面是补全缺失值的次序的方法  #na.last = "keep",不处理缺失值,na.last = TRUE,后排序缺失值,na.last = FALSE,先排序缺失值。
    if (!is.na(na.last) && any(nas)) {
        yy <- NA
        NAkeep <- (na.last == "keep")
        if (NAkeep || na.last) {
            yy[!nas] <- y
            if (!NAkeep)
                yy[nas] <- (length(y) + 1L):length(yy)
        }
        else {
            len <- sum(nas)
            yy[!nas] <- y + len
            yy[nas] <- seq_len(len)
        }
        y <- yy
        names(y) <- nm
    }
    else names(y) <- nm[!nas]
    y
}

[说明1] 关于因子转整数

> f <- c(‘Ba‘, ‘BA‘, ‘b‘, ‘A‘, ‘A‘, ‘b‘, ‘Ba‘, ‘Bac‘, NaN, NaN)
> fac <- factor(colour)
> as.integer(fac)
 [1] 3 4 2 1 1 2 3 5 6 6

由此可见: (1) 因子会作为字符串进行机械比较,排出次序。(2) 因子中任意两个缺失值地位(大小)相同。

实际问题中,因子为人为设定,故采用有序因子(ordered factor),消除机械转换的干扰。

> qulity <- c(‘good‘,‘soso‘,‘good‘,‘soso‘,‘bad‘,‘good‘,‘bad‘)
> names(qulity) <- c(‘day1‘,‘day2‘,‘day3‘,‘day4‘,‘day5‘,‘day6‘,‘day7‘)
> q <- factor(qulity, levels = c(‘bad‘,‘soso‘,‘good‘), labels = c(‘bad‘, ‘soso‘, ‘good‘), order = TRUE)
> rank(q)
day1 day2 day3 day4 day5 day6 day7
 6.0  3.5  6.0  3.5  1.5  6.0  1.5 

[说明2] "average", "max", "min" 排序

> t
  a   b   c   d   e   f   g   h   i   j   k   l   m   n   o
  4 NaN   4   7   8   2 NaN   9   9   7 NaN   5   2   2   1
> rank(t, na.last = "keep", ties.method = "first")
 a  b  c  d  e  f  g  h  i  j  k  l  m  n  o
 5 NA  6  8 10  2 NA 11 12  9 NA  7  3  4  1
> rank(t, na.last = "keep", ties.method = "average")
   a    b    c    d    e    f    g    h    i    j    k    l    m    n    o
 5.5   NA  5.5  8.5 10.0  3.0   NA 11.5 11.5  8.5   NA  7.0  3.0  3.0  1.0 

可以将"average"排序理解为先对数据进行"first"排序,即全部元素都有唯一且不同的次序。

如f, m, n 得分相同,但可按先后次序排成2, 3, 4, 但是f, m, n属于同一群体,故可以取该群体中的平均水平作为次序,使得分相同的元素地位相当。

故不难理解"max"排序是群体中的元素全部取群中最好的水平,这也是普遍采用的“并列排名”方法;

"min"排序是群体中的元素全部取群体中最差的水平,这样增大了不同等级的顺序差异。

[说明3] first = sort.list(sort.list(x))

对序列先按大小排序,大小相同的元素,从头至尾由小到大排序。

> x
a c d e f h i j l m n o
4 4 7 8 2 9 9 7 5 2 2 1
> sort.list(sort.list(x))
 [1]  5  6  8 10  2 11 12  9  7  3  4  1

[说明4] random = sort.list(order(x, stats::runif(sum(!nas))))

weight = stats::runif(sum(!nas)) 为每个已知元素生成0-1之间随机数,作为“权重”序列weight

sort.list(order(x, weigth)) 依据随机的“权重”决定得分相同的元素的次序

不妨人为参与权重设计

a c d e f h i j l m n o
4 4 7 8 2 9 9 7 5 2 2 1
> weight = c(0.45, 0.55, 0.1, 0.1, 0.1, 0.55, 0.45, 0.1, 0.1, 0.3, 0.1, 0.1);
> sort.list(order(x,weight))
 [1]  5  6  8 10  2 12 11  9  7  4  3  1

不难发现,a, c 得分均为4,但w(a) = 0.45 < w(c) = 0.55, 遵照小号在前,a 排在c 前面。h, j 刚好相反w(h) = 0.55 > w(j) = 0.45, j 排在h 前面。

d, j 得分,“权重”均相同,故按之前从头到尾递增顺序排列。

f, m, n 得分均为2, w(f) = w(n) = 0.1 < w(m) = 0.3, 排序结果为f < n < m, 由此可见,“权重”优先于“前后顺序”,这样做使得排序更加随机化,若序列存在大量得分相同的元素,一定程度克服了“前小后大”规则的约束,使排序结果更随机。

以上仅为说明随机排序的机制,实际应用中只能确定小数在前大数在后,并不能解释相同的数之间的顺序。

4.rank函数小结

rank(x, na.last = TRUE,
     ties.method = c("average", "first", "random", "max", "min"))

(1) rank 函数是对一维度数组、向量x 进行排序。若x 为数值,则按照小数在线大数在后的原则进行排序,若x 为因子,则应参考[说明1]进行顺序因子设计。

P.S. 实际情况中,存在大量用二维表格描述的数据,比如行表示地点列表示时间的统计表,若进行排序,应先通过字符拼接的手段将表格转化为一维的向量,否则结果将失去意义。

(2) rank 将数据分为确定值与缺失值两种。缺失值可按先后排在确定值之间(na.last = FALSE), 也可排在之后(na.last = TRUE), 也可保留,不参与排序(na.last = "keep").

(3) "first" 是最基本的排序,小数在前大数在后,相同元素先者在前后者在后。

  "max" 是相同元素都取该组中最好的水平,即通常所讲的并列排序。

  "min" 是相同元素都取该组中最差的水平,可以增大序列的等级差异。

  "average" 是相同元素都取该组中的平均水平,该水平可能是个小数。

  "random" 是相同元素随机编排次序,避免了“先到先得”,“权重”优于“先后顺序”的机制增大了随机的程度。

[1]Returns the sample ranks of the values in a vector. Ties (i.e., equal values) and missing values can be handled in several ways.

时间: 2024-10-26 13:14:33

R语言rank函数详细解析的相关文章

C语言scanf函数详细解释(转)

函数名: scanf 功 能: 执行格式化输入 用 法: int scanf(char *format[,argument,...]); scanf()函数是通用终端格式化输入函数,它从标准输入设备(键盘) 读取输入的信息.可以读入任何固有类型的数据并自动把数值变换成适当的机内格式. 其调用格式为:      scanf("<格式化字符串>",<地址表>); scanf()函数返回成功赋值的数据项数,出错时则返回EOF. 其控制串由三类字符构成: 1.格式化说明

R语言——绘图函数深入学习

利用R自带数据集 通过data()函数可以查看R自带数据集. > data() 返回以下结果,每一条记录都是一个数据,键入相应的数据名称可以查看具体信息. Data sets in package ¡®datasets¡¯: AirPassengers Monthly Airline Passenger Numbers 1949-1960 BJsales Sales Data with Leading Indicator BJsales.lead (BJsales) Sales Data wit

R语言seq()函数用法

1.seq() 用来生成一组数字的函数. Usage: ## Default S3 method:seq(from = 1, to = 1, by = ((to - from)/(length.out - 1)),length.out = NULL, along.with = NULL, ...)seq.int(from, to, by, length.out, along.with, ...)seq_along(along.with)seq_len(length.out) Arguments:

R语言table()函数

R语言table()函数比较有用,两个示例尤其是混淆矩阵这个案例比较有用: 例子一:统计频次 z<-c(1,2,2,4,2,7,1,1);z1<-table(z);summary(z1); z1#实现z中各数据频次的统计z1 2 4 7 3 3 1 1 names(z1)#居然是有名字的[1] "1" "2" "4" "7"例子二:实现混淆矩阵 t=table(c(1,0,1,1,1,0,0,1),c(0,0,1,

R语言封装函数

R语言封装函数 原帖见豆瓣:https://www.douban.com/note/279077707/ 一个完整的R函数,需要包括函数名称,函数声明,函数参数以及函数体几部分. 1. 函数名称,即要编写的函数名称,这一名称就作为将来调用R函数的依据.2. 函数声明,函数名称 <- function, 即声明该对象的类型为函数.3. 函数参数,这里是输入的数据,函数参数是一个虚拟出来的一个对象.函数参数所等于的数据,就是在函数体内部将要处理的值,或者对应的数据类型. 函数体内部的程序语句进行数据

R语言中函数调试

有时候会用R语言写一下简单的脚本处理函数,加入需要调试的话可以按照下面的步骤进行: fun <- function(x , y){ x + y x - y x * y x / y } debug(fun) 先创建一个简单的函数,然后用debug() 函数对创建的fun()函数进行debug.这时控制台没有任何变化,但是当再次运行创建函数时会进入debug状态: fun(2 + 3) debugging in: fun(2 + 3) debug at #1: { x + y x - y x * y

R语言常用函数

数据结构 一.数据管理vector:向量 numeric:数值型向量 logical:逻辑型向量 character:字符型向量list:列表 data.frame:数据框 c:连接为向量或列表length:求长度subset:求子集 seq,from:to,sequence:等差序列 rep:重复 NA:缺失值 NULL:空对象 sort,order,unique,rev:排序 unlist:展平列表 attr,attributes:对象属性 mode,typeof:对象存储模式与类型 nam

R语言apply()函数用法

在R语言的帮助文档里,apply函数的功能是: Retruns a vector or array or list of values obtained by applying a function to margins of an array or matrix. 就是说apply把一个function作用到array或者matrix的margins(可以理解为数组的每一行或者每一列)中,返回值时vector.array.list. 简单的说,apply函数经常用来计算矩阵中行或列的均值.和值

C语言scanf函数详细解释

函数名: scanf 功 能: 执行格式化输入 用 法: int scanf(char *format[,argument,...]); scanf()函数是通用终端格式化输入函数,它从标准输入设备(键盘) 读取输入的信息.可以读入任何固有类型的数据并自动把数值变换成适当的机内格式. 其调用格式为:      scanf("<格式化字符串>",<地址表>); scanf()函数返回成功赋值的数据项数,出错时则返回EOF. 其控制串由三类字符构成: 1.格式化说明