2016-03-02 2 views
2

У меня есть набор данных input, и я хочу преобразовать его в набор данных output. В основном я пытаюсь манипулировать набором данных, чтобы я мог разделить количество дней между двумя датами в разные месяцы. Хотите узнать, можно ли это сделать в R?Получить количество дней в разных месяцах с использованием 2 дат

R код для создания наборов данных ниже для удобства.

library('data.table') 
input=data.table(SerialNum=c(1,2),StartDate=c('28/01/2015','28/01/2015'),EndDate=c('03/02/2015','03/03/2015')) 

#  SerialNum StartDate EndDate 
# 1:   1 28/01/2015 03/02/2015 
# 2:   2 28/01/2015 03/03/2015 


output=data.table(SerialNum=c(1,1,2,2,2), 
        StartDate=c('28/01/2015','28/01/2015','28/01/2015','28/01/2015','28/01/2015'), 
        EndDate=c('03/02/2015','03/02/2015','03/03/2015','03/03/2015','03/03/2015'), 
        MMMYY=c('Jan15','Feb15','Jan15','Feb15','Mar15'), 
        Days=c(4,3,4,28,3)) 

#  SerialNum StartDate EndDate MMMYY Days 
# 1:   1 28/01/2015 03/02/2015 Jan15 4 
# 2:   1 28/01/2015 03/02/2015 Feb15 3 
# 3:   2 28/01/2015 03/03/2015 Jan15 4 
# 4:   2 28/01/2015 03/03/2015 Feb15 28 
# 5:   2 28/01/2015 03/03/2015 Mar15 3 
+1

Я не понимаю эту часть: «Разделить количество дней между двумя датами в разные месяцы». Разве вы не хотите, чтобы количество дней между двумя датами? Что означает «в разные месяцы»? – Stibu

+0

Извинения за неясность. Я на самом деле пытаюсь рассчитать количество дней пребывания пациента в больнице, но с разбивкой по месяцам. Например, если пациент остался с 28 января 2002 года до 03Feb2015, он/она оставался бы 4 дня в январе и 3 дня в феврале. Чтобы сделать сводную таблицу, чтобы узнать, сколько дней для пациентов используется в январе и феврале соответственно, я бы необходимо манипулировать набором данных, чтобы дать мне 2 наблюдения. 1 за январь и 1 за февраль – user6008722

ответ

3

Вы можете сделать это путем создания последовательности из StartDate в EndDate и извлечь переменную месяц года от этого (mnth в примере ниже). Далее вам итог по serialNum и вновь созданный месяц-год переменная (mnth):

input[, .(mnth = format(seq(StartDate,EndDate,"day"), "%b%y")), 
     by = .(SerialNum, StartDate, EndDate) 
     ][, .N, by = .(SerialNum, StartDate, EndDate, mnth)] 

, который даст вам:

SerialNum StartDate EndDate mnth N 
1:   1 2015-01-28 2015-02-03 jan15 4 
2:   1 2015-01-28 2015-02-03 feb15 3 
3:   2 2015-01-28 2015-03-03 jan15 4 
4:   2 2015-01-28 2015-03-03 feb15 28 
5:   2 2015-01-28 2015-03-03 mrt15 3 

Если вы StartDate и EndDate столбцы не отформатированы как даты еще, вам может конвертировать их в формат даты с:

input[, `:=` (StartDate = as.Date(StartDate,"%d/%m/%Y"), 
       EndDate = as.Date(EndDate,"%d/%m/%Y"))] 

# or with the 'lubridate' package like @Titolondon used 
library(lubridate) 
input[, `:=` (StartDate = dmy(StartDate), EndDate = dmy(EndDate))] 

Используемые данные:

input <- data.table(SerialNum = c(1,2), 
        StartDate = as.Date(c('28/01/2015','28/01/2015'),"%d/%m/%Y"), 
        EndDate = as.Date(c('03/02/2015','03/03/2015'),"%d/%m/%Y")) 
+0

Это очень полезно. Я понимаю .N ​​используется, потому что это разница в количестве дней. Как я могу изменить код, если бы у меня были как даты, так и время, чтобы я мог получить дробные дни? – user6008722

1

Это основание R решение, нежели чем в растворе data.table: sapply работает отдельно по каждому значению SerialNum. Мы создаем последовательность дат от StartDate до EndDate, затем подсчитываем количество дат в течение месяца. Все это обернуто в do.call(rbind, ...), чтобы превратить полученный список в единый фрейм данных.

library(lubridate) 

input = data.frame(SerialNum=c(1,2),StartDate=c('28/01/2015','28/01/2015'),EndDate=c('03/02/2015','03/03/2015'), 
        stringsAsFactors=FALSE) 

input[,2:3] = lapply(input[,2:3], dmy) 

do.call(rbind, 
     sapply(unique(input$SerialNum), function(i) { 

      start = input[input$SerialNum==i,"StartDate"] 
      end = input[input$SerialNum==i, "EndDate"] 

      dates = seq(start, end, by="1 day") 

      data.frame(SerialNum=i, StartDate=start, EndDate=end, 
        MMMYY=unique(format(dates, "%b%y")), 
        Days=sapply(split(dates, droplevels(month(dates, label=TRUE))), length)) 

     }, simplify=FALSE)) 

    SerialNum StartDate EndDate MMMYY Days 
Jan   1 2015-01-28 2015-02-03 Jan15 4 
Feb   1 2015-01-28 2015-02-03 Feb15 3 
Jan1   2 2015-01-28 2015-03-03 Jan15 4 
Feb1   2 2015-01-28 2015-03-03 Feb15 28 
Mar   2 2015-01-28 2015-03-03 Mar15 3 
1

Использование data.table и lubridate:

library(data.table) 

input = data.table(
    SerialNum = c(1, 2), 
    StartDate = c('28/01/2015', '28/01/2015'), 
    EndDate = c('03/02/2015', '03/03/2015') 
) 

Работа с lubridate для манипулирования датой

library(lubridate) 

Если уже не в POSIXct, преобразовать столбец с lubridate функций

input[, StartDate := dmy(StartDate)] 
input[, EndDate := dmy(EndDate)] 

Trick: создать последовательность даты между StartDate и EndDate по SerialNum

DT <- input[, .(seqDate = StartDate + days(0:(EndDate - StartDate))), 
      by = .(SerialNum, StartDate, EndDate)] 

Dérivé MMMYY колонки из этой новой последовательности дат.Я использовал month.abb иметь хорошую аббревиатуру, но вы можете использовать MMMYY = format(seqDate, "%b%y"), если вы находитесь в хорошей настройке

DT[, MMMYY := paste0(month.abb[month(seqDate)], format(seqDate, "%y"))] 

Подсчитать количество дней в месяц локали (колонка MMMYY)

output = DT[, .(Days = .N), by = .(SerialNum, StartDate, EndDate, MMMYY)] 
output 
#> SerialNum StartDate EndDate MMMYY Days 
#> 1:   1 2015-01-28 2015-02-03 Jan15 4 
#> 2:   1 2015-01-28 2015-02-03 Feb15 3 
#> 3:   2 2015-01-28 2015-03-03 Jan15 4 
#> 4:   2 2015-01-28 2015-03-03 Feb15 28 
#> 5:   2 2015-01-28 2015-03-03 Mar15 3 
Смежные вопросы