Я имею дело с датами и хотел сгруппировать несколько строк, но не могу найти, как это сделать. В моих данных одна строка — это особь в интервале времени и в месте. Что-то вроде того :
ind place start_date end_date
<int> <int> <date> <date>
1 1 1 2011-01-04 2011-01-05
2 1 1 2011-01-05 2011-01-06
3 1 1 2011-01-10 2011-01-11
4 1 4 2010-12-30 2010-12-31
5 1 4 2010-12-31 2011-01-01
6 1 4 2011-01-01 2011-01-03
7 2 2 2018-02-17 2018-02-19
8 2 2 2018-02-19 2018-02-23
9 3 3 2018-02-08 2018-02-13
10 3 3 2018-02-13 2018-02-16
11 3 3 2018-02-16 2018-02-20
12 3 3 2018-03-27 2018-03-29
Как видите, иногда start_date
такой же, как и предыдущий end_date
. Я могу group_by
ind
и place
, чтобы объединить временные интервалы, но проблема в том, что в некоторых строках есть пробел между start_date
и предыдущим end_date
. Поэтому мне нужно разделить эти группы на несколько других групп перед объединением.
В первую очередь я хочу получить:
ind place start_date end_date group
<int> <int> <date> <date> <int>
1 1 1 2011-01-04 2011-01-05 1
2 1 1 2011-01-05 2011-01-06 1
3 1 1 2011-01-10 2011-01-11 2
4 1 4 2010-12-30 2010-12-31 3
5 1 4 2010-12-31 2011-01-01 3
6 1 4 2011-01-01 2011-01-03 3
7 2 2 2018-02-17 2018-02-19 4
8 2 2 2018-02-19 2018-02-23 4
9 3 3 2018-02-08 2018-02-13 5
10 3 3 2018-02-13 2018-02-16 5
11 3 3 2018-02-16 2018-02-20 5
12 3 3 2018-03-27 2018-03-29 6
И в конце:
ind place start_date end_date
<chr> <chr> <date> <date>
1 1 1 2011-01-04 2011-01-06
2 1 1 2011-01-10 2011-01-11
3 1 4 2010-12-30 2011-01-03
4 2 2 2018-02-17 2018-02-23
5 3 3 2018-02-08 2018-02-20
6 3 3 2018-03-27 2018-03-29
У вас есть идея, как я могу это сделать?
Спасибо !
Сначала вы можете отсортировать arrange
по дате start
, а затем создать столбец группировки, в котором start
отличается от end
в предыдущей строке. Последние start
и end
будут датами min
и max
внутри этих групп.
library(tidyverse)
df %>%
mutate(start = as.Date(start_date), end = as.Date(end_date)) %>%
arrange(ind, place, start) %>%
mutate(group = cumsum(coalesce(start != lag(end), 0)), .by = c(ind, place)) %>%
reframe(start = min(start), end = max(end), .by = c(ind, group, place)) %>%
select(-group) %>%
arrange(ind, place)
Выход
ind place start end
1 1 1 2011-01-04 2011-01-06
2 1 1 2011-01-10 2011-01-11
3 1 4 2010-12-30 2011-01-03
4 2 2 2018-02-17 2018-02-23
5 3 3 2018-02-08 2018-02-20
6 3 3 2018-03-27 2018-03-29
Один из способов — добавить дополнительную группирующую переменную, которая проверяет, меньше ли end_date, чем start_date.
library(dplyr)
df %>%
group_by(grp = cumsum(lag(end_date, default=end_date[1]) < start_date),
ind, place) %>%
summarize(start_date = first(start_date),
end_date = last(end_date), .groups = "drop") %>%
select(-grp)
# A tibble: 6 × 4
ind place start_date end_date
<int> <int> <date> <date>
1 1 1 2011-01-04 2011-01-06
2 1 1 2011-01-10 2011-01-11
3 1 4 2010-12-30 2011-01-03
4 2 2 2018-02-17 2018-02-23
5 3 3 2018-02-08 2018-02-20
6 3 3 2018-03-27 2018-03-29
@jrdavalos Если данные упорядочены (кажется, так и есть), это должно дать те же результаты. (min и max возвращают Inf
, если есть пустые группы, иногда это нежелательно)
Может быть, с
max
иmin
, а не сfirst
иlast