【问题标题】:Add counter to consecutive observations of categorical variable in R?为R中分类变量的连续观察添加计数器?
【发布时间】:2019-05-01 02:14:59
【问题描述】:

我有一个数据框,其中一个变量将我的观察结果 (ID) 和另一个分类变量 (类型) 分组。我在 R 中工作,并试图创建一个新变量来计算 ID 中相同类型的连续观察值(数据是时间序列)。请参阅下面的示例表 - Counter 是我要创建的变量。是否计算 0 并不重要。

dat <- data.frame(id = c(rep("a", 7), rep("b", 4)),
                  type = c(0, 1, 1, 2, 2, 0, 1, 1, 1, 2, 0),
                  counter = c(0, 1, 2, 1, 2, 0, 1, 1, 2, 1, 0))

到目前为止,我能够制作计数器,虽然可能不是以最有效的方式,但我正在努力在分组 (ID) 中执行此操作并有效地在 type = 1 和 type = 2 之间切换。我编写的代码使计数器在下面。关于如何有效地做到这一点的任何想法?谢谢。

dat$counter <- 0
counter     <- 0
for(i in 1:nrow(dat)){
  if(dat[i,"type"] != 0){
    counter <- counter + 1
    dat[i,"count"] <- counter
    # use to differentiate between 1 and 2?
    this_group <- dat[i,"type"]
  }
  if(dat[i,"type"] == 0){
    counter <- 0
  }
}

【问题讨论】:

  • 您在 for 循环中忘记了一个 ) for(i in 1:nrow(dat) -- 已添加 –
  • 我不明白你的问题。你没有从什么开始(没有counter?)以及你想创建什么counter - 你的第一个dat指令中的那个,或者你下面的代码给出的那个?
  • @vaettchen 谢谢。我需要在我的帖子中提供的dat 中创建counter 变量。用我的代码创建的counter 不正确。

标签: r dataframe for-loop data-cleaning


【解决方案1】:

对于每个idtype 和以type 0 开头的连续行,使用aveseq_along 创建一个序列。没有使用任何包:

transform(dat, 
  counter = (type > 0) * ave(type, id, type, cumsum(type == 0), FUN = seq_along))

给予:

   id type counter
1   a    0       0
2   a    1       1
3   a    1       2
4   a    2       1
5   a    2       2
6   a    0       0
7   a    1       1
8   b    1       1
9   b    1       2
10  b    2       1
11  b    0       0

【讨论】:

  • 谢谢 - 这个解决方案效果很好。很简单。接近一百万次观测,所以这非常快。我用 ave 尝试了几个解决方案,但始终无法弄清楚 - 它有助于看到这一点。标记为已回答。
【解决方案2】:
library(dplyr)

dat %>%
  mutate(counter = case_when(
    type == 0 ~ 0,
    id != lag(id) ~ 1,
    type != lag(type) ~ 1
  )) %>%
  mutate(counter = case_when(
    id != lag(id) ~ 1,
    type == lag(type) ~ lag(counter) + 1,
    T ~ counter
  ))

结果:

   id type counter
1   a    0       0
2   a    1       1
3   a    1       2
4   a    2       1
5   a    2       2
6   a    0       0
7   a    1       1
8   b    1       1
9   b    1       2
10  b    2       1
11  b    0       0

注意:一些代码在两个case_when() 参数中重复,但这些重复对于涵盖许多条件是必要的。

我在各种条件下测试了这段代码,它看起来很健壮。它无法处理的一件事是如果您在最后一个值处重复(它将返回NA,因为我使用lag())。

这段较长的代码也涵盖了这种情况,并且(我认为)无论您的代码如何都应该可以工作:

dat %>%
  mutate(counter = case_when(
    type == 0 ~ 0,
    type != lag(type) ~ 1
  )) %>%
  mutate(counter = case_when(
    id != lag(id) ~ 1,
    type == lag(type) ~ lag(counter) + 1,
    T ~ counter
  )) %>%
  mutate(counter = case_when(
    is.na(counter) ~ lag(counter) + 1,
    T ~ counter
  ))

【讨论】:

  • 谢谢!为帖子点赞。这确实很有帮助,但我接受了另一个答案,因为它很简单,没有 Na,而且它的稳健性。
猜你喜欢
  • 2020-03-18
  • 2021-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-03
  • 2019-11-15
  • 2017-09-09
  • 1970-01-01
相关资源
最近更新 更多