¿Cómo agregar datos por minuto durante una semana en medios por hora?

15

¿Cómo obtendrías los medios por hora para múltiples columnas de datos, durante un período diario, y mostrarías los resultados de doce "Hosts" en el mismo gráfico? Es decir, me gustaría graficar cómo se ve un período de 24 horas, para una semana de datos. El objetivo final sería comparar dos conjuntos de estos datos, antes y después de los muestreos.

            dates         Host CPUIOWait CPUUser CPUSys
1 2011-02-11 23:55:12     db       0      14      8
2 2011-02-11 23:55:10     app1     0       6      1
3 2011-02-11 23:55:09     app2     0       4      1

He podido ejecutar xyplot (CPUUser ~ date | Host) con buen efecto. Sin embargo, en lugar de mostrar cada fecha de la semana, me gustaría que el eje X sea las horas del día.

Intentar obtener estos datos en un objeto xts produce errores como "order.by requiere un objeto basado en el tiempo apropiado"

Aquí hay un str () del marco de datos:

'data.frame':   19720 obs. of  5 variables:
$ dates    : POSIXct, format: "2011-02-11 23:55:12" "2011-02-11 23:55:10" ...
$ Host     : Factor w/ 14 levels "app1","app2",..: 9 7 5 4 3 10 6 8 2 1 ...  
$ CPUIOWait: int  0 0 0 0 0 0 0 0 0 0 ...
$ CPUUser  : int  14 6 4 4 3 10 4 3 4 4 ...
$ CPUSys   : int  8 1 1 1 1 3 1 1 1 1 ...

ACTUALIZACIÓN: Solo para referencia futura, decidí ir con un diagrama de caja, para mostrar tanto la mediana como los "valores atípicos".

Esencialmente:

Data$hour <- as.POSIXlt(dates)$hour  # extract hour of the day
boxplot(Data$CPUUser ~ Data$hour)    # for a subset with one host or for all hosts
xyplot(Data$CPUUser ~ Data$hour | Data$Host, panel=panel.bwplot, horizontal=FALSE)

Gracias

Scott Hoffman
fuente
Supongo que obtienes esos errores xts()porque la datescolumna es un factor.
Joshua Ulrich
Soy realmente nuevo en R ... Creé la columna de fechas a partir de la función strptime. Los datos originales son de read.csv.
Scott Hoffman
1
Veamos str()el data.frame.
Roman Luštrik
@Roman Gracias por la función str (), no estaba al tanto de eso. Entonces, al deshacerme de la columna Factor, puedo generar un objeto xts como este, x <-xts (d [, 3: 5], order.by = d [, 1]). Luego pude presentar una solicitud por hora, lo que acorta los datos de 19720 objetos a 480. No estoy seguro de si esto me llevará a donde quiero, pero creo que ahora estoy más cerca.
Scott Hoffman

Respuestas:

14

Aquí hay un enfoque que usa cut () para crear los factores horarios apropiados y ddply () de la biblioteca plyr para calcular las medias.

library(lattice)
library(plyr)

## Create a record and some random data for every 5 seconds 
## over two days for two hosts.
dates <- seq(as.POSIXct("2011-01-01 00:00:00", tz = "GMT"),
             as.POSIXct("2011-01-02 23:59:55", tz = "GMT"),
             by = 5)
hosts <- c(rep("host1", length(dates)), rep("host2", 
           length(dates)))
x1    <- sample(0:20, 2*length(dates), replace = TRUE)
x2    <- rpois(2*length(dates), 2)
Data  <- data.frame(dates = dates, hosts = hosts, x1 = x1, 
                    x2 = x2)

## Calculate the mean for every hour using cut() to define 
## the factors and ddply() to calculate the means. 
## getmeans() is applied for each unique combination of the
## hosts and hour factors.
getmeans  <- function(Df) c(x1 = mean(Df$x1), 
                            x2 = mean(Df$x2))
Data$hour <- cut(Data$dates, breaks = "hour")
Means <- ddply(Data, .(hosts, hour), getmeans)
Means$hour <- as.POSIXct(Means$hour, tz = "GMT")

## A plot for each host.
xyplot(x1 ~ hour | hosts, data = Means, type = "o",
       scales = list(x = list(relation = "free", rot = 90)))
