根据滚动日期中存在的条件创建新列

时间:2014-11-29 20:44:41

标签: r conditional data.table dplyr date-range

为了使这个问题更加普遍,我相信它也可以改为:创建一个滚动的时间敏感因子变量。虽然这是一个不常见的要求,但它可以用于许多不同的数据源。

我有一系列non-uniform time data与>成千上万的用户每天1条记录。我想创建一个新列player_type,用于跟踪其行为的滚动30天定义。这种行为是由他们玩的游戏定义的;列'games'是gameA的一个因素,gameB。

因此有三种行为:

  1. 独家玩GameA - 'A'
  2. 独家玩GameB - 'B'
  3. 同时播放两款游戏 - 'Hybrid'
  4. 我想使用这个新专栏来查看他们的游戏行为随时间的变化,以及计算每个组中玩家的数量,看看他们如何改变。

    每个玩家的时间序列都非常不规律。玩家每天可以玩多种类型的游戏,或者不玩任何游戏数月。每个玩家的时间序列不规则,只有当玩家玩游戏时才创建记录,因此我希望解决方案可能会使用类似的过滤器:

    interval(current_date, current_date - new_period(days=30)(使用lubridate)。

    这是一个示例数据集。请记住,它是简化的并测试滚动的1天更改,因此检查记录之前的简单方法实际上不起作用。 如果您能够制作更好的数据集,请提供建议,我将编辑此帖子。

    p <- c( 1,   1,   1,   2,   2,   2,   6,   6,   6)
    
    g <- c('A', 'B', 'B', 'A', 'B', 'A', 'A', 'B', 'B')
    
    d <- seq(as.Date('2014-10-01'), as.Date('2014-10-9'), by=1)
    
    df <- data.frame(player_id = p, date = d, games = g)
    

    作为输出我需要:

     player_id       date games   type
    1         1 2014-10-01     A      A (OR NA)
    2         1 2014-10-02     B Hybrid
    3         1 2014-10-03     B      B
    4         2 2014-10-04     A      A (OR NA)
    5         2 2014-10-05     B Hybrid
    6         2 2014-10-06     A Hybrid
    7         6 2014-10-07     A      A (OR NA)
    8         6 2014-10-08     B Hybrid
    9         6 2014-10-09     B      B
    

    解决方案应该类似于apply列,并应用一个功能,可以检查30天的时间,并使用ifelse()语句查看他们玩过的游戏。

    这是一个非常相似的帖子 - 应该有助于解决这个问题。 How do I do a conditional sum which only looks between certain date criteria

    我还使用dplyr探索了rowwise()和条件mutates(),但是抓取是我的历史时间组件。

    感谢您的帮助!我不能完全感谢这个论坛。我会经常回来看看。

1 个答案:

答案 0 :(得分:4)

假设我理解正确,这是使用data.table函数的foverlaps()方式。

创建dt并设置密钥,如下所示:

dt <- data.table(player_id = p, games = g, date = d, end_date = d)
setkey(dt, player_id, date, end_date)

hybrid_index <- function(dt, roll_days) {
    ivals = copy(dt)[, date := date-roll_days]
    olaps = foverlaps(ivals, dt, type="any", which=TRUE)
    olaps[, val := dt$games[xid] != dt$games[yid]]
    olaps[, any(val), by=xid][(V1), xid]
}

我们创建一个虚拟data.table ivals(用于间隔),对于每一行,我们指定 start end 日期。请注意,通过将 end_date 指定为dt$end_date,我们肯定会有一个匹配(这是故意的) - 这将为您提供您要求的非NA版本。

[这里有一些细微的变化,你可以得到NA版本,但我会留给你(假设这个答案是对的)。]

我们只需找到ivalsdt重叠的范围,每个 player_id。我们得到匹配的指数。从那里它是直截了当的。如果玩家的游戏是非同质的,那么我们会从dt返回相应的hybrid_index索引。我们用“混合”代替那些指数。

# roll days = 1L
dt[, type := games][hybrid_index(dt, 1L), type := "hybrid"]
#    player_id games       date   end_date   type
# 1:         1     A 2014-10-01 2014-10-01      A
# 2:         1     B 2014-10-02 2014-10-02 hybrid
# 3:         1     B 2014-10-03 2014-10-03      B
# 4:         2     A 2014-10-04 2014-10-04      A
# 5:         2     B 2014-10-05 2014-10-05 hybrid
# 6:         2     A 2014-10-06 2014-10-06 hybrid
# 7:         6     A 2014-10-07 2014-10-07      A
# 8:         6     B 2014-10-08 2014-10-08 hybrid
# 9:         6     B 2014-10-09 2014-10-09      B

# roll days = 2L
dt[, type := games][hybrid_index(dt, 2L), type := "hybrid"]
#    player_id games       date   end_date   type
# 1:         1     A 2014-10-01 2014-10-01      A
# 2:         1     B 2014-10-02 2014-10-02 hybrid
# 3:         1     B 2014-10-03 2014-10-03 hybrid
# 4:         2     A 2014-10-04 2014-10-04      A
# 5:         2     B 2014-10-05 2014-10-05 hybrid
# 6:         2     A 2014-10-06 2014-10-06 hybrid
# 7:         6     A 2014-10-07 2014-10-07      A
# 8:         6     B 2014-10-08 2014-10-08 hybrid
# 9:         6     B 2014-10-09 2014-10-09 hybrid

为了清楚地说明这个想法,我创建了一个函数并在函数中复制了dt。但您可以避免这种情况,并将ivals中的日期直接添加到dt,并使用by.x中的by.yfoverlaps()参数。请查看?foverlaps