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

Я работаю с рыбой с электронной меткой. Фрагмент моих данных телеметрии (фрейм данных "d") приведен ниже. Каждая временная метка представляет собой обнаружение уникальной рыбы.

TagID          Detection              Location      RiverKm
163            02/23/2012 03:17:44    Alcatraz_E     4.414
163            02/23/2012 03:56:25    Alcatraz_E     4.414
163            04/14/2012 15:10:20    Alcatraz_E     4.414
163            04/14/2012 15:12:11    Alcatraz_N     4.414
163            03/11/2012 08:59:48    Alcatraz_N     4.414
163            03/11/2012 09:02:15    Alcatraz_N     4.414
163            03/11/2012 09:04:05    Alcatraz_N     4.414
163            03/11/2012 09:04:06    Alcatraz_N     4.414
163            03/11/2012 09:06:09    Alcatraz_N     4.414
163            03/11/2012 09:06:11    Alcatraz_E     4.414

Там много разных TagID (отдельных рыб). Я хотел бы разделить обнаружения на периоды встречи для каждой рыбы, указав время начала («прибытие») и время окончания («отъезд») с критическим значением 1 час. Например, для вышеупомянутой рыбы (TagID 163) вывод будет таким:

TagID       arrival                  departure            Location        RiverKm
163        02/23/2012 03:17:44    02/23/2012 03:56:25     Alcatraz_E       4.414 
163        04/14/2012 15:10:2     04/14/2012 15:12:11     Alcatraz_N       4.414
163        03/11/2012 08:59:48    03/11/2012 09:06:11     Alcatraz_E       4.414

Я хотел бы создать цикл (или любую другую структуру кода), которая делает следующее:

for j in 1:length(unique(d$TagID))
  1. Определите время первого обнаружения («t1»)
  2. ЕСЛИ следующее обнаружение этого тега во временном ряду («t2») происходит менее чем через час после t1, пропустите его и перейдите к следующему обнаружению; ИНАЧЕ, поместите t1 в вектор "прибытия" и t2 в "вектор отправления".
  3. Остановиться, когда каждая метка времени прибытия и отправления будет классифицирована для каждого TagID.

Я понятия не имею, как сделать это наиболее эффективным способом, и был бы очень признателен за вашу помощь.

Благодарю вас!


person Von    schedule 08.10.2014    source источник


Ответы (2)


Сначала вы должны упорядочить данные по дате. Вот почему вы должны преобразовать свою переменную Detection в допустимый тип r datetime: POSIXct. как только ваши данные упорядочены, используя diff и cumsum, вы можете создать группирующую переменную для обнаружения перехода: здесь переход происходит по крайней мере через час (60 минут). Я использую data.table для синтаксиса сахара в операциях группировки, но в этом нет необходимости, особенно если у вас нет большого количества данных.

Вот мой полный код:

library(data.table)
## data coerecion
d$Detection <- 
  as.POSIXct(strptime(d$Detection,'%m/%d/%Y %H:%M:%S'))
## sort using Detecetion
d <- d[order(d$Detection),]
# id is incrementing variable that detects a jump of an hour
d$id <- cumsum(c(F,round(diff(d$Detection)/60) >60))
## you don't mention how to choose location,Riverkm so I take by default the first ones
setDT(d)[,list(start   =Detection[1],
               end     =Detection[length(Detection)],
               Location=Location[1],
               RiverKm =RiverKm[1]),
         "TagID,id"]

#    TagID id               start                 end   Location RiverKm
# 1:   163  0 2012-02-23 03:17:44 2012-02-23 03:56:25 Alcatraz_E   4.414
# 2:   163  1 2012-03-11 08:59:48 2012-03-11 09:06:11 Alcatraz_N   4.414
# 3:   163  2 2012-04-14 15:10:20 2012-04-14 15:12:11 Alcatraz_E   4.414
person agstudy    schedule 08.10.2014
comment
спасибо за вашу работу над этим, я ценю оба подхода. - person Von; 10.10.2014

Вот аналогичный подход с dplyr (версия 0.3). Я отредактировал свои коды с новыми функциями из 0.3.

# If you need to download the latest development version
if (packageVersion("devtools") < 1.6) {
install.packages("devtools")
}
devtools::install_github("hadley/lazyeval")
devtools::install_github("hadley/dplyr")

library(dplyr)

