为了使这个问题更加普遍,我相信它也可以改为:创建一个滚动的时间敏感因子变量。虽然这是一个不常见的要求,但它可以用于许多不同的数据源。
我有一系列non-uniform time data
与>成千上万的用户每天1条记录。我想创建一个新列player_type
,用于跟踪其行为的滚动30天定义。这种行为是由他们玩的游戏定义的;列'games'
是gameA的一个因素,gameB。
因此有三种行为:
'A'
'B'
'Hybrid'
我想使用这个新专栏来查看他们的游戏行为随时间的变化,以及计算每个组中玩家的数量,看看他们如何改变。
每个玩家的时间序列都非常不规律。玩家每天可以玩多种类型的游戏,或者不玩任何游戏数月。每个玩家的时间序列不规则,只有当玩家玩游戏时才创建记录,因此我希望解决方案可能会使用类似的过滤器:
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()
,但是抓取是我的历史时间组件。
感谢您的帮助!我不能完全感谢这个论坛。我会经常回来看看。
答案 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
版本,但我会留给你(假设这个答案是对的)。]
我们只需找到ivals
与dt
重叠的范围,每个 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.y
和foverlaps()
参数。请查看?foverlaps
。