आर में तारीखों को कैसे विभाजित करें (ब्रेक डाउन करें)?

Aug 17 2020

मैं रजिस्टर डेटा का उपयोग करके बीमार छुट्टी पर एक अध्ययन कर रहा हूं। रजिस्टर से, मुझे केवल प्रत्येक व्यक्ति के लिए बीमार पत्तियों की शुरुआती तारीखें और अंतिम तिथियां मिलीं। लेकिन तारीखें साल दर साल टूटती नहीं हैं। उदाहरण के लिए, व्यक्ति A के लिए, केवल प्रारंभ दिनांक (1-may-2016) और अंतिम तिथि (14-feb-2018) के लिए डेटा हैं।

इसलिए, मैं जानना चाहता हूं कि मैं वर्ष दर वर्ष R (यानी 01/05/16 से 14/02/18 तक) को 01/5 / 16-31 / 12/16, 01 में कैसे विभाजित कर सकता हूं। / 01 / 2017-31 / 12/17, 01/01 / 18-14 / 02/18) प्रत्येक वर्ष के लिए बीमार पत्तियों की कुल संख्या की गणना करने के लिए।

प्रश्न के लिए बनाया गया उदाहरण डेटा निम्नानुसार है;

sick_leave <- tribble(
      ~id,        ~from,          ~to, 
        1, "01/01/2018", "03/10/2020",
        2, "01/01/2016", "01/01/2021", 
        3, "02/01/2018", "02/06/2018",
        3, "02/07/2018", "31/12/2018",
        4, "02/10/2018", "02/02/2019",
        4, "31/12/2019", "01/01/2021",
        5, "02/10/2017", "20/05/2018",
        6, "02/03/2021", "31/12/2021",
        7, "01/01/2016", "05/06/2016"
    ) %>% mutate(from = dmy(from),to = dmy(to))

वांछित उत्पादन है:

id  year  from        to          wanted
 1  2018  2018-01-01  2018-12-31  365
 1  2019  2019-01-01  2019-12-31  365
 1  2020  2020-01-01  2020-10-03  277
 2  2016  2016-01-01  2016-12-31  366
 2  2017  2017-01-01  2017-12-31  365
 2  2018  2018-01-01  2018-12-31  365
 2  2019  2019-01-01  2019-12-31  365
 2  2020  2020-01-01  2020-12-31  366
 2  2021  2021-01-01  2021-01-01    1
 3  2018  2018-01-02  2018-06-02  152
 3  2018  2018-07-02  2018-12-31  183
 4  2018  2018-10-02  2018-12-31   91
 4  2019  2019-01-01  2019-02-02   33
 4  2019  2019-12-31  2019-12-31    1
 4  2020  2020-01-01  2020-12-31  366
 4  2021  2021-01-01  2021-01-01    1
 5  2017  2017-10-02  2017-12-31   91
 5  2018  2018-01-01  2018-05-20  140
 6  2021  2021-03-02  2021-12-31  305
 7  2016  2016-01-01  2016-06-05  157

जवाब

1 Edo Aug 17 2020 at 15:40

इस समाधान के साथ, आप अपने अनुरोध के अनुसार नई पंक्तियाँ बनाकर तारीखों को विभाजित कर सकते हैं।

ध्यान दें कि फ़ंक्शन split_by_yearपंक्ति द्वारा पंक्तिबद्ध किया गया है।

कोड में मैं आपको कुछ टिप्पणियां छोड़ दूंगा।

# necessary libraries
library(dplyr)
library(lubridate)

split_by_year <- function(from, to){
    
    year_from <- year(from)
    year_to   <- year(to)
    
    # get sequence of years
    years <- seq(year_from, year_to)
    
    # create start and end date for each year
    starts <- make_date(years)  
    ends   <- make_date(years, 12, 31)
    
    # set starts and ends together, replace limits with from and end
    dates <- sort(c(starts, ends))
    dates[c(1, length(dates))] <- c(from, to)
    
    # recreate dataframe with columns from and to
    m <- matrix(dates, ncol = 2, byrow = TRUE)
    colnames(m) <- c("from", "to")
    mutate_all(as_tibble(m), as_date)
    
}

sick_leave %>%
    rowwise() %>% # next line will be performed row by row
    summarise(id = id, split_by_year(from, to)) %>% 
    mutate(sick_days = as.numeric(to - from + 1))

आउटपुट:

# A tibble: 20 x 4
      id from       to         sick_days
   <dbl> <date>     <date>         <dbl>
 1     1 2018-01-01 2018-12-31       365
 2     1 2019-01-01 2019-12-31       365
 3     1 2020-01-01 2020-10-03       277
 4     2 2016-01-01 2016-12-31       366
 5     2 2017-01-01 2017-12-31       365
 6     2 2018-01-01 2018-12-31       365
 7     2 2019-01-01 2019-12-31       365
 8     2 2020-01-01 2020-12-31       366
 9     2 2021-01-01 2021-01-01         1
