2012-07-09 9 views
5

Digamos que tengo varios años de datos que se parecen a la siguienteCómo subconjunto data.frame por semanas y luego suma?

# load date package and set random seed 
library(lubridate) 
set.seed(42) 

# create data.frame of dates and income 
date <- seq(dmy("26-12-2010"), dmy("15-01-2011"), by = "days") 
df <- data.frame(date = date, 
       wday = wday(date), 
       wday.name = wday(date, label = TRUE, abbr = TRUE), 
       income = round(runif(21, 0, 100)), 
       week = format(date, format="%Y-%U"), 
       stringsAsFactors = FALSE) 

#   date wday wday.name income week 
# 1 2010-12-26 1  Sun  91 2010-52 
# 2 2010-12-27 2  Mon  94 2010-52 
# 3 2010-12-28 3  Tues  29 2010-52 
# 4 2010-12-29 4  Wed  83 2010-52 
# 5 2010-12-30 5  Thurs  64 2010-52 
# 6 2010-12-31 6  Fri  52 2010-52 
# 7 2011-01-01 7  Sat  74 2011-00 
# 8 2011-01-02 1  Sun  13 2011-01 
# 9 2011-01-03 2  Mon  66 2011-01 
# 10 2011-01-04 3  Tues  71 2011-01 
# 11 2011-01-05 4  Wed  46 2011-01 
# 12 2011-01-06 5  Thurs  72 2011-01 
# 13 2011-01-07 6  Fri  93 2011-01 
# 14 2011-01-08 7  Sat  26 2011-01 
# 15 2011-01-09 1  Sun  46 2011-02 
# 16 2011-01-10 2  Mon  94 2011-02 
# 17 2011-01-11 3  Tues  98 2011-02 
# 18 2011-01-12 4  Wed  12 2011-02 
# 19 2011-01-13 5  Thurs  47 2011-02 
# 20 2011-01-14 6  Fri  56 2011-02 
# 21 2011-01-15 7  Sat  90 2011-02 

me gustaría resumir 'ingresos' para cada semana (domingo a sábado). Actualmente hago lo siguiente:

Weekending 2011-01-01 = sum(df$income[1:7]) = 487 
Weekending 2011-01-08 = sum(df$income[8:14]) = 387 
Weekending 2011-01-15 = sum(df$income[15:21]) = 443 

Sin embargo, me gustaría un enfoque más sólido que se sume automáticamente por semana. No puedo descifrar cómo subconjunto automático de los datos en semanas. Cualquier ayuda sería muy apreciada.

+0

No agregue soluciones a las preguntas. Si desea responder su propia pregunta, hágalo en una respuesta (esto se recomienda en SO). – Andrie

+0

Ahh, vale, no sabía si eso sería una mala forma. Lo agregaré como sugieres. –

Respuesta

0

Esta solución está influenciada por @Andrie y @Chase.

# load plyr 
library(plyr) 

# format weeks as per requirement (replace "00" with "52" and adjust corresponding year) 
tmp <- list() 
tmp$y <- format(df$date, format="%Y") 
tmp$w <- format(df$date, format="%U") 
tmp$y[tmp$w=="00"] <- as.character(as.numeric(tmp$y[tmp$w=="00"]) - 1) 
tmp$w[tmp$w=="00"] <- "52" 
df$week <- paste(tmp$y, tmp$w, sep = "-") 

# get summary 
df2 <- ddply(df, .(week), summarize, income=sum(income)) 

# include week ending date 
tmp$week.ending <- lapply(df2$week, function(x) rev(df[df$week==x, "date"])[[1]]) 
df2$week.ending <- sapply(tmp$week.ending, as.character) 

#  week income week.ending 
# 1 2010-52 487 2011-01-01 
# 2 2011-01 387 2011-01-08 
# 3 2011-02 443 2011-01-15 
8

Primer uso format para convertir la fecha para los números de semana, entonces plyr::ddply() para el cálculo de los resúmenes:

library(plyr) 
df$week <- format(df$date, format="%Y-%U") 
ddply(df, .(week), summarize, income=sum(income)) 
    week income 
1 2011-52 413 
2 2012-01 435 
3 2012-02 379 

Para obtener más información sobre format.date, ver ?strptime, en particular la parte que define %U como la semana número.


EDIT:

