dplyr对变量进行排名观察

时间:2015-02-18 16:43:19

标签: r dplyr

这是一个小例子。在我的大数据集中,我有多年的数据,每组(div)的观察数量并不总是相等。

示例数据:

set.seed(1)
df<-data.frame(
  year = 2014,
  id = sample(LETTERS[1:26], 12),
  div = rep(c("1", "2a", "2b"), each=4),
  pts = c(9,7,9,3,7,5,3,7,2,7,7,1),
  x = c(10,12,11,7,7,5,4,12,4,6,7,2)
)

DF

#   year id div pts  x
#1  2014  G   1   9 10
#2  2014  J   1   7 12
#3  2014  N   1   9 11
#4  2014  U   1   3  7
#5  2014  E  2a   7  7
#6  2014  S  2a   5  5
#7  2014  W  2a   3  4
#8  2014  M  2a   7 12
#9  2014  L  2b   2  4
#10 2014  B  2b   7  6
#11 2014  D  2b   7  7
#12 2014  C  2b   1  2

我想对这些数据进行排名,以便div 1中的个体排名高于div 2a / 2b,而div 1中的个体排名为1,2,3,4,基于最高数量的&#39; pts&#39 ;其次是最高数量的&#39; x&#39;。

div 2a和div 2b中的个人也应根据相同的标准单独排名。这看起来像这样:

df %>% 
  group_by(div) %>%
  arrange(desc(pts), desc(x)) %>%
  mutate(position = row_number(div))


#   year id div pts  x position
#1  2014  N   1   9 11        1
#2  2014  G   1   9 10        2
#3  2014  J   1   7 12        3
#4  2014  U   1   3  7        4
#5  2014  M  2a   7 12        1
#6  2014  E  2a   7  7        2
#7  2014  S  2a   5  5        3
#8  2014  W  2a   3  4        4
#9  2014  D  2b   7  7        1
#10 2014  B  2b   7  6        2
#11 2014  L  2b   2  4        3
#12 2014  C  2b   1  2        4

但是,我想生成另一个等级的最终列/变量。这将使div 1中的所有个体都高于2a / 2b,但2a / 2b相等。即2a / 2b中的1个人现在应该获得5.5,排名2的个人现在应该获得7.5。所有年份在div2a和div2b中总有相同数量的个体。

它应该是这样的:

#   year id div pts  x position final
#1  2014  N   1   9 11        1   1.0  
#2  2014  G   1   9 10        2   2.0
#3  2014  J   1   7 12        3   3.0
#4  2014  U   1   3  7        4   4.0
#5  2014  M  2a   7 12        1   5.5
#6  2014  E  2a   7  7        2   7.5
#7  2014  S  2a   5  5        3   9.5
#8  2014  W  2a   3  4        4  11.5
#9  2014  D  2b   7  7        1   5.5
#10 2014  B  2b   7  6        2   7.5  
#11 2014  L  2b   2  4        3   9.5
#12 2014  C  2b   1  2        4  11.5

我需要理想地找到dplyr解决方案。此外,它确实需要推广到“div1&#39;可能会有所不同,div2a / div2b中的个体数量会有所不同(尽管长度(div2a)==长度(div2b)总是如此)。

2 个答案:

答案 0 :(得分:7)

我就是这样做的:

library(data.table)
dt = as.data.table(df)

dt[order(-pts, -x), rank.init := 1:.N, by = div]

dt[, div.clean := sub('(\\d+).*', '\\1', div)]
setorder(dt, div.clean, rank.init)

dt[, rank.final := mean(.I), by = .(div.clean, rank.init)]
setorder(dt, div, rank.final)
#    year id div pts  x rank.init div.clean rank.final
# 1: 2014  N   1   9 11         1         1        1.0
# 2: 2014  G   1   9 10         2         1        2.0
# 3: 2014  J   1   7 12         3         1        3.0
# 4: 2014  U   1   3  7         4         1        4.0
# 5: 2014  M  2a   7 12         1         2        5.5
# 6: 2014  E  2a   7  7         2         2        7.5
# 7: 2014  S  2a   5  5         3         2        9.5
# 8: 2014  W  2a   3  4         4         2       11.5
# 9: 2014  D  2b   7  7         1         2        5.5
#10: 2014  B  2b   7  6         2         2        7.5
#11: 2014  L  2b   2  4         3         2        9.5
#12: 2014  C  2b   1  2         4         2       11.5

答案 1 :(得分:5)

@ eddi的答案已经非常好了。我只是想使用frank()的开发版本中的data.table, v1.9.5函数来说明相同的函数,它可以计算向量,列表,data.frames或data.tables的排名。

# from @eddi's
setDT(df)[, div.clean := sub('(\\d+).*', '\\1', div)]

df[, position := frank(.SD, -pts, -x, ties.method="first"), by=div]
df[, final := frank(.SD, div.clean, position, ties.method="average")]

这也保留了原始订单,如果它有任何重要性。

我将转换保留给dplyr给您。