在列之间使用“rank”来创建新变量

时间:2013-04-12 02:53:43

标签: r

我有一个我无法弄清楚的问题,我几乎肯定会涉及rank。假设我有一个df宽范围,其中3个变量带有整数值。

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

我想创建三个新变量,其中var1var2var3的值从最大到最小。例如,

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       

我该怎么做呢?谢谢!

3 个答案:

答案 0 :(得分: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

要使用基础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

答案 1 :(得分:3)

我认为以long格式工作更容易(并且内存效率更高,因为apply会强制转换为matrix。这是一种使用reshapedata.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 = '.'))

答案 2 :(得分: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