在R中对分类变量的连续观察中添加反计数吗?

时间:2018-11-29 04:30:34

标签: r dataframe for-loop data-cleaning

我有一个数据框,其中的变量将我的观察结果(ID)分组,另一个变量是分类的(type)。我正在R中工作,正在尝试创建一个新变量,该变量计算ID(数据是时间序列)中同一类型的连续观察值。请参阅下面的示例表-计数器是我要创建的变量。是否计数为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
  }
}

2 个答案:

答案 0 :(得分:3)

对于每个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

答案 1 :(得分:1)

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
  ))