2013-08-04 15 views
6

This question chiede informazioni sull'aggregazione per periodo di tempo in R, che i panda chiamano ricampionamento. La risposta più utile utilizza il pacchetto XTS per raggruppare per un determinato periodo di tempo, applicando alcune funzioni come sum() o mean().Aggregazione per periodo di tempo in lubridato

Uno dei commenti suggeriva che c'era qualcosa di simile in lubridato, ma non elaborato. Qualcuno può fornire un esempio idiomatico usando lubridate? Ho letto la vignetta lubridata un paio di volte e posso immaginare una combinazione di lubridate e plyr, tuttavia voglio assicurarmi che non ci sia un modo più semplice per cui mi manchi.

Per rendere l'esempio più reale, diciamo che voglio la somma giornaliera di biciclette che viaggiano in direzione nord da questo insieme di dati:

library(lubridate) 
library(reshape2) 

bikecounts <- read.csv(url("http://data.seattle.gov/api/views/65db-xm6k/rows.csv?accessType=DOWNLOAD"), header=TRUE, stringsAsFactors=FALSE) 
names(bikecounts) <- c("Date", "Northbound", "Southbound") 

dati assomiglia a questo:

> head(bikecounts) 
        Date Northbound Southbound 
1 10/02/2012 12:00:00 AM   0   0 
2 10/02/2012 01:00:00 AM   0   0 
3 10/02/2012 02:00:00 AM   0   0 
4 10/02/2012 03:00:00 AM   0   0 
5 10/02/2012 04:00:00 AM   0   0 
6 10/02/2012 05:00:00 AM   0   0 

risposta

6

Non lo so perché dovresti usare lubridate per questo. Se siete solo in cerca di qualcosa di meno impressionante di quanto XTS si potrebbe provare questo

tapply(bikecounts$Northbound, as.Date(bikecounts$Date, format="%m/%d/%Y"), sum) 

In sostanza, non vi resta che split per data, quindi applicare una funzione.


lubridate può essere utilizzato per creare un fattore di raggruppamento per problemi di applicazione di divisione. Così, per esempio, se si desidera che la somma per ogni mese (ignorando l'anno)

tapply(bikecounts$Northbound, month(mdy_hms(bikecounts$Date)), sum) 

Ma, è solo utilizzando i wrapper per le funzioni di base R, e nel caso del PO, penso che la funzione di base R as.Date è il più semplice (come dimostra il fatto che anche le altre risposte hanno ignorato la tua richiesta di usare lubridate ;-)).


Qualcosa che non era coperto dal Answer all'altro Question collegato al PO è split.xts. period.apply divide uno xts allo endpoints e applica una funzione a ciascun gruppo. È possibile trovare endpoint utili per una determinata attività con la funzione endpoints. Ad esempio, se si dispone di un oggetto xts, x, quindi endpoints(x, "months") fornirebbe i numeri di riga che sono l'ultima riga di ogni mese. split.xts sfrutta questo per dividere un oggetto xts - split(x, "months") restituirebbe un elenco di oggetti xts in cui ogni componente era per un mese diverso.

Anche se, split.xts() e endpoints() sono principalmente destinati agli oggetti xts, funzionano anche su alcuni altri oggetti, compresi i vettori basati su tempo semplice. Anche se non si desidera utilizzare XTS oggetti, è ancora possibile trovare usi per endpoints() a causa della sua convenienza o la sua velocità (implementato in C)

> split.xts(as.Date("1970-01-01") + 1:10, "weeks") 
[[1]] 
[1] "1970-01-02" "1970-01-03" "1970-01-04" 

[[2]] 
[1] "1970-01-05" "1970-01-06" "1970-01-07" "1970-01-08" "1970-01-09" 
[6] "1970-01-10" "1970-01-11" 

> endpoints(as.Date("1970-01-01") + 1:10, "weeks") 
[1] 0 3 10 

Credo che il miglior uso di lubridate a questo problema è per l'analisi del Stringhe "Date" in oggetti POSIXct. vale a dire la funzione mdy_hms in questo caso.

Ecco una soluzione xts che utilizza lubridate per analizzare le stringhe "Data".

x <- xts(bikecounts[, -1], mdy_hms(bikecounts$Date)) 
period.apply(x, endpoints(x, "days"), sum) 
apply.daily(x, sum) # identical to above 

