【发布时间】:2017-08-15 11:52:34
【问题描述】:
我正在尝试计算每个 ID 连续 # 天不活动 (consecDaysInactive)。
我已经创建了一个指标变量inactive,它在 id 处于非活动状态时为 1,在活动时为 0。我还有一个 id 变量和一个 date 变量。我的分析数据集将有数十万行,因此效率很重要。
我试图创建的逻辑如下:
- 每个 id,如果用户处于活动状态,
consecDaysInactive= 0 - 每个 ID,如果用户处于非活动状态,并且在前一天处于活动状态,
consecDaysInactive= 1 - 每个 id,如果用户在前一天不活跃,
consecDaysInactive= 1 + # 之前连续不活跃的天数 -
consecDaysInactive应该重置为 0 以获得新的 id 值。
我已经能够创建一个累积总和,但无法在 >= 非活动行 ==0 之后将其重置为 0。
我在下面说明了我想要的结果 (consecDaysInactive),以及我能够以编程方式实现的结果 (bad_consecDaysInactive)。
library(dplyr)
d <- data.frame(id = c(1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2), date=as.Date(c('2017-01-01','2017-01-02','2017-01-03','2017-01-04','2017-01-05','2017-01-06','2017-01-07','2017-01-08','2017-01-01','2017-01-02','2017-01-03','2017-01-04','2017-01-05','2017-01-06','2017-01-07','2017-01-08')), inactive=c(0,0,0,1,1,1,0,1,0,1,1,1,1,0,0,1), consecDaysInactive=c(0,0,0,1,2,3,0,1,0,1,2,3,4,0,0,1))
d <- d %>%
group_by(id) %>%
arrange(id, date) %>%
do( data.frame(., bad_consecDaysInactive = cumsum(ifelse(.$inactive==1, 1,0))
)
)
d
其中consecDaysInactive 在连续每一天不活动时迭代 +1,但在用户活跃的每个日期重置为 0,并且对于新的 id 值重置为 0。如下输出所示,我无法将 bad_consecDaysInactive 重置为 0 - 例如行
id date inactive consecDaysInactive bad_consecDaysInactive
<dbl> <date> <dbl> <dbl> <dbl>
1 1 2017-01-01 0 0 0
2 1 2017-01-02 0 0 0
3 1 2017-01-03 0 0 0
4 1 2017-01-04 1 1 1
5 1 2017-01-05 1 2 2
6 1 2017-01-06 1 3 3
7 1 2017-01-07 0 0 3
8 1 2017-01-08 1 1 4
9 2 2017-01-01 0 0 0
10 2 2017-01-02 1 1 1
11 2 2017-01-03 1 2 2
12 2 2017-01-04 1 3 3
13 2 2017-01-05 1 4 4
14 2 2017-01-06 0 0 4
15 2 2017-01-07 0 0 4
16 2 2017-01-08 1 1 5
我还考虑(并尝试过)在 group_by() 和 do() 中增加一个变量,但由于 do() 不是迭代的,我无法让我的计数器超过 2:
d2 <- d %>%
group_by(id) %>%
do( data.frame(., bad_consecDaysInactive2 = ifelse(.$inactive == 0, 0, ifelse(.$inactive==1,.$inactive+lag(.$inactive), .$inactive))))
d2
产生了,如上所述:
id date inactive consecDaysInactive bad_consecDaysInactive bad_consecDaysInactive2
<dbl> <date> <dbl> <dbl> <dbl> <dbl>
1 1 2017-01-01 0 0 0 0
2 1 2017-01-02 0 0 0 0
3 1 2017-01-03 0 0 0 0
4 1 2017-01-04 1 1 1 1
5 1 2017-01-05 1 2 2 2
6 1 2017-01-06 1 3 3 2
7 1 2017-01-07 0 0 3 0
8 1 2017-01-08 1 1 4 1
9 2 2017-01-01 0 0 0 0
10 2 2017-01-02 1 1 1 1
11 2 2017-01-03 1 2 2 2
12 2 2017-01-04 1 3 3 2
13 2 2017-01-05 1 4 4 2
14 2 2017-01-06 0 0 4 0
15 2 2017-01-07 0 0 4 0
16 2 2017-01-08 1 1 5 1
如您所见,我的迭代器 bad_consecDaysInactive2 重置为 0,但不会超过 2!如果有 data.table 解决方案,我也很乐意听到。
【问题讨论】:
-
这样的?
library(data.table); setDT(d)[, consecDaysInactive2:=cumsum(inactive), by=.(id, cumsum(!inactive))] -
library(data.table); setDT(d)[, v := if (inactive[1]) seq.int(.N) else 0L, by=rleid(inactive)] -
感谢 chinsoon12 和 Frank -- 这两个都运行良好。我将以此为契机探索 data.table 库。 @Frank,关于您将这篇文章标记为重复,我认为这与您标记的文章不同,其中 OP 要求一种在 dplyr 中使用 data.table 函数的方法,目的是制作一个随不同 ID 值递增的常量。我尝试的操作不同,我没有在 dplyr 中要求 data.table 方法; dplyr 是我尝试过的方法,但无法实现我的目标,因此提出了问题。再次感谢您的帮助。
-
@rsty Np。是的,你的问题原来是一个由两部分组成的问题(如我所见):第一个由链接解决(如何在 1s 上进行分组);第二个是相当微不足道的(算在这些组中)。所以在 dplyr
group_by(g = rleid(something)) %>% mutate(r = if (x[1]==1) row_number() else 0L)或类似的。如果其他人想取消重复,那很好,但我想我会留下它。
标签: r data.table dplyr data-manipulation