【问题标题】:Look back column based on date and rank in R在 R 中基于日期和排名回顾列
【发布时间】:2019-12-23 14:45:55
【问题描述】:

我正在尝试根据排名创建一个新列,每个月都会更改。以下是示例输入数据。

df <- data.frame(id=c(1,1,1,1,1,1,1,2,2,2,3,3,4),
             rank=c(3,1,1,1,1,1,2,2,3,1,1,2,3),
             dates=c('2019-06-15','2019-07-15','2019-08-15','2019-09-15','2019-10-15','2019-11-15','2019-12-15',
                     '2019-10-15','2019-11-15','2019-12-15',
                     '2019-11-15','2019-12-15','2019-12-15'))

这是预期的输出,我想要最新日期的行。

 id   rank   dates      new_col
  1    2    2019-12-15       0
  2    1    2019-12-15       0
  3    2    2019-12-15       1
  4    3    2019-12-15       0

new_col 表示rank 从 6 个月的回溯中有所增加? 例如,如果一行从 12 月开始为 2,但它们在 10 月行是 1,则 在 12 月的行中,我们可以输入 new_col= 1。

我们必须将回顾日期限制为 6 个月

【问题讨论】:

  • 从 6 个月的回溯中增加是什么意思?如果它低于上个月但高于 2 个月前,反之亦然怎么办?或者您是说正好回顾六个月,并且在那一天总是只有一行可以比较?
  • 6 个月回顾意味着,仅检查日期中的 6 个月,如果超过 6 个月则忽略日期。
  • 如果低于上个月,但高于 2 个月前。例如 1,3,2 (rank) 那么它应该是 0
  • 而且,6 个月回顾意味着,检查排名仅 6 个月。例如 1,1,1,1,1,2(等级)然后 new_col 应该是 1
  • 仅供参考,您的数据有点帮助(对于结构),但在这里真的没用。一组好的示例数据将包括不匹配您的窗口的条件。当您的窗口为 6 个月时,将所有内容都跨越 3 个月不会帮助您测试任何代码的有效性。

标签: r dplyr data.table plyr


【解决方案1】:

这是在data.table 中使用非等连接的选项:

#convert into IDate and get dates from 6m ago
DT[, dates := as.IDate(dates, format="%Y-%m-%d")][, c("start", "end") := 
    .(as.IDate(sapply(dates, function(x) seq(x, by="-6 months", length.out=2L)[2L])), dates)]

#extract latest rows for each id
latest <- DT[DT[, .I[.N], id]$V1]

#non-equi join and for each latest date of each id, check if the current rank is the highest over last 6m
DT[latest, on=.(id, dates>=start, dates<end), 
    by=.EACHI, {
        a <- +all(i.rank > x.rank)
        .(new_col=replace(a, is.na(a), 0L))
        }]

输出:

   id      dates      dates new_col
1:  1 2019-06-15 2019-12-15       0
2:  2 2019-06-15 2019-12-15       0
3:  3 2019-06-15 2019-12-15       1
4:  4 2019-06-15 2019-12-15       0

数据:

library(data.table)
DT <- data.table(id=c(1,1,1,1,1,1,1,2,2,2,3,3,4),
    rank=c(3,1,1,1,1,1,2,2,3,1,1,2,3),
    dates=c('2019-06-15','2019-07-15','2019-08-15','2019-09-15','2019-10-15','2019-11-15','2019-12-15',
        '2019-10-15','2019-11-15','2019-12-15',
        '2019-11-15','2019-12-15','2019-12-15'))

【讨论】:

    【解决方案2】:

    假设您愿意使用 data.table。首先在时间变量之后对数据进行排序。使用 shift 获取最后两个可用值(在您的情况下为 6),并取最大值。需要确保对于每个 ID,您都有完整的时间序列,否则,我认为它将采用最后可用的值。通过比较rank和rank_max可以判断rank是否发生了变化。

    library(data.table)
    df <- data.table(id=c(1,1,1,2,2,2,3,3,3) %>% as.character,
                 rank=c(1,3,2,2,3,1,1,2,3),
                 time=rep(1:3,3))
    setorder(df, time)
    df[, rank_max := do.call(pmax, shift(rank, 1:2, type = "lag")), by=id]
    
       id rank time rank_max
    1:  1    1    1       NA
    2:  2    2    1       NA
    3:  3    1    1       NA
    4:  1    3    2       NA
    5:  2    3    2       NA
    6:  3    2    2       NA
    7:  1    2    3        3
    8:  2    1    3        3
    9:  3    3    3        2
    

    【讨论】:

    • 你可以在do.call语句中改变pmax来选择是选择最大值还是最小值。
    • 现在我阅读了所有新的 cmets,我不确定这是否有用。特别是这有点不清楚:“如果它低于上个月,但高于 2 个月前。例如 1,3,2(排名),那么它应该是 0”。如果过去的变化相互抵消,那么使用平均值可能会有用:df[, mean := mean( shift(rank, 1:2, type = "lag") %>% unlist), by=id]
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-22
    • 1970-01-01
    • 1970-01-01
    • 2019-08-17
    相关资源
    最近更新 更多