在 R 中对分类变量的连续观察添加计数器?
Add counter to consecutive observations of categorical variable in R?
我有一个数据框,其中有一个变量对我的观察结果 (ID) 进行分组,另一个变量是分类变量 (type)。我在 R 中工作,并试图创建一个新变量来计算 ID 内相同类型的连续观察(数据是时间序列)。请参阅下面的示例 table - 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
}
}
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()
参数中重复出现,但这些重复对于涵盖许多条件是必要的。
我在各种条件下测试了这段代码,它看起来很健壮。它无法处理的一件事是,如果您在最后一个值处重复(它将 return 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
))
对于每个 id
、type
和以 type
0 开头的连续行,使用 ave
和 seq_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
我有一个数据框,其中有一个变量对我的观察结果 (ID) 进行分组,另一个变量是分类变量 (type)。我在 R 中工作,并试图创建一个新变量来计算 ID 内相同类型的连续观察(数据是时间序列)。请参阅下面的示例 table - 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
}
}
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()
参数中重复出现,但这些重复对于涵盖许多条件是必要的。
我在各种条件下测试了这段代码,它看起来很健壮。它无法处理的一件事是,如果您在最后一个值处重复(它将 return 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
))
对于每个 id
、type
和以 type
0 开头的连续行,使用 ave
和 seq_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