R - Анализ раздвижных дверей # событий за период времени
Я пересылаю этот вопрос, так как думал, что мне нужен анализ кластерного типа, но для этого нужен анализ "скользящего окна". У меня есть набор данных, в котором записано 59 тыс. Записей за 63 года, мне нужно идентифицировать "кластеры" событий по следующим критериям:
Последовательность из 6 или более событий, с интервалом не более 6 часов между последовательными событиями в последовательности.
Каждое событие имеет уникальный идентификатор и отметку даты / времени, при которой выходные данные в идеале должны назначать идентификатор кластера событиям, которые соответствуют вышеуказанным критериям. Я был направлен в сторону скользящего окна, это лучший вариант для использования? может быть, используя rollapply из пакета зоопарка?
Я добавил пример данных за один год, если кто-то чувствует себя в очень полезном настроении. https://dl.dropboxusercontent.com/u/16400709/Stackru/DataStack.csv
Я видел результаты такого анализа в R, но пока не смог его воспроизвести, результаты этого анализа можно увидеть в этой статье -> https://dl.dropboxusercontent.com/u/16400709/Stackru/fuhrmann_etal_waf2014.pdf
Спасибо за ваше время!
1 ответ
Вот решение с использованием rollapply
от zoo
пакет.
require(chron)
require(zoo)
d <- read.csv("path/to/file/DataStack.csv")
d[] <- lapply(d, as.character)
d$time <- chron(d$Date, d$Time, format = c(dates = "d/m/y", times = "h:m:s"))
d <- d[order(d$time), ]
d$diffHours <- c(0, diff(d$time)) * 24
d$withinSixHr <- ifelse(d$diffHours < 6, 1, 0)
d$streak <- c(rep(NA, 5), rollapply(zoo(d$withinSixHr), width = 6, FUN = sum))
d$cluster <- ifelse(d$streak == 6, 1, 0)
d$clusterParticipant <- 0
for (i in 6:nrow(d)) {
if (d[i, "cluster"] == 1) {
d[i - 5, "clusterParticipant"] <- 1
d[i - 4, "clusterParticipant"] <- 1
d[i - 3, "clusterParticipant"] <- 1
d[i - 2, "clusterParticipant"] <- 1
d[i - 1, "clusterParticipant"] <- 1
d[i - 0, "clusterParticipant"] <- 1
}
}
И вот результат:
> head(d[c(1, 5:10)], n = 20)
EventID time diffHours withinSixHr streak cluster clusterParticipant
2 272481 (01/01/11 00:02:00) 0.0000000 1 NA NA 1
3 272666 (01/01/11 00:40:00) 0.6333333 1 NA NA 1
4 272674 (01/01/11 00:46:00) 0.1000000 1 NA NA 1
5 272701 (01/01/11 01:15:00) 0.4833333 1 NA NA 1
6 272715 (01/01/11 02:00:00) 0.7500000 1 NA NA 1
7 272720 (01/01/11 02:25:00) 0.4166667 1 6 1 1
8 272723 (01/01/11 02:56:00) 0.5166667 1 6 1 1
21 278829 (09/01/11 03:25:00) 192.4833333 0 5 0 0
1 268346 (17/01/11 10:03:00) 198.6333333 0 4 0 0
43 280736 (25/01/11 15:35:00) 197.5333333 0 3 0 0
26 279417 (25/01/11 17:15:00) 1.6666667 1 3 0 1
44 280739 (25/01/11 17:41:00) 0.4333333 1 3 0 1
45 280740 (25/01/11 18:08:00) 0.4500000 1 3 0 1
46 280751 (25/01/11 18:40:00) 0.5333333 1 4 0 1
47 280806 (25/01/11 19:09:00) 0.4833333 1 5 0 1
48 281559 (25/01/11 21:50:00) 2.6833333 1 6 1 1
14 276331 (01/02/11 06:10:00) 152.3333333 0 5 0 0
15 276336 (01/02/11 08:24:00) 2.2333333 1 5 0 0
50 281741 (01/02/11 20:06:00) 11.7000000 0 4 0 0
11 275388 (24/02/11 15:53:00) 547.7833333 0 3 0 0
РЕДАКТИРОВАТЬ: приведенный ниже код предназначен для присвоения каждому кластеру (или суперкластеру) идентификационного номера. Создает переменную clusterDiff
и использует его в качестве коммутатора, чтобы определить, есть ли изменения в статусе кластера. Это будет довольно медленно на большом наборе данных, но сработает.
d$clusterDiff <- c(d[1, "clusterParticipant"], diff(d$clusterParticipant))
d$clusterID <- as.numeric(NA)
count <- 1
inCluster <- FALSE
for (i in 1:nrow(d)) {
if (d[i, "clusterDiff"] == 1) {
d[i, "clusterID"] <- count
inCluster <- TRUE
} else if (d[i, "clusterDiff"] == -1) {
inCluster <- FALSE
count <- count + 1
} else if (inCluster == TRUE & d[i, "clusterDiff"] == 0) {
d[i, "clusterID"] <- count
} else { next }
}