Агрегирование (подсчет) вхождений значений за произвольный период - PullRequest
3 голосов
/ 23 сентября 2011

У меня есть CSV-файл с временными метками и определенными типами событий, которые произошли в это время.Я хочу посчитать количество вхождений определенных типов событий с 6-минутными интервалами.

Входные данные выглядят так:

date,type
"Sep 22, 2011 12:54:53.081240000","2"
"Sep 22, 2011 12:54:53.083493000","2"
"Sep 22, 2011 12:54:53.084025000","2"
"Sep 22, 2011 12:54:53.086493000","2"

Я загружаю и лечу данные этимкусок кода:

> raw_data <- read.csv('input.csv')
> cured_dates <- c(strptime(raw_data$date, '%b %d, %Y %H:%M:%S', tz="CEST"))
> cured_data <- data.frame(cured_dates, c(raw_data$type))
> colnames(cured_data) <- c('date', 'type')

После отверждения данные выглядят так:

> head(cured_data)
                 date type
1 2011-09-22 14:54:53    2
2 2011-09-22 14:54:53    2
3 2011-09-22 14:54:53    2
4 2011-09-22 14:54:53    2
5 2011-09-22 14:54:53    1
6 2011-09-22 14:54:53    1

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

date                       type   count
2011-09-22 14:54:00 CEST   1      11
2011-09-22 14:54:00 CEST   2      19
2011-09-22 15:00:00 CEST   1      9
2011-09-22 15:00:00 CEST   2      12
2011-09-22 15:06:00 CEST   1      23
2011-09-22 15:06:00 CEST   2      18

Агрегатная функция зоопарка выглядит многообещающе, я нашел этот фрагмент кода:

# aggregate POSIXct seconds data every 10 minutes
tt <- seq(10, 2000, 10)
x <- zoo(tt, structure(tt, class = c("POSIXt", "POSIXct")))
aggregate(x, time(x) - as.numeric(time(x)) %% 600, mean)

Теперь мне просто интересно, как я могу применить этов моем случае использования.

Наивный, как я пытался:

> zoo_data <- zoo(cured_data$type, structure(cured_data$time, class = c("POSIXt", "POSIXct")))
> aggr_data = aggregate(zoo_data$type, time(zoo_data$time), - as.numeric(time(zoo_data$time)) %% 360, count)
Error in `$.zoo`(zoo_data, type) : not possible for univariate zoo series

Я должен признать, что не совсем уверен в R, но я стараюсь.: -)

Я немного потерян.Может ли кто-нибудь указать мне правильное направление?

Спасибо большое!Приветствия, Алекс.

Вот вывод dput для небольшого подмножества моих данных.Сами данные - это что-то около 80 миллионов строк.

structure(list(date = structure(c(1316697885, 1316697885, 1316697885, 
1316697885, 1316697885, 1316697885, 1316697885, 1316697885, 1316697885, 
1316697885, 1316697885, 1316697885, 1316697885, 1316697885, 1316697885, 
1316697885, 1316697885, 1316697885, 1316697885, 1316697885, 1316697885, 
1316697885, 1316697885), class = c("POSIXct", "POSIXt"), tzone = ""), 
    type = c(2L, 2L, 2L, 2L, 1L, 1L, 1L, 2L, 1L, 2L, 1L, 2L, 
    1L, 2L, 1L, 1L, 1L, 2L, 1L, 1L, 2L, 1L, 2L)), .Names = c("date", 
"type"), row.names = c(NA, -23L), class = "data.frame")

Ответы [ 2 ]

3 голосов
/ 23 сентября 2011

Мы можем прочитать его с помощью read.csv, преобразовать первый столбец в дату и время, разделенные на 6 минут, и добавить фиктивный столбец из 1. Затем перечитайте его, используя read.zoo, разбив по типу и агрегируя по пустому столбцу:

# test data

Lines <- 'date,type
"Sep 22, 2011 12:54:53.081240000","2"
"Sep 22, 2011 12:54:53.083493000","2"
"Sep 22, 2011 12:54:53.084025000","2"
"Sep 22, 2011 12:54:53.086493000","2"
"Sep 22, 2011 12:54:53.081240000","3"
"Sep 22, 2011 12:54:53.083493000","3"
"Sep 22, 2011 12:54:53.084025000","3"
"Sep 22, 2011 12:54:53.086493000","4"'

library(zoo)
library(chron)