Per questo compito specifico, xts ha anche una ottimizzata period.sum funzione (scritto in Fortran), che è molto veloce

period.sum(x, endpoints(x, "days")) 
+0

Anche questo è utile. Felice di accettare questa risposta se il consenso è "non usare lubridate, ma utilizzare XTS". Detto questo, sento un sacco di "usare il lubridato", quindi mi piacerebbe sapere quale è il problema! – Peter

+1

Sono tendenzialmente d'accordo con @GSee. Credo che il modo più semplice di "lubridare" per ottenere una variabile di raggruppamento "ddply" usando le funzioni "lubridate" sarebbe solo: "bikecounts $ date2 <- mdy_hms (x = bikecounts $ Date)"; 'bikecounts $ date3 <- round_date (x = bc $ date2, unit =" day ")'. – Henrik

+0

Grande serie di risposte da parte di tutti. Puntate su questo per 1.) correggendo la mia premessa iniziale 2.) fornendo un esempio di base R 3.) Mostrando come sarebbe una versione lubridata e 4.) spiegando i vantaggi di xts. – Peter

2

Qui è un'opzione usando data.table dopo l'importazione del csv:

library(data.table) 

# convert the data.frame to data.table 
bikecounts <- data.table(bikecounts) 

# Calculate 
bikecounts[, list(NB=sum(Northbound), SB=sum(Southbound)), by=as.Date(Date, format="%m/%d/%Y")] 

     as.Date NB SB 
    1: 2012-10-02 1165 773 
    2: 2012-10-03 1761 1760 
    3: 2012-10-04 1767 1708 
    4: 2012-10-05 1590 1558 
    5: 2012-10-06 926 1080 
---      
299: 2013-07-27 1212 1289 
300: 2013-07-28 902 1078 
301: 2013-07-29 2040 2048 
302: 2013-07-30 2314 2226 
303: 2013-07-31 2008 2076 

Nota, è anche possibile utilizzare fread() ("lettura veloce") dal pacchetto data.table per leggere in CSV in un file data.table in un unico passaggio. L'unico svantaggio consiste nel convertire manualmente la data e l'ora dalla stringa.

eg: 
bikecounts <- fread("http://data.seattle.gov/api/views/65db-xm6k/rows.csv?accessType=DOWNLOAD", header=TRUE, stringsAsFactors=FALSE) 
setnames(bikecounts, c("Date", "Northbound", "Southbound")) 
bikecounts[, Date := as.POSIXct(D, format="%m/%d/%Y %I:%M:%S %p")] 
+1

Anche questa risposta è molto buona e serve un'aggregazione molto rapida. Senza fare benchmark, scommetto che questo approccio è il più veloce. – Peter

+0

Che dire del mixing data.table con lubridate o con fasttime? – skan

2

Uso ddply dal pacchetto plyr:

library(plyr) 
bikecounts$Date<-with(bikecounts,as.Date(Date, format = "%m/%d/%Y")) 
x<-ddply(bikecounts,.(Date),summarise, sumnorth=sum(Northbound),sumsouth=sum(Southbound)) 


> head(x) 
     Date sumnorth sumsouth 
1 2012-10-02  1165  773 
2 2012-10-03  1761  1760 
3 2012-10-04  1767  1708 
4 2012-10-05  1590  1558 
5 2012-10-06  926  1080 
6 2012-10-07  951  1191 


> tail(x) 
      Date sumnorth sumsouth 
298 2013-07-26  1964  1999 
299 2013-07-27  1212  1289 
300 2013-07-28  902  1078 
301 2013-07-29  2040  2048 
302 2013-07-30  2314  2226 
303 2013-07-31  2008  2076 
1

Qui viene la richiesta soluzione lubridate, che ho anche aggiunto alla domanda collegata. Esso utilizza una combinazione di lubridate e zoo aggregata() per queste operazioni:

ts.month.sum <- aggregate(zoo.ts, month, sum) 

ts.daily.mean <- aggregate(zoo.ts, day, mean) 

ts.mins.mean <- aggregate(zoo.ts, minutes, mean) 

Ovviamente, è necessario convertire prima i dati in un oggetto zoo(), che è abbastanza facile. Puoi anche utilizzare yearmon() o yearqtr() o funzioni personalizzate per sia diviso e applicare. Questo metodo è sintatticamente dolce come quello di panda.

Problemi correlati