2016-05-27 20 views
6

Ho un set di dati che sembra come il seguente:Data roll-up in R

ID FromDate ToDate SiteID Cost 
    1 8/12/2014 8/31/2014 12 245.98 
    1 9/1/2014 9/7/2014 12 269.35 
    1 10/10/2014 10/17/2014 12 209.98 
    1 11/22/2014 11/30/2014 12 309.12 
    1 12/1/2014 12/11/2014 12 202.14 
    2 8/16/2014 8/21/2014 12 109.35 
    2 8/22/2014 8/24/2014 14 44.12 
    2 9/25/2014 9/29/2014 12 98.75 
    3 9/15/2014 9/30/2014 23 536.27 
    3 10/1/2014 10/31/2014 12 529.87 
    3 11/1/2014 11/30/2014 12 969.55 
    3 12/1/2014 12/12/2014 12 607.35 

Quello che vorrei questo a guardare come è:

ID FromDate ToDate SiteID Cost 
    1 8/12/2014 9/7/2014 12 515.33 
    1 10/10/2014 10/17/2014 12 209.98 
    1 11/22/2014 12/11/2014 12 511.26 
    2 8/16/2014 8/21/2014 12 109.35 
    2 8/22/2014 8/24/2014 14 44.12 
    2 9/25/2014 9/29/2014 12 98.75 
    3 9/15/2014 9/30/2014 23 536.27 
    3 10/1/2014 12/12/2014 12 2106.77 

Come si può vedere, le date sono arrotolati se c'è una continuazione e i costi sono riassunti per ID e SiteID. Per aiutare qualcuno a capire la complessità, se c'è una continuazione nell'intervallo di date, ma il SiteID cambia, allora è una riga separata. Se non c'è continuazione nell'intervallo di date, è una riga separata. Come posso farlo in R? Inoltre, ho oltre 100.000 ID individuali. Quindi qual è il modo/pacchetto più efficiente da usare per questo?

risposta

6

Questo potrebbe fare

df %>% 
    mutate(gr = cumsum(FromDate-lag(ToDate, default=1) != 1)) %>% 
    group_by(gr, ID, SiteID) %>% 
    summarise(FromDate = min(FromDate), 
      ToDate = max(ToDate), 
      cost  = sum(Cost)) 


    gr ID SiteID FromDate  ToDate cost 
    (int) (int) (int)  (date)  (date) (dbl) 
1  1  1  12 2014-08-12 2014-09-07 515.33 
2  2  1  12 2014-10-10 2014-10-17 209.98 
3  3  1  12 2014-11-22 2014-12-11 511.26 
4  4  2  12 2014-08-16 2014-08-21 109.35 
5  4  2  14 2014-08-22 2014-08-24 44.12 
6  5  2  12 2014-09-25 2014-09-29 98.75 
7  6  3  23 2014-09-15 2014-09-30 536.27 
8  6  3  12 2014-10-01 2014-12-12 2106.77 

con data.table

library(data.table) 
setDT(df) 
df[, gr := cumsum(FromDate - shift(ToDate, fill=1) != 1), 
    ][, list(FromDate=min(FromDate), ToDate=max(ToDate), cost=sum(Cost)), by=.(gr, ID, SiteID)] 



    gr ID SiteID FromDate  ToDate cost 
1: 1 1  12 2014-08-12 2014-09-07 515.33 
2: 2 1  12 2014-10-10 2014-10-17 209.98 
3: 3 1  12 2014-11-22 2014-12-11 511.26 
4: 4 2  12 2014-08-16 2014-08-21 109.35 
5: 4 2  14 2014-08-22 2014-08-24 44.12 
6: 5 2  12 2014-09-25 2014-09-29 98.75 
7: 6 3  23 2014-09-15 2014-09-30 536.27 
8: 6 3  12 2014-10-01 2014-12-12 2106.77 
+1

Mi piace molto questo approccio - come semplificare a: 'df%>% mutate (crit = FromDate-lag (ToDate, default = 1) == 1, gr = cumsum (crit == FALSE))% >% group_by (gr, ID, SiteID)%>% riassumere (costo = somma (cost), FromDate = min (FromDate), todate = max (tODATE)) ' – JasonAizkalns

+0

Perché questo codice cadere il "ID "Colonna? – akash87

+0

@JasonAizkalns Grazie. Questo è chiaramente meglio. – Khashaa

2

Ecco un modo con dplyr e tidyr - probabilmente un paio di opportunità per pulire questo in su, ma la premessa è quella di creare un nuovo indicatore di gruppo. Qualcuno con alcune migliori abilità di data.table può probabilmente trovare qualcosa di carino per questo.

library(dplyr) 
library(tidyr) 

df$FromDate <- lubridate::mdy(df$FromDate) 
df$ToDate <- lubridate::mdy(df$ToDate) 

gather(df, Date, Val, -c(ID, SiteID, Cost)) %>% 
    arrange(ID, SiteID, Val, Date) %>% 
    group_by(ID, SiteID) %>% 
    mutate(lagDateDiff = as.integer(Val - lag(Val)), 
     indicator = ifelse(Date == "ToDate" | is.na(lagDateDiff), 0, 
          ifelse((Date == "FromDate" & lagDateDiff == 1), 0, 1)), 
     newGroup = cumsum(indicator)) %>% # Run to here to see intermediate result 
    select(-lagDateDiff, -indicator) %>% 
    spread(Date, Val) %>% 
    group_by(ID, SiteID, newGroup) %>% 
    summarise(Min_From_Date = min(FromDate), 
      Max_To_Date = max(ToDate), 
      Sum_Cost = sum(Cost)) 

#  ID SiteID newGroup Min_From_Date Max_To_Date Sum_Cost 
# (int) (int) (dbl)  (date)  (date) (dbl) 
# 1  1  12  0 2014-08-12 2014-09-07 515.33 
# 2  1  12  1 2014-10-10 2014-10-17 209.98 
# 3  1  12  2 2014-11-22 2014-12-11 511.26 
# 4  2  12  0 2014-08-16 2014-08-21 109.35 
# 5  2  12  1 2014-09-25 2014-09-29 98.75 
# 6  2  14  0 2014-08-22 2014-08-24 44.12 
# 7  3  12  0 2014-10-01 2014-12-12 2106.77 
# 8  3  23  0 2014-09-15 2014-09-30 536.27 
+0

non ho familiarità con l'%>% notazione. Potresti fornire un link o una documentazione in merito? – akash87

+0

'%>%' proviene dal [pacchetto 'magrittr'] (https://cran.r-project.org/web/packages/magrittr/vignettes/magrittr.html). In breve, è noto come operatore "pipe", con cui si reindirizza un valore in un'espressione o una chiamata. Invece di 'f (x)' possiamo scrivere 'x%>% f' che rende più facile leggere e mantenere certe catene di codice. – JasonAizkalns