Дополнительные дни между датами в R

#r #dplyr

Вопрос:

У меня есть длинный список, в котором нужны дни между датами

 ClientID <- c("00932", "00932", "00932")
Visit <- c("2018-11-10", "2018-11-20", "2018-11-25")

ClientID    Visit
00932    2018-11-10
00932    2018-11-20
00932    2018-11-25
 

Мне нужна новая колонка, в которой говорится:

 ClientID    Visit    Days
00932    2018-11-10    0
00932    2018-11-20    10
00932    2018-11-25    15
 

Ответ №1:

Измените Visit класс на дату и для каждого ClientID вычтите значение Visit с минимальной Visit датой.

 library(dplyr)

df %>%
  mutate(Visit = as.Date(Visit, '%m-%d-%Y')) %>%
  group_by(ClientID) %>%
  mutate(Days = as.integer(Visit - min(Visit))) %>%
  ungroup

# ClientID Visit       Days
#  <chr>    <date>     <int>
#1 00932    2018-11-10     0
#2 00932    2018-11-20    10
#3 00932    2018-11-25    15
 

данные

 ClientID <- c("00932", "00932", "00932")
Visit <- c("11-10-2018", "11-20-2018", "11-25-2018")
df <- data.frame(ClientID, Visit)
 

Комментарии:

1. Это решение создает 2 пустых столбца в моем фрейме данных, как посещение, так и Дни не являются N/A

2. Это прекрасно работает, используя данные в моем посте.

Ответ №2:

Учитывая, что у вас их несколько ClientID и вы хотите рассчитать Days на этом уровне:

 library(lubridate)
library(tidyverse)

ClientID <- c("00932", "00932", "00932")
Visit <- c("11-10-2018", "11-20-2018", "11-25-2018")

df <- data.frame(ClientID, Visit)

df %>%
  group_by(ClientID) %>%
  mutate(Visit= mdy(Visit),
         Days= as.numeric(Visit-lag(Visit)))%>%
  ungroup()%>%
  mutate_if(is.numeric, ~replace_na(., 0))

# A tibble: 3 x 3
  ClientID Visit       Days
  <chr>    <date>     <dbl>
1 00932    2018-11-10     0
2 00932    2018-11-20    10
3 00932    2018-11-25     5
 

Добавим еще ClientID одно и два наблюдения, чтобы лучше это продемонстрировать:

 ClientID <- c("00932", "00932", "00932", "00935", "00935")
Visit <- c("11-10-2018", "11-20-2018", "11-25-2018",  "11-20-2019", "11-25-2019")

df <- data.frame(ClientID, Visit)

df %>%
  group_by(ClientID) %>%
  mutate(Visit= mdy(Visit),
         Days= as.numeric(Visit-lag(Visit)))%>%
  ungroup()%>%
  mutate_if(is.numeric, ~replace_na(., 0))

# A tibble: 5 x 3
  ClientID Visit       Days
  <chr>    <date>     <dbl>
1 00932    2018-11-10     0
2 00932    2018-11-20    10
3 00932    2018-11-25     5
4 00935    2019-11-20     0
5 00935    2019-11-25     5
 

Добавление функции, как было предложено в комментариях:

 days_func <- function(df){
  
  df %>%
    group_by(ClientID) %>%
    mutate(Visit= mdy(Visit),
           Days= as.numeric(Visit-lag(Visit)))%>%
    ungroup()%>%
    mutate_if(is.numeric, ~replace_na(., 0))->df
  
  return(df)
}

df1 <- days_func(df)

df1

# A tibble: 3 x 3
  ClientID Visit       Days
  <chr>    <date>     <dbl>
1 00932    2018-11-10     0
2 00932    2018-11-20    10
3 00932    2018-11-25     5
 

Комментарии:

1. Как я могу преобразовать это в функцию? Столбец «Дни» не может быть добавлен, если я попытаюсь превратить это в функцию

2. @RandomPerson Я добавил его. Проверять.

3. @RandomPerson это решило вашу цель?

Ответ №3:

Поскольку я предполагаю, что вам нужен промежуток времени между датами, а не между датой и последней датой, я предлагаю это:

dn <- as.numeric(as.Date(Visit))

Текст с датами последовательно преобразуется в дату и в число.

dn2 <- c(dn[1], dn[-length(dn)])

Мы готовим второй вектор для вычитания, так как он будет работать быстро. В нем будет такой порядок участников, как этот:

df df2

1-й 1-й

2-й 1-й

3-й 2-й

n-й n-й-1

Days <- dn - dn2

Найдите пролет.