按组和起始年份计算多个连续事件

时间:2017-08-22 14:23:14

标签: r dplyr data.table

我是一个几年的潜伏者,但我终于找到了一些我只能用旧帖子弄清楚的东西。我有一个数据框,包含数百个国家/地区,年份和带有二进制指示符的事件变量:

library('dplyr')
library('data.table')

country<-c("albania","albania","albania","albania","albania","albania","albania","albania","thailand","thailand","thailand","thailand","thailand","thailand","thailand","thailand")
year<-c(1960,1961,1962,1963,1964,1965,1966,1967,1972,1973,1974,1975,1976,1977,1978,1979)
event<-c(0,1,1,0,0,1,1,1,1,1,0,0,1,0,0,0)
input<-data.frame(country=country, year=year, event=event)

input    

    country year event
1   albania 1960     0
2   albania 1961     1
3   albania 1962     1
4   albania 1963     0
5   albania 1964     0
6   albania 1965     1
7   albania 1966     1
8   albania 1967     1
9  thailand 1972     1
10 thailand 1973     1
11 thailand 1974     0
12 thailand 1975     0
13 thailand 1976     1
14 thailand 1977     0
15 thailand 1978     0
16 thailand 1979     0

我想创建一个新的数据框,显示每个国家/地区的多个连续事件及其持续时间和起始年份。例如:

output

   country start duration
1  albania 1961        2
2  albania 1965        3
3 thailand 1972        2
4 thailand 1976        1

我已经阅读过,我认为是大多数关于使用dplyrdata.table rle()rleid()按小组计算连续事件的相关帖子,但我无法将它们带到我想要的地方。

关注this example,我无法按国家/地区获得具有多个事件长度的新数据框;不只是最大,最小等等,而且忽略了我需要抓住事件的起始年份。试图建立这个代码来达到我想要的状态给我留下了很多错误。 dplyr示例的“基本代码”似乎是一些起点:

output <- input %>%
group_by(country) %>%
do({
tmp <- with(rle(.$event == 1), lengths[values])
data.frame(country= .$country, Max = if (length(tmp) == 0) 0 else max(tmp))
 }) %>%
 slice(1L)

这显然拉近了最大值,我努力改变它以拉动每一个事件。

Following the data.table / rleid模型创建一个新的变异变量,计算连续“事件”的持续时间,但我无法提取一个国家内多个事件的“结束”年份。也许一些滞后差异函数使用变异变量然后提取所有具有负值的行?一旦标记了结束事件的行,开始年份将只是当前年份 - 长度。这种方法的基本代码是:

sum0 <- function(x) { x[x == 1] = sequence(with(rle(x), lengths[values == 1])); x }
setDT(input)[, duration := sum0(event), by = country]

input

     country year event duration
 1:  albania 1960     0        0
 2:  albania 1961     1        1
 3:  albania 1962     1        2 
 4:  albania 1963     0        0
 5:  albania 1964     0        0
 6:  albania 1965     1        1
 7:  albania 1966     1        2
 8:  albania 1967     1        3
 9: thailand 1972     1        1
10: thailand 1973     1        2
11: thailand 1974     0        0
12: thailand 1975     0        0
13: thailand 1976     1        1
14: thailand 1977     0        0
15: thailand 1978     0        0
16: thailand 1979     0        0

我看了另外7-10个帖子,但没有链接,因为它们在性质上与我引用的两个相似。我想提前感谢任何有任何建议的人。我希望我遵循所有协议提出问题;我试着小心并遵守规则。感谢您所做的所有伟大工作!你让我通过了5到6年的学习R和JAGS。

2 个答案:

答案 0 :(得分:3)

这就是我要做的事情(将dplyr从中删除):

setDT(input)

input[, 
  if (first(event) == 1) .(year = first(year), N = .N)
, by=.(country, g = rleid(country, event))][, !"g"]

    country year N
1:  albania 1961 2
2:  albania 1965 3
3: thailand 1972 2
4: thailand 1976 1

效率不高,但希望能够轻松实现。

答案 1 :(得分:2)

这就是你想要的:

library(data.table)

setDT(input)
input[, .(event = event[1], start = year[1], duration = .N),
      by = .(country, rleidv(event))][event == 1][
          , c('event', 'rleidv') := NULL][]

#     country start duration
# 1:  albania  1961        2
# 2:  albania  1965        3
# 3: thailand  1972        2
# 4: thailand  1976        1

正如Frank在评论中指出的那样,此解决方案在计算中由data.table优化,这使其更有效。 <{1}}表达式中的if(cond) ...将不会被优化。