# convert to chron and bin into 6 minute bins using trunc
# Also add a dummy column of 1's 
# and remove any leading space (removing space not needed if there is none)

DF <- read.csv(textConnection(Lines), as.is = TRUE)
fmt <- '%b %d, %Y %H:%M:%S'
DF <- transform(DF, dummy = 1,
         date = trunc(as.chron(sub("^ *", "", date), format = fmt), "00:06:00"))

# split and aggregate

z <- read.zoo(DF, split = 2, aggregate = length)

С приведенными выше данными испытаний решение выглядит следующим образом:

> z
                    2 3 4
(09/22/11 12:54:00) 4 3 1

Обратите внимание, что вышеизложенное было сделано в широкой форме, поскольку эта форма представляет собой временной ряд, тогда как длинная форма - нет. Существует один столбец для каждого типа. В наших тестовых данных у нас были типы 2, 3 и 4, поэтому есть три столбца.

(Мы использовали chron здесь, поскольку его метод trunc хорошо подходит для биннинга по 6-минутным группам. Chron не поддерживает часовые пояса, что может быть преимуществом, поскольку вы не можете сделать одну из многих возможных ошибок часового пояса, но если вы хотите, чтобы POSIXct в любом случае конвертировал его в конце, например, time(z) <- as.POSIXct(paste(as.Date.dates(time(z)), times(time(z)) %% 1)). Это выражение показано в таблице в одной из статей R News 4/1, за исключением того, что мы использовали as.Date.dates вместо просто as.Date, чтобы обойти ошибку это, кажется, было введено с тех пор. Мы могли бы также использовать time(z) <- as.POSIXct(time(z)), но это привело бы к другому часовому поясу.)

EDIT:

Исходное решение сгруппировано по датам, но впоследствии я заметил, что вы хотите разбить на 6-минутные периоды, чтобы решение было пересмотрено.

EDIT:

Пересмотрено на основе комментария.

2 голосов
/ 23 сентября 2011

Ты почти весь там. Все, что вам нужно сделать сейчас, это создать версию этих данных в zoo-isch и сопоставить ее с кодом aggregate.zoo. Поскольку вы хотите классифицировать как по времени, так и по типу, ваш второй аргумент для aggregate.zoo должен быть немного более сложным, и вам нужно количество, а не средние значения, поэтому вы должны использовать length (). Я не думаю, что count - это базовая функция R или zoo, и единственная функция count, которую я вижу в своем рабочем пространстве, происходит от pkg: plyr, поэтому я не знаю, насколько хорошо она будет работать с aggregate.zoo. length работает, как большинство людей ожидают от векторов, но часто удивляет людей при работе с data.frames. Если вы не получаете то, что хотите, с length, то вы должны увидеть, работает ли вместо него NROW (и с вашим макетом данных они оба преуспеют): с новым объектом данных необходимо сначала поставить аргумент типа. И это сводит агрегирование / zoo к обработке только классификаторов одной категории, поэтому вам нужно добавить as.vector, чтобы удалить его zoo-ness:

with(cured_data, 
     aggregate(as.vector(x), list(type = type, 
                                   interval=as.factor(time(x) - as.numeric(time(x)) %% 360)),
                             FUN=NROW) 
 )

#  interval            x 
#1 2011-09-22 09:24:00 12
#2 2011-09-22 09:24:00 11

Это пример, модифицированный откуда вы взяли код (пример для SO от WizaRd Dirk): Совокупность (количество) значений за произвольный период времени

tt <- seq(10, 2000, 10)
x <- zoo(tt, structure(tt, class = c("POSIXt", "POSIXct")))
aggregate(as.vector(x), by=list(cat=as.factor(x), 
     tms = as.factor(index(x) - as.numeric(index(x)) %% 600)), length)

   cat                 tms  x
1    1 1969-12-31 19:00:00 26
2    2 1969-12-31 19:00:00 22
3    3 1969-12-31 19:00:00 11
4    1 1969-12-31 19:10:00 17
5    2 1969-12-31 19:10:00 28
6    3 1969-12-31 19:10:00 15
7    1 1969-12-31 19:20:00 17
8    2 1969-12-31 19:20:00 16
9    3 1969-12-31 19:20:00 27
10   1 1969-12-31 19:30:00  8
11   2 1969-12-31 19:30:00  4
12   3 1969-12-31 19:30:00  9
...