如果相同,则折叠连续的周期
collapse consecutive periods if the same
我试着用R代码表达我的用例如下:
haves <- data.frame(
id = c(1,1,1,1)
, start = c(as.Date('2022-01-01'), as.Date('2022-02-01'), as.Date('2022-02-01'), as.Date('2022-02-16'))
, end = c(as.Date('2022-01-31'), as.Date('2022-02-28'), as.Date('2022-02-15'), as.Date('2022-02-28'))
, category = c("A", "B", "A", "A")
)
haves
wants <- data.frame(
id = c(1,1,1)
, start = c(as.Date('2022-01-01'), as.Date('2022-02-01'), as.Date('2022-02-01'))
, end = c(as.Date('2022-01-31'), as.Date('2022-02-28'), as.Date('2022-02-28'))
, category = c("A", "B", "A")
)
wants
基本上,如果时间段是连续的并且包含相同的类别但也取决于 id,我想折叠时间段(请参阅需求中的最后 2 列)。你认为这可能吗?按 id 和类别分组,然后在开始和结束时使用 min 和 max 是行不通的。
这应该可行,但如果您有任何问题,请告诉我。
首先为 id 和类别中的连续行块创建一个 ID,然后在其中找到连续的块。
haves %>%
as_tibble() %>%
mutate(
g_id = cumsum( paste0(id, '|', category) != lag(paste0(id, '|', category), n = 1L, default = '&%' ))
) %>%
group_by(id, category, g_id) %>%
mutate(
lag1 = replace_na(lag(end, n = 1L)+1 == start, T)
) %>%
ungroup() %>%
mutate(
g_id2 = cumsum( paste0(g_id, '|', lag1) != lag(paste0(g_id, '|', lag1), n = 1L, default = '&%' ))
) %>%
group_by(id, category, g_id2) %>%
summarise(
start = min(start),
end = max(end)
) %>%
arrange(g_id2)
使用 rle
,这应该有效:
r <- rle(haves$category)$l
haves %>%
mutate(cons = rep(seq(r), r)) %>%
group_by(id, category, cons) %>%
summarise(start = min(start),
end = max(end))
# A tibble: 3 x 5
# Groups: id, category [2]
id category cons start end
<dbl> <chr> <int> <date> <date>
1 1 A 1 2022-01-01 2022-01-31
2 1 A 3 2022-02-01 2022-02-28
3 1 B 2 2022-02-01 2022-02-28
或 cons = data.table::rleid(category)
.
一个data.table
选项
library(data.table)
unique(
setDT(haves)[
,
`:=`(start = min(start), end = max(end)), rleid(category)
]
)
给予
id start end category
1: 1 2022-01-01 2022-01-31 A
2: 1 2022-02-01 2022-02-28 B
3: 1 2022-02-01 2022-02-28 A
我试着用R代码表达我的用例如下:
haves <- data.frame(
id = c(1,1,1,1)
, start = c(as.Date('2022-01-01'), as.Date('2022-02-01'), as.Date('2022-02-01'), as.Date('2022-02-16'))
, end = c(as.Date('2022-01-31'), as.Date('2022-02-28'), as.Date('2022-02-15'), as.Date('2022-02-28'))
, category = c("A", "B", "A", "A")
)
haves
wants <- data.frame(
id = c(1,1,1)
, start = c(as.Date('2022-01-01'), as.Date('2022-02-01'), as.Date('2022-02-01'))
, end = c(as.Date('2022-01-31'), as.Date('2022-02-28'), as.Date('2022-02-28'))
, category = c("A", "B", "A")
)
wants
基本上,如果时间段是连续的并且包含相同的类别但也取决于 id,我想折叠时间段(请参阅需求中的最后 2 列)。你认为这可能吗?按 id 和类别分组,然后在开始和结束时使用 min 和 max 是行不通的。
这应该可行,但如果您有任何问题,请告诉我。
首先为 id 和类别中的连续行块创建一个 ID,然后在其中找到连续的块。
haves %>%
as_tibble() %>%
mutate(
g_id = cumsum( paste0(id, '|', category) != lag(paste0(id, '|', category), n = 1L, default = '&%' ))
) %>%
group_by(id, category, g_id) %>%
mutate(
lag1 = replace_na(lag(end, n = 1L)+1 == start, T)
) %>%
ungroup() %>%
mutate(
g_id2 = cumsum( paste0(g_id, '|', lag1) != lag(paste0(g_id, '|', lag1), n = 1L, default = '&%' ))
) %>%
group_by(id, category, g_id2) %>%
summarise(
start = min(start),
end = max(end)
) %>%
arrange(g_id2)
使用 rle
,这应该有效:
r <- rle(haves$category)$l
haves %>%
mutate(cons = rep(seq(r), r)) %>%
group_by(id, category, cons) %>%
summarise(start = min(start),
end = max(end))
# A tibble: 3 x 5
# Groups: id, category [2]
id category cons start end
<dbl> <chr> <int> <date> <date>
1 1 A 1 2022-01-01 2022-01-31
2 1 A 3 2022-02-01 2022-02-28
3 1 B 2 2022-02-01 2022-02-28
或 cons = data.table::rleid(category)
.
一个data.table
选项
library(data.table)
unique(
setDT(haves)[
,
`:=`(start = min(start), end = max(end)), rleid(category)
]
)
给予
id start end category
1: 1 2022-01-01 2022-01-31 A
2: 1 2022-02-01 2022-02-28 B
3: 1 2022-02-01 2022-02-28 A