Как агрегировать по минутам данные за неделю в почасовые средства?

15

Как бы вы получили почасовые средние значения для нескольких столбцов данных за ежедневный период и показывали результаты для двенадцати "хостов" на одном графике? То есть я хотел бы наметить, как выглядит 24-часовой период для данных за недели. Конечной целью будет сравнение двух наборов этих данных до и после выборок.

            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

Я смог запустить xyplot (CPUUser ~ date | Host) с хорошим эффектом. Однако вместо того, чтобы показывать каждую дату недели, я бы хотел, чтобы ось X была часами дня.

Попытка передать эти данные в объект xts приводит к ошибкам, таким как «order.by требует соответствующий объект на основе времени»

Вот str () фрейма данных:

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

ОБНОВЛЕНИЕ: просто для дальнейшего использования, я решил пойти с коробкой, чтобы показать и медиану, и «выбросы».

По существу:

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)

Благодарность

Скотт Хоффман
источник
Я предполагаю, что вы получаете эти ошибки, xts()потому что datesстолбец является фактором.
Джошуа Ульрих
Я действительно новичок в R ... Я создал столбец дат из функции strptime. Исходные данные взяты из read.csv.
Скотт Хоффман
1
Давайте посмотрим str()на data.frame.
Роман Луштрик
@Roman Спасибо за функцию str (), я не знал об этом. Итак, избавившись от столбца Factor, я могу сгенерировать объект xts, подобный этому, x <-xts (d [, 3: 5], order.by = d [, 1]). Затем я смог подать заявку в час, что сокращает данные с объектов 19720 года до 480. Я не уверен, что это приведет меня туда, куда я хочу, но я думаю, что сейчас я ближе.
Скотт Хоффман

Ответы:

14

Вот один из подходов, использующих cut () для создания подходящих часовых коэффициентов и ddply () из библиотеки plyr для расчета средних значений.

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)))
Джейсон Морган
источник
Спасибо за это ... Я думаю, что мне, возможно, придется перефразировать вопрос или задать новый. Глядя на этот вопрос stats.stackexchange.com/questions/980/… , я теперь думаю, что получение средств - это не совсем то, что мне нужно.
Скотт Хоффман
@JVM Можете ли вы объяснить, как работает функция getmeans, и почему вы просто не использовали функции mean или colMeans?
Скотт Хоффман
1
Функция ddply () разрезает исходный набор данных на подмножества, определяемые хостами и часами. Затем он передает их getmeans () как data.frame. Для вашей задачи использование colMeans (), вероятно, будет работать нормально, но вам, вероятно, потребуется сначала удалить ненужные столбцы. Хорошая вещь об использовании ddply () таким образом, что вы можете вычислить любую произвольную статистику, которая вас может заинтересовать; например, sd (), range () и т. д.
Джейсон Морган
6

Агрегация также работает без использования zoo(со случайными данными из 2 переменных за 3 дня и 4 хостов, как из JWM). Я предполагаю, что у вас есть данные со всех хостов за каждый час.

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)

Я не совсем уверен, хотите ли вы усреднить только в течение каждого часа или в течение каждого часа в течение всех дней. Я сделаю оба.

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)

Результат выглядит так:

> 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

Я также не совсем уверен, какой тип графика вам нужен. Вот базовая версия графика только для первой переменной с отдельными строками данных для каждого хоста.

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

Тот же график для данных, которые усредняются только в течение каждого часа.

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)
каракал
источник
Хороший ответ, много там, с которым я не знаком, поэтому я должен попробовать это. Тем не менее, глядя на мои данные вашими методами, я думаю, что мне нужно показать и высокие моменты в моих данных. Спасибо
Скотт Хоффман
2

Вы можете проверить aggregate.zooфункцию из пакета zoo: http://cran.r-project.org/web/packages/zoo/zoo.pdf

Чарли

Чарли
источник
Можете ли вы помочь мне понять, почему я получаю АН при выполнении этого?
Скотт Хоффман
Привет Скотт, я на самом деле не использовал эту aggregate.zooфункцию, хотя я использовал zooпакет. Вы удостоверились, что Ваш объект был zooобъектом сначала? Документация, на которую я указал, должна вам помочь.
Чарли