2016-05-27 15 views
6

Ich habe einen Datensatz, wie folgt aussieht:Datum 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 

Was ich würde das so aussehen mag, ist:

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 

Wie kann man die Daten sehen, werden aufgerollt, wenn es eine Fortsetzung gibt und die Kosten durch ID und SiteID summiert werden. Um jemandem zu helfen, die Komplexität zu verstehen, wenn es eine Fortsetzung des Datumsintervalls gibt, sich aber die SiteID ändert, handelt es sich um eine separate Zeile. Wenn das Datumsintervall nicht fortgeführt wird, handelt es sich um eine separate Zeile. Wie mache ich das in R? Außerdem habe ich über 100.000 individuelle IDs. Was ist der effizienteste Weg/Paket dafür?

Antwort

6

könnte dies tun

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 

mit 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

Ich mag diesen Ansatz viel besser - wie wäre es mit der Vereinfachung zu: 'df%>% mutieren (crit = FromDate-lag (ToDate, Standard = 1) == 1, gr = cumsum (crit == FALSCH))% >% group_by (gr, ID, SiteID)%>% summarize (Kosten = sum (Kosten), Fromdate = min (Fromdate), ToDate = max (ToDate)) ' – JasonAizkalns

+0

Warum fallen dieser Code die„ID " Säule? – akash87

+0

@JasonAizkalns Danke. Das ist eindeutig besser. – Khashaa

2

Hier ist eine Möglichkeit mit dplyr und tidyr - wahrscheinlich ein paar Möglichkeiten, dies zu bereinigen, aber die Prämisse ist es, einen neuen Gruppenindikator zu erstellen. Jemand mit etwas besseren data.table Fähigkeiten kann wahrscheinlich etwas ziemlich glattes für diesen einen kommen.

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

Ich bin nicht vertraut mit dem%>% Notation. Können Sie einen Link oder eine Dokumentation dazu bereitstellen? – akash87

+0

'%>%' kommt aus dem ['magritrtrack] (https://cran.r-project.org/web/packages/magrittr/vignettes/magrittr.html). Kurz gesagt, es ist bekannt als ein "Pipe" -ähnlicher Operator, mit dem Sie einen Wert vorwärts in einen Ausdruck oder Aufruf leiten. Anstelle von 'f (x)' können wir 'x%>% f' schreiben, wodurch bestimmte Code-Ketten leichter zu lesen und zu pflegen sind. – JasonAizkalns