Я пытаюсь добавить список месяца и года между двумя датами.
У меня есть следующий набор данных:
PKID Name Gender DateStart DateEnd
68 PAUL 1 24/11/2021 23/02/2022
68 PAUL 1 24/04/2022 23/06/2023
40 KATE 2 01/01/2000 14/03/2000
40 KATE 2 03/12/2000 31/01/2001
И я хочу создать следующий набор данных:
PKID Name Gender DateStart DateEnd year Month
68 PAUL 1 24/11/2021 23/02/2022 2021 11
68 PAUL 1 24/11/2021 23/02/2022 2021 12
68 PAUL 1 24/11/2021 23/02/2022 2022 1
68 PAUL 1 24/11/2021 23/02/2022 2022 2
68 PAUL 1 24/04/2022 23/06/2023 2022 4
68 PAUL 1 24/04/2022 23/06/2023 2022 5
68 PAUL 1 24/04/2022 23/06/2023 2022 6
40 KATE 2 01/01/2000 14/03/2000 2000 1
40 KATE 2 01/01/2000 14/03/2000 2000 2
40 KATE 2 01/01/2000 14/03/2000 2000 3
40 KATE 2 03/12/2000 31/01/2001 2000 12
40 KATE 2 03/12/2000 31/01/2001 2001 1
Где месяц соответствует месяцу между звездной датой и конечной датой, а год соответствует месяцу.
Я пробовал следующее:
# Load necessary libraries
library(dplyr)
library(tidyr)
library(lubridate) # For handling date operations
# Sample data
df <- read.table(text = "
PKID Name Gender DateStart DateEnd
68 PAUL 1 24/11/2021 23/02/2022
68 PAUL 1 24/04/2022 23/06/2023
40 KATE 2 01/01/2000 14/03/2000
40 KATE 2 03/12/2000 31/01/2001
", header = TRUE, stringsAsFactors = FALSE)
# Convert date columns to Date format
df$DateStart <- dmy(df$DateStart)
df$DateEnd <- dmy(df$DateEnd)
# Generate sequence of dates for each row
df <- df %>%
group_by(PKID, Name, Gender, DateStart, DateEnd) %>%
complete(Date = seq.Date(DateStart, DateEnd, by = "month")) %>%
ungroup() %>%
mutate(
year = year(Date), # Extract year
Month = month(Date) # Extract month
) %>%
select(-Date) # Remove the temporary Date column
# Print the result
print(df)
Но я получаю следующую ошибку:
Error in reframe():
ℹ In argument: complete(data = pick(everything()), ..., fill = fill, explicit = explicit).
ℹ In group 1: PKID = 40, Name = "KATE", Gender = 2, DateStart = 2000-01-01, DateEnd = 2000-03-14.
Caused by error:
! object 'DateStart' not found
Я внес несколько изменений в ваш подход, чтобы он работал.
library(dplyr)
library(tidyr)
library(lubridate)
df %>%
mutate(row = row_number(),
Date = DateStart) %>%
group_by(row) %>%
complete(PKID, Name, Gender, DateStart, DateEnd,
Date = seq(DateStart, DateEnd, by = "month")) %>%
ungroup() %>%
mutate(
year = year(Date),
Month = month(Date)
) %>%
select(-Date, -row)
# A tibble: 22 × 7
# PKID Name Gender DateStart DateEnd year Month
# <int> <chr> <int> <date> <date> <dbl> <dbl>
# 1 68 PAUL 1 2021-11-24 2022-02-23 2021 11
# 2 68 PAUL 1 2021-11-24 2022-02-23 2021 12
# 3 68 PAUL 1 2021-11-24 2022-02-23 2022 1
# 4 68 PAUL 1 2022-04-24 2023-06-23 2022 4
# 5 68 PAUL 1 2022-04-24 2023-06-23 2022 5
# 6 68 PAUL 1 2022-04-24 2023-06-23 2022 6
# 7 68 PAUL 1 2022-04-24 2023-06-23 2022 7
# 8 68 PAUL 1 2022-04-24 2023-06-23 2022 8
# 9 68 PAUL 1 2022-04-24 2023-06-23 2022 9
#10 68 PAUL 1 2022-04-24 2023-06-23 2022 10
# ℹ 12 more rows
# ℹ Use `print(n = ...)` to see more rows
Альтернатива использованию гнезда.
df |>
nest(data=c(DateStart, DateEnd), .by=c(PKID, Name, Gender, DateStart, DateEnd)) |>
mutate(date=sapply(data, \(x) unique(
c(seq.Date(x$DateStart, x$DateEnd, by = "month"), x$DateEnd))),
year=sapply(date, year),
Month=sapply(date, month)) |>
unnest(c(year, Month)) |>
select(-c(data, date))
# A tibble: 26 × 7
PKID Name Gender DateStart DateEnd year Month
<int> <chr> <int> <date> <date> <dbl> <dbl>
1 68 PAUL 1 2021-11-24 2022-02-23 2021 11
2 68 PAUL 1 2021-11-24 2022-02-23 2021 12
3 68 PAUL 1 2021-11-24 2022-02-23 2022 1
4 68 PAUL 1 2021-11-24 2022-02-23 2022 2
5 68 PAUL 1 2022-04-24 2023-06-23 2022 4
6 68 PAUL 1 2022-04-24 2023-06-23 2022 5
7 68 PAUL 1 2022-04-24 2023-06-23 2022 6
8 68 PAUL 1 2022-04-24 2023-06-23 2022 7
9 68 PAUL 1 2022-04-24 2023-06-23 2022 8
10 68 PAUL 1 2022-04-24 2023-06-23 2022 9
# ℹ 16 more rows
# ℹ Use `print(n = ...)` to see more rows
Можешь попробовать:
library(dplyr)
library(purrr)
library(tidyr)
library(lubridate)
df |>
mutate(date = map2(DateStart, rollforward(DateEnd), \(x, y) seq(x, y, by = "month"))) |>
unnest(date) |>
mutate(year = year(date),
month = month(date),
date = NULL)
# A tibble: 26 × 7
PKID Name Gender DateStart DateEnd year month
<int> <chr> <int> <date> <date> <dbl> <dbl>
1 68 PAUL 1 2021-11-24 2022-02-23 2021 11
2 68 PAUL 1 2021-11-24 2022-02-23 2021 12
3 68 PAUL 1 2021-11-24 2022-02-23 2022 1
4 68 PAUL 1 2021-11-24 2022-02-23 2022 2
5 68 PAUL 1 2022-04-24 2023-06-23 2022 4
6 68 PAUL 1 2022-04-24 2023-06-23 2022 5
7 68 PAUL 1 2022-04-24 2023-06-23 2022 6
8 68 PAUL 1 2022-04-24 2023-06-23 2022 7
9 68 PAUL 1 2022-04-24 2023-06-23 2022 8
10 68 PAUL 1 2022-04-24 2023-06-23 2022 9
# ℹ 16 more rows
# ℹ Use `print(n = ...)` to see more rows
Или альтернативно с reframe()
df |>
reframe(date = seq(DateStart, rollforward(DateEnd), by = "month"),
year = year(date),
month = month(date),
.by = everything()) |>
select(-date)
Это не сработает, если EndDate приходится на тот же день, что и StartDate. Замените в первой строке 23.02.2022 на 24.02.2022. Вы получаете дополнительный месяц.
@Эдвард - хороший улов. Зафиксированный.
Спасибо, что научили меня rollforward
- Сегодня я кое-чему научился!
В базе R мы можем добавить столбец "list"
, используя seq.Date
в Map
с strftime
для месяцев. Затем мы создаем data.frame
, скажем, из PKID и списков соответствующих месяцев, которые мы rbind
и, наконец, merge
в исходный фрейм данных.
> dat |>
+ transform(...=Map(seq.Date, DateStart, DateEnd, by='month') |>
+ lapply(strftime, '%m') |> list() |> list2DF() |>
+ setNames('mlst')) |>
+ with(Map(data.frame, PKID=PKID, months=mlst)) |>
+ do.call(what='rbind') |> merge(dat, sort=FALSE)
PKID months Name Gender DateStart DateEnd
1 68 11 PAUL 1 2021-11-24 2022-02-23
2 68 11 PAUL 1 2022-04-24 2023-06-23
3 68 12 PAUL 1 2021-11-24 2022-02-23
4 68 12 PAUL 1 2022-04-24 2023-06-23
5 68 01 PAUL 1 2021-11-24 2022-02-23
6 68 01 PAUL 1 2022-04-24 2023-06-23
7 68 04 PAUL 1 2021-11-24 2022-02-23
8 68 04 PAUL 1 2022-04-24 2023-06-23
9 68 05 PAUL 1 2021-11-24 2022-02-23
10 68 05 PAUL 1 2022-04-24 2023-06-23
11 68 06 PAUL 1 2021-11-24 2022-02-23
12 68 06 PAUL 1 2022-04-24 2023-06-23
13 68 07 PAUL 1 2021-11-24 2022-02-23
14 68 07 PAUL 1 2022-04-24 2023-06-23
15 68 08 PAUL 1 2021-11-24 2022-02-23
16 68 08 PAUL 1 2022-04-24 2023-06-23
17 68 09 PAUL 1 2021-11-24 2022-02-23
18 68 09 PAUL 1 2022-04-24 2023-06-23
19 68 10 PAUL 1 2021-11-24 2022-02-23
20 68 10 PAUL 1 2022-04-24 2023-06-23
21 68 11 PAUL 1 2021-11-24 2022-02-23
22 68 11 PAUL 1 2022-04-24 2023-06-23
23 68 12 PAUL 1 2021-11-24 2022-02-23
24 68 12 PAUL 1 2022-04-24 2023-06-23
25 68 01 PAUL 1 2021-11-24 2022-02-23
26 68 01 PAUL 1 2022-04-24 2023-06-23
27 68 02 PAUL 1 2021-11-24 2022-02-23
28 68 02 PAUL 1 2022-04-24 2023-06-23
29 68 03 PAUL 1 2021-11-24 2022-02-23
30 68 03 PAUL 1 2022-04-24 2023-06-23
31 68 04 PAUL 1 2021-11-24 2022-02-23
32 68 04 PAUL 1 2022-04-24 2023-06-23
33 68 05 PAUL 1 2021-11-24 2022-02-23
34 68 05 PAUL 1 2022-04-24 2023-06-23
35 40 01 KATE 2 2000-01-01 2000-03-14
36 40 01 KATE 2 2000-12-03 2001-01-31
37 40 02 KATE 2 2000-01-01 2000-03-14
38 40 02 KATE 2 2000-12-03 2001-01-31
39 40 03 KATE 2 2000-01-01 2000-03-14
40 40 03 KATE 2 2000-12-03 2001-01-31
41 40 12 KATE 2 2000-01-01 2000-03-14
42 40 12 KATE 2 2000-12-03 2001-01-31
43 40 01 KATE 2 2000-01-01 2000-03-14
44 40 01 KATE 2 2000-12-03 2001-01-31
Обратите внимание, что вам нужен правильный формат данных в столбцах. Поскольку это базовые знания, я включил их в раздел данных ниже.
Данные:
> dput(dat)
structure(list(PKID = c(68L, 68L, 40L, 40L), Name = c("PAUL",
"PAUL", "KATE", "KATE"), Gender = c(1L, 1L, 2L, 2L), DateStart = c("24/11/2021",
"24/04/2022", "01/01/2000", "03/12/2000"), DateEnd = c("23/02/2022",
"23/06/2023", "14/03/2000", "31/01/2001")), class = "data.frame", row.names = c(NA,
-4L))
> date_cols <- c('DateStart', 'DateEnd')
> dat[date_cols] <- lapply(dat[date_cols], as.Date, '%d/%m/%Y')
Спасибо . Это работает, однако последний месяц отсутствует в списке. Как и для даты начала 24.11.2021 и даты окончания 23.02.2022, у нас есть выходные данные для месяцев 11 и 12 для 2021 года и только для месяца 1 для 2022 года. Месяц 2 отсутствует в выходных данных.