【问题标题】:Add a "rank" column to a data frame向数据框中添加“排名”列
【发布时间】:2013-03-02 04:40:04
【问题描述】:

我有一个数据框,其中包含不同年份、不同项目的计数:

df <- data.frame(item = rep(c('a','b','c'), 3),
                 year = rep(c('2010','2011','2012'), each=3),
                 count = c(1,4,6,3,8,3,5,7,9))

我想添加一个“year.rank”列,它给出了一个项目在给定年份内的排名,其中较高的计数会导致较高的“排名”。有了上面的内容,它看起来像:

  item year count year.rank
1    a 2010     1         3
2    b 2010     4         2
3    c 2010     6         1
4    a 2011     3         2
5    b 2011     8         1
6    c 2011     3         3
7    a 2012     5         3
8    b 2012     7         2
9    c 2012     9         1

我知道我可以使用 order(df$count) 对整个数据框执行此操作,但我不确定我将如何按年执行此操作。

【问题讨论】:

    标签: r


    【解决方案1】:

    有一个rank 函数可以帮助您:

    transform(df, 
              year.rank = ave(count, year, 
                              FUN = function(x) rank(-x, ties.method = "first")))
      item year count year.rank
    1    a 2010     1         3
    2    b 2010     4         2
    3    c 2010     6         1
    4    a 2011     3         2
    5    b 2011     8         1
    6    c 2011     3         3
    7    a 2012     5         3
    8    b 2012     7         2
    9    c 2012     9         1
    

    【讨论】:

    • +1 因为我尝试了排名但没有成功!!我被排名功能卡住了!
    • @agstudy,原来我发帖太快了,没有成功。关键是-x(因为排名通常从低到高)和ties.method(因为排名通常默认为平均)。
    • 注意如果count 变量恰好是POSIXlt 变量而不是数字变量,您可以将其包装在as.numeric()
    【解决方案2】:

    data.table练习版:

    library(data.table)
    DT <- as.data.table(df)
    DT[,yrrank:=rank(-count,ties.method="first"),by=year]
    
       item year count yrrank
    1:    a 2010     1      3
    2:    b 2010     4      2
    3:    c 2010     6      1
    4:    a 2011     3      2
    5:    b 2011     8      1
    6:    c 2011     3      3
    7:    a 2012     5      3
    8:    b 2012     7      2
    9:    c 2012     9      1
    

    【讨论】:

    • 这很棒。谢谢你。是否有任何好的文档可以使用 data.table 的副作用部分?我已经开始使用它,但还没有达到我想要的熟练程度。
    • @Wilduck - 这与其说是副作用,不如说是主要影响!我对data.table 也很陌生,但我刚刚浏览了cran.r-project.org/web/packages/data.table/vignettes/… 的常见问题解答,Google 是你的朋友!
    • 副作用是指它对 data.table 执行操作,而不是返回单独的结果。 en.wikipedia.org/wiki/Side_effect_(computer_science) 无论如何,我感谢您的回复。
    • data.table 1.9.6 函数现在称为 frank 或 frankv,非常有帮助
    【解决方案3】:

    使用order函数,

    transform(dat, x= ave(count,year,FUN=function(x) order(x,decreasing=T)))
      item year count x
    1    a 2010     1 3
    2    b 2010     4 2
    3    c 2010     6 1
    4    a 2011     3 2
    5    b 2011     8 1
    6    c 2011     3 3
    7    a 2012     5 3
    8    b 2012     7 2
    9    c 2012     9 1
    

    编辑

    您也可以在这里使用plyr

    ddply(dat,.(year),transform,x =  order(count,decreasing=T))
    

    【讨论】:

    • 我喜欢更简洁的解决方案,我发现使用ave() 比使用ave(rank()) 更好,但在这种情况下您无法控制ties.method,对吧?
    【解决方案4】:

    使用 dplyr 你可以这样做:

    library(dplyr) # 0.4.1
    df %>% 
      group_by(year) %>% 
      mutate(yrrank = row_number(-count))
    
    #Source: local data frame [9 x 4]
    #Groups: year
    #
    #  item year count yrrank
    #1    a 2010     1      3
    #2    b 2010     4      2
    #3    c 2010     6      1
    #4    a 2011     3      2
    #5    b 2011     8      1
    #6    c 2011     3      3
    #7    a 2012     5      3
    #8    b 2012     7      2
    #9    c 2012     9      1
    

    同理:

    df %>% 
      group_by(year) %>% 
      mutate(yrrank = rank(-count, ties.method = "first"))
    

    请注意,结果数据仍按“年份”分组。如果您想删除分组,您可以简单地使用%&gt;% ungroup() 扩展管道。

    【讨论】:

      【解决方案5】:

      在使用其他人给出的答案时,我发现以下执行速度比 transformdyplr 变体更快:

      df$year.rank <- ave(count, year, FUN = function(x) rank(-x, ties.method = "first"))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-09
        • 1970-01-01
        • 2021-01-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多