foo <- data.frame(
    TagID = rep(c(163:164), each = 10),
    Detection = rep(c("02/23/2012 03:17:44", "02/23/2012 03:56:25", "04/14/2012 15:10:20",
                  "04/14/2012 15:12:11", "03/11/2012 08:59:48", "03/11/2012 09:02:15",
                  "03/11/2012 09:04:05", "03/11/2012 09:04:06", "03/11/2012 09:06:09",
                  "03/11/2012 09:06:11"), times = 2),
    Location = rep(c("Alcatraz_E", "Alcatraz_E", "Alcatraz_E", "Alcatraz_N", "Alcatraz_N",
                 "Alcatraz_N", "Alcatraz_N", "Alcatraz_N", "Alcatraz_N", "Alcatraz_E"),times = 2),
    RiverKm = 4.414,
    stringsAsFactors = FALSE)

foo$Detection <- as.POSIXct(strptime(foo$Detection,'%m/%d/%Y %H:%M:%S'))

foo %>%
    arrange(TagID, Detection) %>%
    group_by(TagID, id = cumsum(!duplicated(TagID) | c(F,round(diff(Detection)/60) > 60))) %>%
    slice(c(1,length(Detection))) %>%
    mutate(Departure = Detection[2]) %>%
    slice(1) %>%
    ungroup 


#  TagID           Detection   Location RiverKm id           Departure
#1   163 2012-02-23 03:17:44 Alcatraz_E   4.414  0 2012-02-23 03:56:25
#2   163 2012-03-11 08:59:48 Alcatraz_N   4.414  1 2012-03-11 09:06:11
#3   163 2012-04-14 15:10:20 Alcatraz_E   4.414  2 2012-04-14 15:12:11
#4   164 2012-02-23 03:17:44 Alcatraz_E   4.414  0 2012-02-23 03:56:25
#5   164 2012-03-11 08:59:48 Alcatraz_N   4.414  1 2012-03-11 09:06:11
#6   164 2012-04-14 15:10:20 Alcatraz_E   4.414  2 2012-04-14 15:12:11
person jazzurro    schedule 09.10.2014
comment
Я ценю использование dplyr — приятно знать, что это возможно без цикла for. Однако похоже, что возвращается только список первых обнаружений (приходов), без отправлений. Есть ли способ сохранить окончательную отметку времени (время отправления)? - person Von; 09.10.2014
comment
@Von Извините, я невнимательно прочитал ваш вопрос. Позвольте мне пересмотреть это. - person jazzurro; 09.10.2014
comment
@Von Я пересмотрел этот сценарий. В конце концов, подход data.table требует гораздо меньшего набора текста. - person jazzurro; 09.10.2014
comment
Понял. Спасибо!! Больше печатать, но, возможно, это лучший подход для расширения функциональности в конечном итоге. - person Von; 10.10.2014
comment
@Von Это зависит от вас, но подход agstudy'а быстрее и короче. - person jazzurro; 10.10.2014
comment
@agstudy в конечном итоге я хотел бы расширить эту функцию, чтобы разделить встречи на время суток (рассвет, закат, день, ночь), состояние реки (прилив, отлив) и т. д. Я слышал, что dplyr был хорошим способом сделай это. Это все, что я имел в виду. Поскольку я задаю вопрос, очевидно, я ничего не знаю - я не хотел никого обидеть. - person Von; 11.10.2014
comment
@agstudy Все хорошо. Я совсем не обиделся. Я оценил твой подход. Мне было чему поучиться. В настоящее время я изучаю data.table, и вы научили меня чему-то, чего я не знал. Для этой задачи data.table предлагает очень простой подход. Спасибо. - person jazzurro; 12.10.2014
comment
@Von Изучив новые функции в dplyr 0.3, я обновил свой код. Я использовал slice. Я также сжал часть кода, добавив часть id = cumsum... в первую часть group_by. - person jazzurro; 16.10.2014
comment
@jazzurro круто! Сейчас я работаю над написанием фактической функции - я опубликую окончательный сценарий, когда это будет сделано. - person Von; 16.10.2014
comment
@jazurro как вы думаете, вы могли бы напечатать словами, что именно делает вторая строка кода? Больше всего меня смущает F... - person Von; 24.10.2014
comment
@Von Я уже иду спать. Но эта штука F идентична Agstudy. F ЛОЖЬ. Я думаю, что запуск небольших фрагментов кода позволит вам увидеть, что происходит. Я и сам так сделал. - person jazzurro; 24.10.2014
comment
@Von Если у вас есть еще вопросы, дайте мне знать. - person jazzurro; 26.10.2014