我有一个类似于以下数据集的大型数据集。
身份证 | 日期 | 改变 | 工资 |
---|---|---|---|
201 | 2023年1月4日 | B-AL | 900 |
201 | 2023年3月1日 | AL-AL | 900 |
201 | 2023年10月1日 | AL-AL | 900 |
201 | 2023年11月10日 | AL-B | 1900 |
201 | 2023年11月28日 | B-AL | 900 |
201 | 2023年12月10日 | AL-B | 1905 |
301 | 2023年1月3日 | B-AL | 1100 |
301 | 2023年2月11日 | AL-B | 2500 |
301 | 2023年4月15日 | B-AL | 1110 |
301 | 2023年9月27日 | AL-B | 2506 |
401 | 2023年1月2日 | B-AL | 700 |
401 | 2023年1月28日 | AL-X | 0 |
401 | 2023年2月10日 | AL-AL | 700 |
401 | 2023年4月2日 | AL-AL | 700 |
401 | 2023年5月10日 | AL-B | 2200 |
401 | 2023年8月13日 | B-AL | 800 |
我想计算每个状态的平均工资,但有两个限制: 首先,我只想考虑每个人的状态,直到第二次达到“B-AL”状态。每个 ID 第二次出现“B-AL”之后的所有行不应在计算中考虑。
(我认为)我通过创建两个帮助变量解决了这个问题,然后用 cumsum() 进行过滤
data <- data %>%
arrange(date) %>%
mutate(num = row_number(),
num2 = ifelse(change == "B-AL" & num == 2, 1, 0),
.by = c(ID, change))
data <- data %>%
group_by(ID) %>%
filter(cumsum(num2) == 0) %>%
ungroup()
现在第二个限制:一旦一个 ID 的状态为“AL-X”,所有后续行就不应该被考虑。
如果我使用与上面相同的方法,我也会失去第一次出现“AL-X”的观察结果。但是,我希望包含此一项,并排除所有后续项。两次操作后,表格应如下所示
身份证 | 日期 | 改变 | 工资 |
---|---|---|---|
201 | 2023年1月4日 | B-AL | 900 |
201 | 2023年3月1日 | AL-AL | 900 |
201 | 2023年10月1日 | AL-AL | 900 |
201 | 2023年11月10日 | AL-B | 1900 |
301 | 2023年1月3日 | B-AL | 1100 |
301 | 2023年2月11日 | AL-B | 2500 |
401 | 2023年1月2日 | B-AL | 700 |
401 | 2023年1月28日 | AL-X | 0 |
之后我可以通过summary计算平均工资(先按状态,然后按ID)
如有任何帮助,我们将不胜感激。我也不确定第一次手术是否合理有效。
根据您想要的输出来判断
library(dplyr)
df %>%
filter(cumsum(Change == c("B-AL")) < 2,
lag(cumsum(Change == c("AL-X")), default=0) < 1, .by = ID)
ID Date Change wage
1 201 04.01.2023 B-AL 900
2 201 01.03.2023 AL-AL 900
3 201 01.10.2023 AL-AL 900
4 201 10.11.2023 AL-B 1900
5 301 03.01.2023 B-AL 1100
6 301 11.02.2023 AL-B 2500
7 401 02.01.2023 B-AL 700
8 401 28.01.2023 AL-X 0
library(dplyr)
foo <- function(x, vc1, vc2, vc1_limit = 2L, vc2_limit = 1) {
vc1_count <- 0L; vc2_count <- 0L
helper <- function(v) {
if (v == vc1) vc1_count <<- vc1_count + 1L else if (v == vc2) vc2_count <<- vc2_count + 1L
if (vc1_count == vc1_limit || vc2_count == vc2_limit) TRUE else FALSE
}
pos <- Position(helper, x)
if (is.na(pos)) length(x) else pos
}
df |>
group_by(ID) |>
filter(row_number() <= foo(Change, vc1 = "B-AL", vc2 = "AL-X"))
# ID Date Change wage
# 1 201 04.01.2023 B-AL 900
# 2 201 01.03.2023 AL-AL 900
# 3 201 01.10.2023 AL-AL 900
# 4 201 10.11.2023 AL-B 1900
# 5 201 28.11.2023 B-AL 900
# 6 301 03.01.2023 B-AL 1100
# 7 301 11.02.2023 AL-B 2500
# 8 301 15.04.2023 B-AL 1110
# 9 401 02.01.2023 B-AL 700
# 10 401 28.01.2023 AL-X 0