如何在R中的组内排名?

Posted

技术标签:

【中文标题】如何在R中的组内排名?【英文标题】:How to rank within groups in R? 【发布时间】:2015-10-29 19:16:40 【问题描述】:

好的,看看这个数据框...

  customer_name order_dates order_values
1          John  2010-11-01           15
2           Bob  2008-03-25           12
3          Alex  2009-11-15            5
4          John  2012-08-06           15
5          John  2015-05-07           20

假设我想添加一个订单变量,该变量按名称、最大订单日期、使用决胜局的最后订单日期对最高订单价值进行排名。所以,最终数据应该是这样的:

  customer_name order_dates order_values ranked_order_values_by_max_value_date
1          John  2010-11-01           15                               3
2           Bob  2008-03-25           12                               1
3          Alex  2009-11-15            5                               1
4          John  2012-08-06           15                               2
5          John  2015-05-07           20                               1

每个人的单笔订单都得1分,之后的所有订单都根据该值进行排名,决胜局是最后一个订单日期获得优先权。 在此示例中,John 的 2012 年 8 月 6 日订单排名第 2,因为它是在 2010 年 11 月 1 日之后放置的。 2015 年 5 月 7 日的订单是 1,因为它是最大的。因此,即使该订单是 20 年前下的,它也应该是排名第一的,因为它是 John 的最高订单价值。

有谁知道我如何在 R 中做到这一点?我可以在数据框中的一组指定变量中进行排名吗?

感谢您的帮助!

【问题讨论】:

@akrun 价值的决胜局怎么样? 这是制作数据框的代码,以防万一:customer_name @SenorO OP 的示例测试起来应该更复杂一些。此外,来自dplyrdense_rank 是一种决胜局 @akun:价值的决胜局将是订单日期。所以约翰有两个 15 美元的订单,但最先下的那个排名更高。 可能是setDT(df1)[, rnk := order(desc(order_values), desc(order_dates)), customer_name] 使用data.table 【参考方案1】:

与@t-himmel 的回答类似,您可以使用 data.table 获取排名。

dt[ , rnk := order(order(order_values, decreasing = TRUE)), customer_name ]

【讨论】:

【参考方案2】:
df %>% 
  group_by(customer_name) %>% 
  arrange(customer_name,desc(order_values)) %>% 
  mutate(rank2=rank(order_values))

【讨论】:

【参考方案3】:

您可以使用dplyr 轻松完成此操作

library(dplyr)
df %>%
    group_by(customer_name) %>%
    mutate(my_ranks = order(order(order_values, order_dates, decreasing=TRUE)))

Source: local data frame [5 x 4]
Groups: customer_name

  customer_name order_dates order_values my_ranks
1          John  2010-11-01           15        3
2           Bob  2008-03-25           12        1
3          Alex  2009-11-15            5        1
4          John  2012-08-06           15        2
5          John  2015-05-07           20        1

【讨论】:

这是不正确的。 correct answer 由 @T.Himmel 提供。【参考方案4】:

评分最高的答案(由 cdeterman 提供)实际上是不正确的。 order 函数提供排名第 1、第 2、第 3 等值的位置,而不是当前顺序中值的排名。

让我们举一个简单的例子,我们想要排名,从最大的开始,按客户名称分组。我已经包含了一个手动排名,所以我们可以检查值

    > df
       customer_name order_values manual_rank
    1           John            2           5
    2           John            5           2
    3           John            9           1
    4           John            1           6
    5           John            4           3
    6           John            3           4
    7           Lucy            4           4
    8           Lucy            9           1
    9           Lucy            6           3
    10          Lucy            2           6
    11          Lucy            8           2
    12          Lucy            3           5

如果我运行 cdeterman 建议的代码,我会得到以下不正确的排名:

    > df %>%
    +   group_by(customer_name) %>%
    +   mutate(my_ranks = order(order_values, decreasing=TRUE))
    Source: local data frame [12 x 4]
    Groups: customer_name [2]

       customer_name order_values manual_rank my_ranks
              <fctr>        <dbl>       <dbl>    <int>
    1           John            2           5        3
    2           John            5           2        2
    3           John            9           1        5
    4           John            1           6        6
    5           John            4           3        1
    6           John            3           4        4
    7           Lucy            4           4        2
    8           Lucy            9           1        5
    9           Lucy            6           3        3
    10          Lucy            2           6        1
    11          Lucy            8           2        6
    12          Lucy            3           5        4

Order 用于将数据帧重新排序为降序或升序。我们真正想要的是运行两次 order 函数,第二次 order 函数为我们提供了我们想要的实际排名。

    > df %>%
    +   group_by(customer_name) %>%
    +   mutate(good_ranks = order(order(order_values, decreasing=TRUE)))
    Source: local data frame [12 x 4]
    Groups: customer_name [2]

       customer_name order_values manual_rank good_ranks
              <fctr>        <dbl>       <dbl>      <int>
    1           John            2           5          5
    2           John            5           2          2
    3           John            9           1          1
    4           John            1           6          6
    5           John            4           3          3
    6           John            3           4          4
    7           Lucy            4           4          4
    8           Lucy            9           1          1
    9           Lucy            6           3          3
    10          Lucy            2           6          6
    11          Lucy            8           2          2
    12          Lucy            3           5          5

【讨论】:

这对我很有用。我必须先运行detach("package:plyr", unload=TRUE),这样它才能正确分组。感谢您的解决方案!【参考方案5】:

在基础R 中,你可以用稍微笨重的东西来做到这一点

transform(df,rank=ave(1:nrow(df),customer_name,
  FUN=function(x) order(order_values[x],order_dates[x],decreasing=TRUE)))
customer_name order_dates order_values 排名 1 约翰 2010-11-01 15 3 2 鲍勃 2008-03-25 12 1 3 亚历克斯 2009-11-15 5 1 4 约翰 2012-08-06 15 2 5 约翰 2015-05-07 20 1

其中order 提供了每个组的主要值和决胜局值。

【讨论】:

【参考方案6】:

这可以通过averank 来实现。 ave 将适当的组传递给rank。由于请求的顺序,rank 的结果是相反的:

with(x, ave(as.numeric(order_dates), customer_name, FUN=function(x) rev(rank(x))))
## [1] 3 1 1 2 1

【讨论】:

以上是关于如何在R中的组内排名?的主要内容,如果未能解决你的问题,请参考以下文章

如何计算 R 中多列的组内百分比变化?

如何按列分组,然后在python中的组内重新排序列

如何在 Pandas 的组内使用 cumsum?

OpenCL 内核中的组内同步,在本地内存上使用自旋锁

如何在 SQL Server 中按日期列排序的组中对列进行排名

如何从 JSPlumb 中的组中删除项目?