【问题标题】:Create sequential counter that restarts on a condition within panel data groups [duplicate]创建在面板数据组内的条件下重新启动的顺序计数器[重复]
【发布时间】:2015-11-21 17:16:59
【问题描述】:

我有一个面板数据集,我想为其创建一个计数器,该计数器随着面板中的每一步而增加,但在发生某些情况时会重新启动。就我而言,我使用的是国家/地区年份数据,并希望计算事件之间的年数。这是一个玩具数据集,其中包含我的真实数据集的主要特征:

df <- data.frame(country = rep(c("A","B"), each=5), year=rep(2000:2004, times=2), event=c(0,0,1,0,0,1,0,0,1,0), stringsAsFactors=FALSE)

我要做的是在每个国家/地区的一系列观察中创建一个键入df$event 的计数器。当我们开始观察每个国家时,时钟从 1 开始;它随着每一年的流逝而增加1;并且每当df$event==1 时,它都会在 1 处重新启动。期望的输出是这样的:

   country year event clock
1        A 2000     0     1
2        A 2001     0     2
3        A 2002     1     1
4        A 2003     0     2
5        A 2004     0     3
6        B 2000     1     1
7        B 2001     0     2
8        B 2002     0     3
9        B 2003     1     1
10       B 2004     0     2

我曾尝试使用splitstackshape 中的getanID 以及ififelse 的一些变体,但到目前为止未能获得所需的结果。

我已经在需要执行此操作的脚本中使用dplyr,因此我更喜欢使用它或基于 R 的解决方案,但我会感谢任何有效的解决方案。我的数据集并不庞大,因此速度并不重要,但效率始终是加分项。

【问题讨论】:

  • 这个问题与另一个问题不太一样。另一个要求为每个组中的所有行制作一个简单的计数器。这个问题询问关于组内的步数计数,直到某些条件发生,然后在条件确实发生时重新启动计数器,并重复执行此操作。这对事件历史数据特别有用,但在其他情况下也很有用,而且更简单的先前版本不会这样做。

标签: r time-series dplyr


【解决方案1】:

dplyr 会是:

df %>% 
  group_by(country, idx = cumsum(event == 1L)) %>% 
  mutate(counter = row_number()) %>% 
  ungroup %>% 
  select(-idx)

#Source: local data frame [10 x 4]
#
#   country year event counter
#1        A 2000     0       1
#2        A 2001     0       2
#3        A 2002     1       1
#4        A 2003     0       2
#5        A 2004     0       3
#6        B 2000     1       1
#7        B 2001     0       2
#8        B 2002     0       3
#9        B 2003     1       1
#10       B 2004     0       2

或者使用data.table:

library(data.table)
setDT(df)[, counter := seq_len(.N), by = list(country, cumsum(event == 1L))]

编辑:group_by(country, idx = cumsum(event == 1L)) 用于按国家和新的分组索引“idx”分组。 event == 1L 部分创建一个逻辑索引,告诉我们“事件”列是否为整数 1 (TRUE/FALSE)。然后,cumsum(...) 的总和从前 2 行的 0 开始,接下来的 3 行从 1 开始,接下来的 3 行从 2 开始,以此类推。我们使用这个新列(+国家)根据需要对数据进行分组。如果您删除了 dplyr 代码中的最后一个管道部分,您可以查看它。

【讨论】:

  • 我怀疑country也应该是一个分组变量。
  • @Khashaa,正确,我忽略了这一点
【解决方案2】:
library(splitstackshape)
df$counter <- getanID(cbind(df$country, cumsum(df$event)))[,.id]

我们利用了您的事件列中已有零和一这一事实。这使得索引更容易。我将国家列与cumsum(df$event) 结合起来。当该命令自己运行时,您可以看到它的效果:

cumsum(df$event)
 [1] 0 0 1 1 1 2 2 2 3 3

它只会随着1 值的增加而增加。结合国家,我们可以看到按国家分组的增长。

从那里,我们可以创建一个 id 列。 @AnandaMahto 的 splitstackshape 包具有 getanID 的功能。

 df
   country year event counter
1        A 2000     0       1
2        A 2001     0       2
3        A 2002     1       1
4        A 2003     0       2
5        A 2004     0       3
6        B 2000     1       1
7        B 2001     0       2
8        B 2002     0       3
9        B 2003     1       1
10       B 2004     0       2

【讨论】:

  • 啊,知道了,谢谢。我曾尝试使用getanIDcountryevent 作为分组变量,但没有想到使用cumsum() 来定义国家/地区内的层级。酷。
猜你喜欢
  • 2021-10-09
  • 1970-01-01
  • 1970-01-01
  • 2015-03-09
  • 2021-08-09
  • 1970-01-01
  • 2021-12-02
  • 2021-12-17
  • 1970-01-01
相关资源
最近更新 更多