Find overlapping dates for each ID and create a new row for the overlap

后端 未结 2 1079
北荒
北荒 2020-12-09 13:05

I would like to find the overlapping dates for each ID and create a new row with the overlapping dates and also combine the characters (char) for the lines. It is possible t

2条回答
  •  青春惊慌失措
    2020-12-09 13:25

    Introduction

    The for-loop you added to your question and the included comparison were a good start. The should be some additional brackets ( and ) in the date comparison. This for-loop-approach automatically considers new rows in the data frame. Therefore, you can get three-, four- and more-character strings in the char column.

    Create input data

    df = as.data.frame(list('ID'=c(15, 15, 16, 17, 17, 17, 17, 17, 17, 17),
                            'date1'=as.Date(c('2003-04-05', '2003-04-20', '2001-01-02', '2003-03-05', '2005-04-15', '2007-05-15', '2008-02-05', '2010-06-07', '2010-09-22', '2012-02-28')),
                            'date2'=as.Date(c('2003-05-06', '2003-06-20', '2002-03-04', '2007-02-22', '2014-05-19', '2008-02-05', '2012-02-14', '2011-02-14', '2014-05-19', '2013-03-04')),
                            'char'=c('E', 'R', 'M', 'I', 'C', 'I', 'M', 'V', 'P', 'R')),
                       stringsAsFactors=FALSE)
    

    Solution

    Iterate all rows (that were existing in the original data.frame) and compare them to all current lines.

    nrow_init = nrow(df)
    for (i in 1:(nrow(df)-1)) {
      print(i)
      ## get rows of df that have overlapping dates
      ##   (1:nrow(df))>i :: consider only rows below the current row to avoid double processing of two row-pairs
      ##   (!grepl(df$char[i],df$char)) :: prevent double letters
      ## Because we call nrow(df) each time (and not save it as a variable once in the beginning), we consider also new rows here. Therefore, we do not need the specific procedure for comparing 3 or more rows.
      loc = ((1:nrow(df))>i) & (!grepl(df$char[i],df$char)) & (df$ID[i]==df$ID) & (((df$date1[i]>df$date1) & (df$date1[i]df$date1[i]) & (df$date1df$date1)) | ((df$date2df$date1[i])))
      ## Uncomment this line, if you want to compare only two rows each and not more
      # loc = ((1:nrow(df))<=nrow_init) & ((1:nrow(df))>i) & (df$ID[i]==df$ID) & (((df$date1[i]>df$date1) & (df$date1[i]df$date1)))
    
      ## proceed only of at least one duplicate row was found
      if (sum(loc) > 0) {
        # build new rows
        #  pmax and pmin do element-wise min and max calculation; df$date1[i] and df$date2[i] are automatically extended to the length of df$date1[loc] and df$date2[loc], respectively
        df_append = as.data.frame(list('ID'=df$ID[loc],
                                       'date1'=pmax(df$date1[i],df$date1[loc]),
                                       'date2'=pmin(df$date2[i],df$date2[loc]),
                                       'char'=paste0(df$char[i],df$char[loc])))
        ## append new rows
        df = rbind(df, df_append)
      }
    }
    
    ## create a new column and sort the characters in it
    ##  idea for sort: https://stackoverflow.com/a/5904854/4612235
    df$sort_char = df$char
    for (i in 1:nrow(df)) df$sort_char[i] = paste(sort(unlist(strsplit(df$sort_char[i], ""))), collapse = "")
    ## remove duplicates
    df = df[!duplicated(df[c('ID', 'date1', 'date2', 'sort_char')]),]
    ## remove additional column
    df$sort_char = NULL
    

    Out put

    ID      date1      date2 char
    15 2003-04-05 2003-05-06    E
    15 2003-04-20 2003-06-20    R
    16 2001-01-02 2002-03-04    M
    17 2003-03-05 2007-02-22    I
    17 2005-04-15 2014-05-19    C
    17 2007-05-15 2008-02-05    I
    17 2008-02-05 2012-02-14    M
    17 2010-06-07 2011-02-14    V
    17 2010-09-22 2014-05-19    P
    17 2012-02-28 2013-03-04    R
    15 2003-04-20 2003-05-06   ER
    17 2005-04-15 2007-02-22   IC
    17 2007-05-15 2008-02-05   CI
    17 2008-02-05 2012-02-14   CM
    17 2010-06-07 2011-02-14   CV
    17 2010-09-22 2014-05-19   CP
    17 2012-02-28 2013-03-04   CR
    17 2010-06-07 2011-02-14   MV
    17 2010-09-22 2012-02-14   MP
    17 2010-06-07 2011-02-14  MCV
    17 2010-09-22 2012-02-14  MCP
    17 2010-09-22 2011-02-14   VP
    17 2010-09-22 2011-02-14  VCP
    17 2010-09-22 2011-02-14  VMP
    17 2010-09-22 2011-02-14 VMCP
    17 2012-02-28 2013-03-04   PR
    17 2012-02-28 2013-03-04  PCR
    

提交回复
热议问题