Teniendo en cuenta los datos y requisitos modificados, una forma es dividir la fecha por 7 para obtener un número numérico que indica la semana. (O más precisamente, se divide por el número de segundos en una semana para obtener el número de semanas desde la época, que es por defecto 1970-01-01

En código:.

df$week <- as.Date("1970-01-01")+7*trunc(as.numeric(df$date)/(3600*24*7)) 
library(plyr) 
ddply(df, .(week), summarize, income=sum(income)) 

     week income 
1 2010-12-23 298 
2 2010-12-30 392 
3 2011-01-06 294 
4 2011-01-13 152 

tengo no verificado que los límites de la semana son el domingo. Deberá verificar esto e insertar un desplazamiento apropiado en la fórmula.

+0

Casi allí, vea editar en mi pregunta un problema que descubrí con este enfoque :) –

+0

@TonyBreyal He editado mi respuesta, como solicité. – Andrie

+0

gracias amablemente. Presenté mi propia solución basada en lecturas adicionales de? Format y plyr, como sugirió. Cambié el data.frame en mi pregunta para reflejar mejor lo que buscaba y creo que es por eso que los resultados no son exactamente lo que estaba buscando (después de aplicar tu código a los nuevos datos) pero al usar tu respuesta pude obtener la solución que necesitaba (la he agregado arriba). Muchas gracias, no podría haberlo hecho sin haber leído tu enfoque :) –

1

Busqué en Google "días de semana grupales en semanas R" y encontré this SO question. Menciona que tiene múltiples años, así que creo que tenemos que mantenernos al tanto con el número de la semana y también el año, por lo que modifiqué las respuestas como format(date, format = "%U%y")

En el uso que se parece a esto:

library(plyr) #for aggregating 
df <- transform(df, weeknum = format(date, format = "%y%U")) 
ddply(df, "weeknum", summarize, suminc = sum(income)) 
#---- 
    weeknum suminc 
1 1152 413 
2 1201 435 
3 1202 379 

Ver ?strptime para todas las abreviaturas de formato.

+0

Casi allí, por favor mira editar en mi pregunta por un problema que vi con este enfoque :) –

+0

@TonyBreyal - parece que Andrie me golpeó al golpe y tiene una respuesta más sólida. Además, la respuesta de Dwin en la pregunta que he vinculado anteriormente también se encuentra en esta línea. Aclamaciones. – Chase

+0

gracias amablemente por el enlace. Lo vi antes, pero no pude entender cómo se aplicaría a mi requisito de permitir que una semana cruzara el límite del año. Ahora tengo la solución y aprecio tu ayuda :) –

1

Trate rollapply del paquete zoo:

rollapply(df$income, width=7, FUN = sum, by = 7) 
# [1] 487 387 443 

O bien, utilizar period.sum del xts paquete:

period.sum(xts(df$income, order.by=df$date), which(df$wday %in% 7)) 
#   [,1] 
# 2011-01-01 487 
# 2011-01-08 387 
# 2011-01-15 443 

O, para obtener la salida en el formato que desee:

data.frame(income = period.sum(xts(df$income, order.by=df$date), 
           which(df$wday %in% 7)), 
      week = df$week[which(df$wday %in% 7)]) 
#   income week 
# 2011-01-01 487 2011-00 
# 2011-01-08 387 2011-01 
# 2011-01-15 443 2011-02 

Tenga en cuenta que la primera semana se muestra como 2011-00 porque así es como se ingresa en sus datos.También puede usar week = df$week[which(df$wday %in% 1)] que coincida con su salida.

6

Esto ahora es simple usando dplyr. También sugeriría usar cut(breaks = "week") en lugar de format() para cortar las fechas en semanas.

library(dplyr) 
df %>% group_by(week = cut(date, "week")) %>% mutate(weekly_income = sum(income)) 
0

df.index = [ 'semanas'] df #El la variable dt como índice

df.resample ('W'). Sum() #sum usando volver a muestrear

0

Con dplyr :

df %>% 
    arrange(date) %>% 
    mutate(week = as.numeric(date - date[1])%/%7) %>% 
    group_by(week) %>% 
    summarise(weekincome= sum(income)) 

En lugar de la fecha [1], puede tener cualquier fecha desde la que desee comenzar su estudio semanal.

Cuestiones relacionadas