#r #dataframe #date #if-statement
Вопрос:
У меня есть такой фрейм данных в R:
Дата начала | Дата окончания | Дата 1 | Дата 2 | Дата 3 | Дата 4 |
---|---|---|---|---|---|
11/12/2018 | 29/11/2019 | 08/03/2021 | NA | NA | NA |
07/03/2018 | 24/04/2019 | 08/03/2021 | 12/09/2016 | NA | NA |
04/06/2018 | 23/04/2019 | 08/03/2021 | 02/10/2017 | 05/10/2018 | NA |
26/07/2018 | 29/08/2019 | 08/03/2021 | 03/08/2015 | 02/10/2017 | 23/01/2017 |
Я хочу создать новый столбец в R, в котором говорится: Если дата 1, Дата 2, Дата 3 или Дата 4 находится между датой начала и датой окончания, в противном случае она должна возвращать 1, 0, как показано в таблице ниже:
Дата начала | Дата окончания | Дата 1 | Дата 2 | Дата 3 | Дата 4 | Изменить |
---|---|---|---|---|---|---|
11/12/2018 | 29/11/2019 | 08/03/2021 | NA | NA | NA | 0 |
07/03/2018 | 24/04/2019 | 08/03/2021 | 12/09/2016 | NA | NA | 0 |
04/06/2018 | 23/04/2019 | 08/03/2021 | 02/10/2017 | 05/10/2018 | NA | 1 |
26/07/2018 | 29/08/2019 | 08/03/2021 | 03/08/2015 | 02/10/2017 | 23/01/2017 | 0 |
У кого-нибудь есть предложения о том, как это решить? Спасибо вам 🙂
Комментарии:
1. Пожалуйста, опубликуйте свои данные в выходных данных команды
dput(your_dataframe)
, чтобы нам было легче получить доступ к вашим данным. Также включите любой код, который вы пробовали, и/или ошибки, которые вы получили.
Ответ №1:
Людям будет намного проще помогать вам, если вы сможете публиковать код / данные, которые мы можем запускать напрямую. Самый простой способ сделать это-использовать удобную функцию R dput
, которая генерирует инструкции для точного воссоздания любого объекта R. Таким образом , вы можете запустить dput(MY_DATA)
или, если ваши данные намного больше, чем необходимо для демонстрации вашего вопроса, dput(head(MY_DATA))
получить первые шесть строк и вставить их в свой вопрос. </PSA>
Вот код для создания ваших примерных данных:
my_data <- data.frame(
stringsAsFactors = FALSE,
Start.date = c("11/12/2018", "07/03/2018", "04/06/2018", "26/07/2018"),
End.date = c("29/11/2019", "24/04/2019", "23/04/2019", "29/08/2019"),
Date.1 = c("08/03/2021", "08/03/2021", "08/03/2021", "08/03/2021"),
Date.2 = c(NA, "12/09/2016", "02/10/2017", "03/08/2015"),
Date.3 = c(NA, NA, "05/10/2018", "02/10/2017"),
Date.4 = c(NA, NA, NA, "23/01/2017")
)
Вот простой подход , чтобы сначала преобразовать даты вашего дня/месяца/года в данные типа даты R, используя lubridate::dmy
, затем сравнить каждую из дат с 1 по 4 с вашими датами начала, а затем, наконец, показать, есть ли какие-либо 1 (в пределах диапазона).
library(dplyr); library(lubridate)
my_data %>%
mutate(across(.fns = ~dmy(.x))) %>%
mutate(across(.cols = starts_with("Date"),
.fns = ~coalesce(.x >= Start.date amp; .x <= End.date, FALSE)*1)) %>%
mutate(Change = pmax(Date.1, Date.2, Date.3, Date.4))
coalesce(..., FALSE)
используется здесь для того, чтобы относиться к NA как к ЛОЖНОМУ.
(...)*1
чтобы преобразовать значение TRUE/FALSE в 1/0.
pmax(...)
чтобы захватить самую большую из 1/0, то есть «есть ли какие-нибудь 1?»
Изменить: альтернатива оставить столбцы дат нетронутыми:
my_data %>%
mutate(across(.fns = ~dmy(.x))) %>%
mutate(across(.cols = starts_with("Date"),
.names = "Check_{.col}",
.fns = ~coalesce(.x >= Start.date amp; .x <= End.date, FALSE)*1)) %>%
rowwise() %>%
mutate(Change = max(c_across(starts_with("Check")))) %>%
select(-starts_with("Check"))
Start.date End.date Date.1 Date.2 Date.3 Date.4 Change
<date> <date> <date> <date> <date> <date> <dbl>
1 2018-12-11 2019-11-29 2021-03-08 NA NA NA 0
2 2018-03-07 2019-04-24 2021-03-08 2016-09-12 NA NA 0
3 2018-06-04 2019-04-23 2021-03-08 2017-10-02 2018-10-05 NA 1
4 2018-07-26 2019-08-29 2021-03-08 2015-08-03 2017-10-02 2017-01-23 0
Ответ №2:
library(tidyverse)
library(lubridate)
df <- read.table(textConnection("start_date;end_date;date_1;date_2;date_3;date_4
11/12/2018;29/11/2019;08/03/2021;NA;NA;NA
07/03/2018;24/04/2019;08/03/2021;12/09/2016;NA;NA
04/06/2018;23/04/2019;08/03/2021;02/10/2017;05/10/2018;NA
26/07/2018;29/08/2019;08/03/2021;03/08/2015;02/10/2017;23/01/2017"),
sep=";",
header = TRUE)
df %>%
mutate(
across(everything(), lubridate::dmy),
change = ((date_1 > start_date amp; date_1 < end_date) |
(date_2 > start_date amp; date_2 < end_date) |
(date_3 > start_date amp; date_3 < end_date)
) %>%
coalesce(FALSE) %>%
as.integer()
)
#> start_date end_date date_1 date_2 date_3 date_4 change
#> 1 2018-12-11 2019-11-29 2021-03-08 <NA> <NA> <NA> 0
#> 2 2018-03-07 2019-04-24 2021-03-08 2016-09-12 <NA> <NA> 0
#> 3 2018-06-04 2019-04-23 2021-03-08 2017-10-02 2018-10-05 <NA> 1
#> 4 2018-07-26 2019-08-29 2021-03-08 2015-08-03 2017-10-02 2017-01-23 0