1

我有一个我想不通的问题,我几乎可以肯定涉及到rank。假设我有一个df具有 3 个具有整数值的变量的宽格式。

id   var1   var2  var3
1    23     8     30
2    1      2     3
3    4      5     1
4    100    80    60

我想创建三个新变量,它们的值从大到小依次为var1var2和。var3例如,

id   var1   var2  var3   var1_rank   var2_rank   var3_rank
1    23     8     30      2          3            1
2    1      2     3       3          2            1 
3    4      5     1       2          1            3
4    100    80    60      1          2            3       

我该怎么做呢?谢谢!

4

3 回答 3

3

获取示例数据:

test <- read.table(text="id   var1   var2  var3
1    23     8     30
2    1      2     3
3    4      5     1
4    100    80    60",header=TRUE)

获取排名部分并适当地重命名(注意-x反转排名,因此它与减小而不是增加大小有关 - 这将data.frame适用于用作输入的任何大小):

ranks <- t(apply(test[,-1], 1, function(x) rank(-x) ))
colnames(ranks) <- paste(colnames(ranks), "_rank", sep="")

加入旧数据框。

data.frame(test, ranks)

结果:

> data.frame(test,ranks)
  id var1 var2 var3 var1_rank var2_rank var3_rank
1  1   23    8   30         2         3         1
2  2    1    2    3         3         2         1
3  3    4    5    1         2         1         3
4  4  100   80   60         1         2         3

要使用 base R 获得@mnel 的答案,您还可以执行以下操作:

testres <- data.frame(test["id"],stack(test[2:4]))
testres$rank <- ave(testres$values,testres$id,FUN=function(x) rank(-x) )

> testres
   id values  ind rank
1   1     23 var1    2
2   2      1 var1    3
3   3      4 var1    2
4   4    100 var1    1
5   1      8 var2    3
6   2      2 var2    2
7   3      5 var2    1
8   4     80 var2    2
9   1     30 var3    1
10  2      3 var3    1
11  3      1 var3    3
12  4     60 var3    3
于 2013-04-12T03:12:37.140 回答
3

我认为以long格式工作更容易(并且内存效率更高,因为apply将强制转换为matrix. 这是一种使用reshape和的方法data.table

library(data.table)
tlong <- reshape(data.table(test), direction ='long', varying = list(2:4), 
                 times = paste0('var',1:3), v.names = 'value')

# calculate the rank within each `id`

tlong[, rank := rank(-value), by = id]
tlong

##     id time value rank
##  1:  1 var1    23    2
##  2:  2 var1     1    3
##  3:  3 var1     4    2
##  4:  4 var1   100    1
##  5:  1 var2     8    3
##  6:  2 var2     2    2
##  7:  3 var2     5    1
##  8:  4 var2    80    2
##  9:  1 var3    30    1
## 10:  2 var3     3    1
## 11:  3 var3     1    3
## 12:  4 var3    60    3

# reshape to wide (if you want)

oldname <- paste0('var1',1:3)

twide <- reshape(tlong, direction = 'wide', timevar = 'time', idvar = 'id')
# reorder from value.var1, rank.var1,... to value.var1, value.var2,....rank.var1, rank.var2

setcolorder(twide, c('id', paste('value', oldname, sep ='.'), paste('rank', oldname, sep = '.'))
于 2013-04-12T03:38:36.233 回答
2

这是一种方法:

data.frame(dat, 4 - t(apply(dat[, -1], 1, rank)))

## > data.frame(dat, 4 - t(apply(dat[, -1], 1, rank)))
##   id var1 var2 var3 var1.1 var2.1 var3.1
## 1  1   23    8   30      2      3      1
## 2  2    1    2    3      3      2      1
## 3  3    4    5    1      2      1      3
## 4  4  100   80   60      1      2      3
于 2013-04-12T03:05:26.170 回答