在R中基于日期(年度)创建排名

3
我们将从以下DataTable开始:
    id       date
 1:  1 2015-12-31
 2:  1 2014-12-31
 3:  1 2013-12-31
 4:  1 2012-12-31
 5:  1 2011-12-31
 6:  2 2015-12-31
 7:  2 2014-12-31
 8:  2 2014-01-25
 9:  2 2013-01-25
10:  2 2012-01-25

library(data.table)
DT <- data.table(c(1, 1, 1, 1, 1, 2, 2, 2, 2, 2),
                 as.IDate(c("2015-12-31", "2014-12-31", "2013-12-31", "2012-12-31", 
                            "2011-12-31", "2015-12-31", "2014-12-31", "2014-01-25",
                            "2013-01-25", "2012-01-25")))
setnames(DT, c("id", "date"))

对于每个唯一的ID,我想创建一个排名。特定ID的最新日期应具有排名0。之后,我应该从该日期减去一年以获得排名-1。如果月份与排名0的日期不同,我们应停止排名。例如,在第8行,对于id = 2,由于月份不是12月,因此我们应该停止排名。

我们将获得以下结果:

    id       date rank_year
 1:  1 2015-12-31         0
 2:  1 2014-12-31        -1
 3:  1 2013-12-31        -2
 4:  1 2012-12-31        -3
 5:  1 2011-12-31        -4
 6:  2 2015-12-31         0
 7:  2 2014-12-31        -1
 8:  2 2014-01-25        NA
 9:  2 2013-01-25        NA
10:  2 2012-01-25        NA

我已经有以下代码(由@Frank和@akrun提供):

code

DT <- DT[order(id, -date)]
DT <- DT[,rank_year := { z = month(date) + year(date)*12
                         as.integer( (z - z[1L])/12) # 12 months
                       }, by = id]

    id       date rank_year
 1:  1 2015-12-31         0
 2:  1 2014-12-31        -1
 3:  1 2013-12-31        -2
 4:  1 2012-12-31        -3
 5:  1 2011-12-31        -4
 6:  2 2015-12-31         0
 7:  2 2014-12-31        -1
 8:  2 2014-01-25        -1
 9:  2 2013-01-25        -2
10:  2 2012-01-25        -3

请注意,当仅修改列或重新排序时,不应将 data.table 赋值给 <-。请查看包文档,其中将解释如何通过引用执行这些操作以及以这种方式执行操作的优点 https://github.com/Rdatatable/data.table/wiki/Getting-started - Frank
起初,我尝试不使用"<-",但我的表格没有更新,当我运行代码后它也不能像我想要的那样工作。 - Alexis
重新排序的正确方法是使用 setorder。"按引用传递"的函数包括 := 和一些名称为 set* 的函数。 - Frank
1
我一定会查看这份文档。虽然我是data.table的新手,但它确实更快。 - Alexis
1个回答

6

好的,我会这样做


DT[, rank_year := replace(
    year(date) - year(date)[1L],  
    month(date) != month(date[1L]), 
    NA_integer_
), by=id]

    id       date rank_year
 1:  1 2015-12-31         0
 2:  1 2014-12-31        -1
 3:  1 2013-12-31        -2
 4:  1 2012-12-31        -3
 5:  1 2011-12-31        -4
 6:  2 2015-12-31         0
 7:  2 2014-12-31        -1
 8:  2 2014-01-25        NA
 9:  2 2013-01-25        NA
10:  2 2012-01-25        NA

详见?replace,了解其工作原理。


扩展旧答案的一种方式是

DT[, r := {
   z = month(date) + year(date)*12
   res = (z - z[1L])/12
   as.integer( replace(res, res %% 1 != 0, NA) ) 
}, by=id]

1
并加上必需的ifelse: DT[, rank := ifelse(month(date) != month(date[1L]), NA_integer_, year(date) - year(date)[1L]), by = id] - Jaap

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接