Совокупность (подсчет) вхождений значений за произвольный период времени

У меня есть файл 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

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

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

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

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

person Alexander Janssen    schedule 23.09.2011    source источник
comment
Прежде всего, спасибо за все ответы! Теперь я собираюсь просмотреть различные подсказки, которые вы предоставили, и дам вам знать, как далеко я продвинулся.   -  person Alexander Janssen    schedule 23.09.2011


Ответы (2)


Мы можем прочитать его, используя read.csv, преобразовать первый столбец в дату и время, разделенные на 6-минутные интервалы, и добавить фиктивный столбец из единиц. Затем перечитайте его, используя 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)), но это приведет к другому часовому поясу.)

РЕДАКТИРОВАТЬ:

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

РЕДАКТИРОВАТЬ:

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

person G. Grothendieck    schedule 23.09.2011
comment
Read.ag(mean) в cbind() немного сбивает с толку; Я прогнал немного больше данных, теперь также со строками данных, где тип = 1, и в итоге получил суть .github.com/d779b0546765b7640804 . Я действительно не хочу агрегировать среднее значение, но хочу использовать что-то вроде COUNT() в SQL для разных значений типа (тип может быть любым целым числом от 1 до 5). - person Alexander Janssen; 23.09.2011

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

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
person IRTFM    schedule 23.09.2011
comment
Эй, пока это выглядит не так уж плохо, но он показывает мне только агрегированные данные для type=1: gist. github.com/8049f54780cf0f18147b Хммммм! Я посмотрю подробнее. - person Alexander Janssen; 23.09.2011
comment
Старайтесь лучше представлять свои данные, и вы получите более быстрые, качественные и проверенные ответы. Посмотрите на функцию dput. - person IRTFM; 23.09.2011
comment
Извините за неточность, я ценю ваши усилия. Я добавил вывод dput к своему исходному сообщению. - person Alexander Janssen; 23.09.2011
comment
Все эти «даты» одинаковы. Я думал, вам нужен какой-то ряд вычислений? И я поверил вам на слово, что агрегатный код работал так, как вы хотели, но вы так и не указали, откуда он взялся. - person IRTFM; 23.09.2011
comment
Да, только в этой части серии. Весь временной интервал составляет около 45 минут (это статистика входа/выхода из интернет-провайдера), и каждую секунду приходится около 200-400 строк либо с типом = 1 (начало запроса учета RADIUS), либо с типом = 2 (остановка запроса учета RADIUS). Я хотел бы знать, сколько Start/Stop за 6-минутный таймфрейм. Необработанные данные имеют время с микросекундной точностью. - person Alexander Janssen; 23.09.2011