Comment agréger par minute les données d'une semaine en moyennes horaires?

15

Comment obtiendriez-vous des moyennes horaires pour plusieurs colonnes de données, pour une période quotidienne, et afficheriez-vous les résultats pour douze "hôtes" dans le même graphique? Autrement dit, j'aimerais représenter graphiquement à quoi ressemble une période de 24 heures, pour une semaine de données. L'objectif final serait de comparer deux ensembles de ces données, avant et après échantillonnage.

            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

J'ai pu exécuter xyplot (CPUUser ~ dates | Host) avec un bon effet. Cependant, plutôt que d'afficher chaque date de la semaine, j'aimerais que l'axe X représente les heures de la journée.

Essayer d'obtenir ces données dans un objet xts entraîne des erreurs telles que "order.by nécessite un objet temporel approprié"

Voici un str () du bloc de données:

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

MISE À JOUR: Juste pour référence future, j'ai décidé d'aller avec un boxplot, pour montrer à la fois la médiane et les «valeurs aberrantes».

Essentiellement:

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)

Merci

Scott Hoffman
la source
Je suppose que vous obtenez ces erreurs xts()parce que la datescolonne est un facteur.
Joshua Ulrich
Je suis vraiment nouveau dans R ... J'ai créé la colonne des dates à partir de la fonction strptime. Les données d'origine proviennent de read.csv.
Scott Hoffman, le
1
Voyons str()le data.frame.
Roman Luštrik
@Roman Merci pour la fonction str (), je n'en étais pas conscient. Donc, en me débarrassant de la colonne Facteur, je peux générer un objet xts comme celui-ci, x <-xts (d [, 3: 5], order.by = d [, 1]). J'ai ensuite pu postuler sur .hourly, ce qui raccourcit les données de 19720 objets à 480. Je ne sais pas si cela me mènera où je veux, mais je suis plus proche maintenant, je pense.
Scott Hoffman

Réponses:

14

Voici une approche utilisant cut () pour créer les facteurs horaires appropriés et ddply () à partir de la bibliothèque plyr pour calculer les moyennes.

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
la source
Merci pour cela ... Je pense que je pourrais avoir besoin de reformuler la question ou d'en poser une nouvelle. En regardant cette question stats.stackexchange.com/questions/980/… , je pense maintenant qu'obtenir les moyens n'est pas exactement ce que je recherche.
Scott Hoffman
@JVM Pouvez-vous expliquer comment fonctionne la fonction getmeans et pourquoi vous n'avez pas simplement utilisé les fonctions mean ou colMeans?
Scott Hoffman
1
La fonction ddply () coupe l'ensemble de données d'origine en sous-ensembles définis par les hôtes et l'heure. Il les transmet ensuite à getmeans () en tant que data.frame. Pour votre tâche, l'utilisation de colMeans () fonctionnerait probablement très bien, mais vous devrez probablement supprimer d'abord les colonnes dont vous n'avez pas besoin. La bonne chose à propos de l'utilisation de ddply () de cette façon est que vous pouvez calculer n'importe quelle statistique arbitraire qui pourrait vous intéresser; par exemple, sd (), range (), etc.
Jason Morgan
6

L'agrégation fonctionne également sans utilisation zoo(avec des données aléatoires de 2 variables pendant 3 jours et 4 hôtes comme de JWM). Je suppose que vous avez des données de tous les hôtes pour chaque heure.

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)

Je ne suis pas tout à fait sûr si vous voulez faire la moyenne juste à l'intérieur de chaque heure ou dans chaque heure sur tous les jours. Je ferai les deux.

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)

Le résultat ressemble à ceci:

> 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

Je ne suis pas non plus entièrement sûr du type de graphique que vous souhaitez. Voici la version simple d'un graphique pour la première variable uniquement avec des lignes de données distinctes pour chaque hôte.

# 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)

Le même graphique pour les données dont la moyenne n'est que dans chaque heure.

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
la source
Belle réponse, beaucoup de choses que je ne connais pas, donc je dois l'essayer. Pourtant, en regardant mes données avec vos méthodes, je pense que je dois également montrer les points forts de mes données. Merci
Scott Hoffman
2

Vous pouvez extraire la aggregate.zoofonction du package zoo: http://cran.r-project.org/web/packages/zoo/zoo.pdf

Charlie

Charlie
la source
Pouvez-vous m'aider à comprendre pourquoi j'obtiens des NA lors de l'exécution de cela?
Scott Hoffman
Salut Scott, je n'ai pas réellement utilisé la aggregate.zoofonction, bien que j'aie utilisé le zoopackage. Vous êtes-vous assuré que votre objet était un zooobjet en premier? La documentation que j'ai indiquée devrait vous y aider.
Charlie