Jason Morgan
fuente
Gracias por esto ... Creo que podría tener que reformular la pregunta o hacer una nueva. Mirando esta pregunta stats.stackexchange.com/questions/980/… , ahora creo que obtener los medios no es exactamente lo que busco.
Scott Hoffman
@JVM ¿Puede explicar cómo funciona la función getmeans y por qué no usó las funciones mean o colMeans?
Scott Hoffman
1
La función ddply () corta el conjunto de datos original en subconjuntos definidos por hosts y hora. Luego los pasa a getmeans () como data.frame. Para su tarea, usar colMeans () probablemente funcionaría bien, pero probablemente primero deba eliminar las columnas que no necesita. Lo bueno de usar ddply () de esta manera es que puede calcular cualquier estadística arbitraria por la que pueda estar interesado; por ejemplo, sd (), range (), etc.
Jason Morgan
6

La agregación también funciona sin usar zoo(con datos aleatorios de 2 variables durante 3 días y 4 hosts como de JWM). Supongo que tiene datos de todos los hosts para cada hora.

nHosts <- 4  # number of hosts
dates  <- seq(as.POSIXct("2011-01-01 00:00:00"),
              as.POSIXct("2011-01-03 23:59:30"), by=30)
hosts  <- factor(sample(1:nHosts, length(dates), replace=TRUE),
                 labels=paste("host", 1:nHosts, sep=""))
x1     <- sample(0:20, length(dates), replace=TRUE)  # data from 1st variable
x2     <- rpois(length(dates), 2)                    # data from 2nd variable
Data   <- data.frame(dates=dates, hosts=hosts, x1=x1, x2=x2)

No estoy del todo seguro si desea promediar solo dentro de cada hora, o dentro de cada hora durante todos los días. Yo haré las dos cosas.

Data$hFac <- droplevels(cut(Data$dates, breaks="hour"))
Data$hour <- as.POSIXlt(dates)$hour  # extract hour of the day

# average both variables over days within each hour and host
# formula notation was introduced in R 2.12.0 I think
res1 <- aggregate(cbind(x1, x2) ~ hour + hosts, data=Data, FUN=mean)
# only average both variables within each hour and host
res2 <- aggregate(cbind(x1, x2) ~ hFac + hosts, data=Data, FUN=mean)

El resultado se ve así:

> head(res1)
  hour hosts        x1       x2
1    0 host1  9.578431 2.049020
2    1 host1 10.200000 2.200000
3    2 host1 10.423077 2.153846
4    3 host1 10.241758 1.879121
5    4 host1  8.574713 2.011494
6    5 host1  9.670588 2.070588

> head(res2)
                 hFac hosts        x1       x2
1 2011-01-01 00:00:00 host1  9.192308 2.307692
2 2011-01-01 01:00:00 host1 10.677419 2.064516
3 2011-01-01 02:00:00 host1 11.041667 1.875000
4 2011-01-01 03:00:00 host1 10.448276 1.965517
5 2011-01-01 04:00:00 host1  8.555556 2.074074
6 2011-01-01 05:00:00 host1  8.809524 2.095238

Tampoco estoy completamente seguro sobre el tipo de gráfico que desea. Aquí está la versión básica de un gráfico para solo la primera variable con líneas de datos separadas para cada host.

# using the data that is averaged over days as well
res1L <- split(subset(res1, select="x1"), res1$hosts)
mat1  <- do.call(cbind, res1L)
colnames(mat1) <- levels(hosts)
rownames(mat1) <- 0:23
matplot(mat1, main="x1 per hour, avg. over days", xaxt="n", type="o", pch=16, lty=1)
axis(side=1, at=seq(0, 23, by=2))
legend(x="topleft", legend=colnames(mat1), col=1:nHosts, lty=1)

El mismo gráfico para los datos que solo se promedian en cada hora.

res2L <- split(subset(res2, select="x1"), res2$hosts)
mat2  <- do.call(cbind, res2L)
colnames(mat2) <- levels(hosts)
rownames(mat2) <- levels(Data$hFac)
matplot(mat2, main="x1 per hour", type="o", pch=16, lty=1)
legend(x="topleft", legend=colnames(mat2), col=1:nHosts, lty=1)
lince
fuente
Buena respuesta, muchas cosas con las que no estoy familiarizado, así que necesito probarlo. Aún así, mirando mis datos con sus métodos, creo que también necesito mostrar los puntos altos de mis datos. Gracias
Scott Hoffman
2

Puede verificar la aggregate.zoofunción desde el paquete zoo: http://cran.r-project.org/web/packages/zoo/zoo.pdf

Charlie

Charlie
fuente
¿Me pueden ayudar a entender por qué obtengo NA cuando ejecuto esto?
Scott Hoffman
Hola Scott, en realidad no he usado la aggregate.zoofunción, aunque sí he usado el zoopaquete. ¿Se aseguró de que su objeto fuera zooprimero un objeto? La documentación que señalé debería ayudarlo allí.
Charlie