10     3 2018-01-02 2018-06-02       152
11     3 2018-07-02 2018-12-31       183
12     4 2018-10-02 2018-12-31        91
13     4 2019-01-01 2019-02-02        33
14     4 2019-12-31 2019-12-31         1
15     4 2020-01-01 2020-12-31       366
16     4 2021-01-01 2021-01-01         1
17     5 2017-10-02 2017-12-31        91
18     5 2018-01-01 2018-05-20       140
19     6 2021-03-02 2021-12-31       305
20     7 2016-01-01 2016-06-05       157
1 Wimpel Aug 17 2020 at 15:46

आपका प्रश्न एक XY- समस्या जैसा लगता है ।
इसके बाद, मैंने वर्ष के अंतराल को बनाना बंद कर दिया, और सीधे आपके वांछित उत्तर पर चला गया: प्रति वर्ष प्रति दिन बीमारी की गणना ।।

वांछित आउटपुट के लिए अद्यतन किया गया .. नीचे कोड जोड़ा गया देखें

नमूना डेटा

#create sample data
library( data.table)
library( lubridate )
sick_leave <- data.table::fread(' 
 id, from, to
  1, "1/1/2018", "3/10/2020"
  2, "1/1/2016", "1/1/2021"
  3, "2/1/2018", "2/6/2018"
  3, "2/7/2018", "31/12/2018"
  4, "2/10/2018", "2/2/2019"
  4, "31/12/2019", "1/1/2021"
  5, "2/10/2017", "20/5/2018"
  6, "2/3/2021", "31/12/2021"
  7, "1/1/2016", "5/6/2016"')
#set dates as real dates
cols = c("from", "to")
sick_leave[, (cols) := lapply( .SD, as.Date, format = "%d/%m/%Y"), .SDcols = cols ]

कोड

#if your data is in data.frame / tibble format, use 
data.table::setDT( sick_leave ) 
#to make it a data.table

#create table from min-date to max_date
DT <- data.table( from = seq( min( sick_leave$from, na.rm = TRUE ), max( sick_leave$to, na.rm = TRUE ),
                                    by = "1 days") )
DT[, to := from + lubridate::days(1) ]

#set keys
setkey( sick_leave, from, to )
setkey( DT, from, to )
#perform overlap join
ans <- foverlaps( sick_leave, DT )
#summarise
ans <- ans[, .(days_sick = .N), by = .(id, year = lubridate::year(from) )]
#cast to wide
dcast( ans, id ~ year, value.var = "days_sick", fill = 0 )

उत्पादन

#    id 2016 2017 2018 2019 2020 2021
# 1:  1    0    1  365  365  277    0
# 2:  2  366  365  365  365  366    1
# 3:  3    0    0  337    0    0    0
# 4:  4    0    0   92   35  366    1
# 5:  5    0   92  140    0    0    0
# 6:  6    0    0    0    0    0  306
# 7:  7  157    0    0    0    0    0

अद्यतन वांछित उत्पादन मिलान

कोड

#if your data is in data.frame / tibble format, use 
data.table::setDT( sick_leave ) 
#to make it a data.table

#make data-table with years
DT <- data.table( from = seq( as.Date("2000-01-01"), length.out = 30, by = "1 year"),
                  to   = seq( as.Date("2000-12-31"), length.out = 30, by = "1 year") )
#set keys
setkey( sick_leave, from, to ); setkey( DT, from, to )
#perform overlap join
ans <- foverlaps( sick_leave, DT )
#choose keep the right columns (start/end)
ans[ from < i.from, from := i.from ]
ans[ to > i.to, to := i.to ]
#cleaning
ans[, `:=`(i.from = NULL, i.to = NULL)][]
#order
setorder( ans, id, from )
#calculate duration
ans[, `:=`( year   = lubridate::year( from ),
            wanted = to - from + 1) ]

उत्पादन

#           from         to id year   wanted
#  1: 2018-01-01 2018-12-31  1 2018 365 days
#  2: 2019-01-01 2019-12-31  1 2019 365 days
#  3: 2020-01-01 2020-10-03  1 2020 277 days
#  4: 2016-01-01 2016-12-31  2 2016 366 days
#  5: 2017-01-01 2017-12-31  2 2017 365 days
#  6: 2018-01-01 2018-12-31  2 2018 365 days
#  7: 2019-01-01 2019-12-31  2 2019 365 days
#  8: 2020-01-01 2020-12-31  2 2020 366 days
#  9: 2021-01-01 2021-01-01  2 2021   1 days
# 10: 2018-01-02 2018-06-02  3 2018 152 days
# 11: 2018-07-02 2018-12-31  3 2018 183 days
# 12: 2018-10-02 2018-12-31  4 2018  91 days
# 13: 2019-01-01 2019-02-02  4 2019  33 days
# 14: 2019-12-31 2019-12-31  4 2019   1 days
# 15: 2020-01-01 2020-12-31  4 2020 366 days
# 16: 2021-01-01 2021-01-01  4 2021   1 days
# 17: 2017-10-02 2017-12-31  5 2017  91 days
# 18: 2018-01-01 2018-05-20  5 2018 140 days
# 19: 2021-03-02 2021-12-31  6 2021 305 days
# 20: 2016-01-01 2016-06-05  7 2016 157 days