Como agregar dados por minuto durante uma semana em médias horárias?

15

Como você obteria meios horários para várias colunas de dados, por um período diário, e mostraria resultados para doze "hosts" no mesmo gráfico? Ou seja, eu gostaria de representar graficamente como é um período de 24 horas, por uma semana de dados. O objetivo final seria comparar dois conjuntos desses dados, antes e depois das amostragens.

            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

Consegui executar o xyplot (CPUUser ~ datas | Host) com bom efeito. No entanto, em vez de mostrar cada data da semana, eu gostaria que o eixo X fosse as horas do dia.

Tentar inserir esses dados em um objeto xts resulta em erros como "order.by requer um objeto baseado em tempo apropriado"

Aqui está um str () do quadro de dados:

'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 ...

ATUALIZAÇÃO: Apenas para referência futura, eu decidi ir com um boxplot, para mostrar a mediana e os 'outliers'.

Essencialmente:

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)

obrigado

Scott Hoffman
fonte
Suponho que você receba esses erros xts()porque a datescoluna é um fator.
Joshua Ulrich
Eu sou realmente novo em R ... Eu criei a coluna de datas a partir da função strptime. Os dados originais são de read.csv.
Scott Hoffman
1
Vamos ver str()o data.frame.
Roman Luštrik
@ Roman Obrigado pela função str (), eu não estava ciente disso. Então, me livrando da coluna Fator, posso gerar um objeto xts como este, x <-xts (d [, 3: 5], order.by = d [, 1]). Consegui, então, aplicar-me a.hourly, que reduz os dados de 19720 objetos para 480. Não tenho certeza se isso me levará aonde eu quero, mas acho que estou mais perto agora.
21811 Scott Hoffman

Respostas:

14

Aqui está uma abordagem usando cut () para criar os fatores horários apropriados e ddply () da biblioteca plyr para calcular as médias.

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
fonte
Obrigado por isso ... acho que talvez seja necessário reformular a pergunta ou fazer uma nova. Olhando para esta pergunta stats.stackexchange.com/questions/980/… , agora acho que obter os meios não é exatamente o que estou procurando.
Scott Hoffman
@JVM Você pode explicar como a função getmeans funciona e por que você não usou apenas as funções mean ou colMeans?
Scott Hoffman
1
A função ddply () corta o conjunto de dados original em subconjuntos definidos por hosts e hora. Depois, passa-os para getmeans () como data.frame. Para sua tarefa, o uso de colMeans () provavelmente funcionaria bem, mas você provavelmente precisaria primeiro remover as colunas que não precisa. O bom de usar ddply () dessa maneira é que você pode calcular qualquer estatística arbitrária pela qual possa estar interessado; por exemplo, sd (), intervalo (), etc.
Jason Morgan
6

A agregação também funciona sem o uso zoo(com dados aleatórios de 2 variáveis ​​por 3 dias e 4 hosts como no JWM). Presumo que você tenha dados de todos os hosts a 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)

Não tenho certeza se você deseja calcular a média apenas dentro de cada hora ou dentro de cada hora durante todos os dias. Eu vou fazer as duas coisas.

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)

O resultado fica assim:

> 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

Também não tenho muita certeza sobre o tipo de gráfico que você deseja. Aqui está a versão básica de um gráfico apenas para a primeira variável com linhas de dados 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)

O mesmo gráfico para os dados que são calculados como média apenas a 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)
caracal
fonte
Boa resposta, muitas por lá que eu não estou familiarizado, então preciso experimentá-la. Ainda assim, olhando meus dados com seus métodos, acho que preciso mostrar os pontos altos dos meus dados também. Obrigado
Scott Hoffman
2

Você pode fazer o checkout da aggregate.zoofunção no pacote zoo: http://cran.r-project.org/web/packages/zoo/zoo.pdf

Charlie

Charlie
fonte
Você pode me ajudar a entender por que estou recebendo NAs ao executar isso?
Scott Hoffman
Oi Scott, eu realmente não usei a aggregate.zoofunção, embora tenha usado o zoopacote. Você se certificou de que seu objeto fosse zooprimeiro? A documentação que eu apontei deve ajudá-lo lá.
18711 Charlie