根据几个变量进行排名

问题描述 投票:5回答:2

这是一个小例子。 在我的更大的数据集中,我有多个年份的数据,而且每个组的观测数(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

我想对这些数据进行排序,使第1组的个人排名高于第2a2b组,在第1组中,个人根据最高的 "pts "数和最高的 "x "数进行1,2,3,4的排序。

在2a组和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

然而,我想产生一个最后的columnvariable,也就是另一个等级。 即在2a2b中排名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'中的个体数量可能会变化,而div2adiv2b中的个体数量也会变化的年份(尽管length(div2a)==length(div2b)总是)。

r dplyr ranking rank
2个回答
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

6
投票

@eddi的回答已经很好了。我只是想用 frank() 的开发版中的功能。data.table, v1.9.5,它可以计算向量、列表、data.frame或data.table的等级。

# 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 给你。

© www.soinside.com 2019 - 2024. All rights reserved.