Создание уникальных групп в последовательных данных, которые повторяются во времени

Подобные вещи уже задавались, но не совсем так, как я могу найти.

Тема о создании последовательных идентификаторов, с несколькими дополнительными ссылками

Нетрудно создать идентификаторы в последовательности, но мои данные содержат временный элемент, который бросил меня в цикл. Следующие данные являются воображаемым набором данных, чтобы проиллюстрировать проблему в чем-то:

    dput(walking_dat)
structure(list(neighborhood = structure(c(3L, 3L, 3L, 3L, 3L, 
2L, 2L, 2L, 2L, 2L, 1L, 1L, 1L), .Label = c("Dinkytown", "Downtown", 
"Uptown"), class = "factor"), street = structure(c(4L, 3L, 3L, 
5L, 3L, 4L, 6L, 7L, 4L, 4L, 1L, 2L, 1L), .Label = c("12thAve", 
"14thAve", "Dupont", "Hennepin", "Lyndale", "Marquette", "Nicolette"
), class = "factor"), sequence = c(1, 2, 3, 4, 5, 1, 2, 3, 4, 
5, 1, 2, 3), visit = c(1, 1, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1, 2)), .Names = c("neighborhood", 
"street", "sequence", "visit"), row.names = c(NA, -13L), class = "data.frame")

   neighborhood    street sequence visit
1        Uptown  Hennepin        1     1
2        Uptown    Dupont        2     1
3        Uptown    Dupont        3     1
4        Uptown   Lyndale        4     1
5        Uptown    Dupont        5     2
6      Downtown  Hennepin        1     1
7      Downtown Marquette        2     1
8      Downtown Nicolette        3     1
9      Downtown  Hennepin        4     2
10     Downtown  Hennepin        5     2
11    Dinkytown   12thAve        1     1
12    Dinkytown   14thAve        2     1
13    Dinkytown   12thAve        3     2

Все данные ради воображения получены от трех человек, идущих на восток в трех кварталах Миннеаполиса. Каждая строка представляет время, когда их местоположение было записано. Первый столбец - это район, по которому они идут. Второй столбец - это пересечение, где они были расположены в каждый момент времени. Третий столбец - это последовательность появления этих данных.

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


Я думал это ave() с FUN=seq_along трюк может сработать, но я не могу найти способ объединить факторы, которые приводят меня туда, где я хочу быть.

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


Обновление: решение Уве работает, но не работает, если кто-то решит остаться на одном перекрестке для всех измерений, что и случилось, когда я попытался представить это в реальных данных. Если это происходит, то исходное количество строк не возвращается в итоговую таблицу data.table. Посмотрите, что здесь происходит:

dput(walking_dat_2)
structure(list(neighborhood = structure(c(3L, 3L, 3L, 3L, 3L, 
2L, 2L, 2L, 2L, 2L, 1L, 1L, 1L), .Label = c("Dinkytown", "Downtown", 
"Uptown"), class = "factor"), street2 = structure(c(2L, 2L, 2L, 
2L, 2L, 2L, 3L, 4L, 2L, 2L, 1L, 1L, 1L), .Label = c("12thAve", 
"Hennepin", "Marquette", "Nicolette"), class = "factor"), sequence = c(1, 
2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3), visit_2 = c(1, 1, 1, 1, 
1, 1, 1, 1, 2, 2, 1, 1, 1)), .Names = c("neighborhood", "street2", 
"sequence", "visit_2"), row.names = c(NA, -13L), class = "data.frame")

   neighborhood   street2 sequence visit_2
1        Uptown  Hennepin        1       1
2        Uptown  Hennepin        2       1
3        Uptown  Hennepin        3       1
4        Uptown  Hennepin        4       1
5        Uptown  Hennepin        5       1
6      Downtown  Hennepin        1       1
7      Downtown Marquette        2       1
8      Downtown Nicolette        3       1
9      Downtown  Hennepin        4       2
10     Downtown  Hennepin        5       2
11    Dinkytown   12thAve        1       1
12    Dinkytown   12thAve        2       1
13    Dinkytown   12thAve        3       1

в этом случае работающее решение Уве возвращает только 6 строк.

library(data.table)
setDT(walking_dat)[, visit_2 := rleid(neighborhood, street2)][
     , unique(.SD, by = "visit_2")][
         , visit_2 := rowid(neighborhood, street2)][
             walking_dat, on = .(neighborhood, street2, sequence), roll = TRUE, visit_2 := x.visit_2][]

   neighborhood   street2 sequence visit visit_2
1:       Uptown  Hennepin        1     1       1
2:     Downtown  Hennepin        1     2       1
3:     Downtown Marquette        2     3       1
4:     Downtown Nicolette        3     4       1
5:     Downtown  Hennepin        4     5       2
6:    Dinkytown   12thAve        1     6       1

2 ответа

Решение

Сложность заключается в том, что последующие записи на той же улице в том же районе должны рассматриваться как одно посещение. Для этого необходимо свернуть эти ряды в один, посчитать посещения разных районов и улиц и, наконец, расширить это до исходного числа рядов.

Обратите внимание, что столбец visit ожидаемый результат не перезаписывается, а сохраняется для сравнения с вычисленным visit_new колонка.

library(data.table)
setDT(walking_dat)[, visit_new := rleid(neighborhood, street)][
  , unique(.SD, by = "visit_new")][
    , visit_new := rowid(neighborhood, street)][
      walking_dat, on = .(neighborhood, street, sequence), roll = TRUE, .SD]
    neighborhood    street sequence visit visit_new
 1:       Uptown  Hennepin        1     1         1
 2:       Uptown    Dupont        2     1         1
 3:       Uptown    Dupont        3     1         1
 4:       Uptown   Lyndale        4     1         1
 5:       Uptown    Dupont        5     2         2
 6:     Downtown  Hennepin        1     1         1
 7:     Downtown Marquette        2     1         1
 8:     Downtown Nicolette        3     1         1
 9:     Downtown  Hennepin        4     2         2
10:     Downtown  Hennepin        5     2         2
11:    Dinkytown   12thAve        1     1         1
12:    Dinkytown   14thAve        2     1         1
13:    Dinkytown   12thAve        3     2         2

Пояснение шаг за шагом

DF приведен к data.table. rleid() Функция создает уникальные номера для изменения района и улицы.

 setDT(walking_dat)[, visit_new := rleid(neighborhood, street)][]
    neighborhood    street sequence visit visit_new
 1:       Uptown  Hennepin        1     1         1
 2:       Uptown    Dupont        2     1         2
 3:       Uptown    Dupont        3     1         2
 4:       Uptown   Lyndale        4     1         3
 5:       Uptown    Dupont        5     2         4
 6:     Downtown  Hennepin        1     1         5
 7:     Downtown Marquette        2     1         6
 8:     Downtown Nicolette        3     1         7
 9:     Downtown  Hennepin        4     2         8
10:     Downtown  Hennepin        5     2         8
11:    Dinkytown   12thAve        1     1         9
12:    Dinkytown   14thAve        2     1        10
13:    Dinkytown   12thAve        3     2        11

Обратите внимание, что строки 2 и 3 повторяются так же, как строки 9 и 10. Дубликаты удаляются на следующем шаге, который создает новый временный объект data.table:

setDT(walking_dat)[, visit_new := rleid(neighborhood, street)][
  , unique(.SD, by = "visit_new")][]
    neighborhood    street sequence visit visit_new
 1:       Uptown  Hennepin        1     1         1
 2:       Uptown    Dupont        2     1         2
 3:       Uptown   Lyndale        4     1         3
 4:       Uptown    Dupont        5     2         4
 5:     Downtown  Hennepin        1     1         5
 6:     Downtown Marquette        2     1         6
 7:     Downtown Nicolette        3     1         7
 8:     Downtown  Hennepin        4     2         8
 9:    Dinkytown   12thAve        1     1         9
10:    Dinkytown   14thAve        2     1        10
11:    Dinkytown   12thAve        3     2        11

Теперь мы можем подсчитать количество посещений отдельных районов и улиц, используя rowid() функция:

setDT(walking_dat)[, visit_new := rleid(neighborhood, street)][
  , unique(.SD, by = "visit_new")][
    , visit_new := rowid(neighborhood, street)][]
    neighborhood    street sequence visit visit_new
 1:       Uptown  Hennepin        1     1         1
 2:       Uptown    Dupont        2     1         1
 3:       Uptown   Lyndale        4     1         1
 4:       Uptown    Dupont        5     2         2
 5:     Downtown  Hennepin        1     1         1
 6:     Downtown Marquette        2     1         1
 7:     Downtown Nicolette        3     1         1
 8:     Downtown  Hennepin        4     2         2
 9:    Dinkytown   12thAve        1     1         1
10:    Dinkytown   14thAve        2     1         1
11:    Dinkytown   12thAve        3     2         2

Наконец, нам нужно снова расширить результат до исходного числа строк. Это достигается путем последовательного соединения временной таблицы данных с исходной DF (все строки включены):

setDT(walking_dat)[, visit_new := rleid(neighborhood, street)][
  , unique(.SD, by = "visit_new")][
    , visit_new := rowid(neighborhood, street)][
      walking_dat, on = .(neighborhood, street, sequence), roll = TRUE, .SD]

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

Новый набор данных

Фиксированный код работает также со вторым набором данных, предоставленным OP:

walking_dat_2 <-
structure(list(neighborhood = structure(c(3L, 3L, 3L, 3L, 3L, 
2L, 2L, 2L, 2L, 2L, 1L, 1L, 1L), .Label = c("Dinkytown", "Downtown", 
"Uptown"), class = "factor"), street = structure(c(2L, 2L, 2L, 
2L, 2L, 2L, 3L, 4L, 2L, 2L, 1L, 1L, 1L), .Label = c("12thAve", 
"Hennepin", "Marquette", "Nicolette"), class = "factor"), sequence = c(1, 
2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3), visit = c(1, 1, 1, 1, 1, 
1, 1, 1, 2, 2, 1, 1, 1), visit_new = c(1L, 1L, 1L, 1L, 1L, 2L, 
3L, 4L, 5L, 5L, 6L, 6L, 6L)), .Names = c("neighborhood", "street", 
"sequence", "visit", "visit_new"), row.names = c(NA, -13L), class = "data.frame")

setDT(walking_dat_2)[, visit_new := rleid(neighborhood, street)][
  , unique(.SD, by = "visit_new")][
    , visit_new := rowid(neighborhood, street)][
      walking_dat_2, on = .(neighborhood, street, sequence), 
      roll = TRUE, .SD]
    neighborhood    street sequence visit visit_new
 1:       Uptown  Hennepin        1     1         1
 2:       Uptown  Hennepin        2     1         1
 3:       Uptown  Hennepin        3     1         1
 4:       Uptown  Hennepin        4     1         1
 5:       Uptown  Hennepin        5     1         1
 6:     Downtown  Hennepin        1     1         1
 7:     Downtown Marquette        2     1         1
 8:     Downtown Nicolette        3     1         1
 9:     Downtown  Hennepin        4     2         2
10:     Downtown  Hennepin        5     2         2
11:    Dinkytown   12thAve        1     1         1
12:    Dinkytown   12thAve        2     1         1
13:    Dinkytown   12thAve        3     1         1
# Not required, but convenient:
walking_dat$combo <- paste(walking_dat$neighborhood, walking_dat$street)

# Place holder:
walking_dat$visit <- NA

# Create it:
for(i in 1:nrow(walking_dat)){
  if(i %in% row.names(walking_dat[with(walking_dat, c(TRUE, diff(as.numeric(interaction(neighborhood, street))) != 0)), ])){
    walking_dat$visit[i] <- sum(walking_dat$combo[with(walking_dat, c(TRUE, diff(as.numeric(interaction(neighborhood, street))) != 0))][1:i]==walking_dat$combo[i], na.rm=T)
  } else{
    walking_dat$visit[i] <- 1
  }
}

walking_dat
   neighborhood    street sequence visit              combo
1        Uptown  Hennepin        1     1    Uptown Hennepin
2        Uptown    Dupont        2     1      Uptown Dupont
3        Uptown    Dupont        3     1      Uptown Dupont
4        Uptown   Lyndale        4     1     Uptown Lyndale
5        Uptown    Dupont        5     2      Uptown Dupont
6      Downtown  Hennepin        1     1  Downtown Hennepin
7      Downtown Marquette        2     1 Downtown Marquette
8      Downtown Nicolette        3     1 Downtown Nicolette
9      Downtown  Hennepin        4     2  Downtown Hennepin
10     Downtown  Hennepin        5     1  Downtown Hennepin
11    Dinkytown   12thAve        1     2  Dinkytown 12thAve
12    Dinkytown   14thAve        2     1  Dinkytown 14thAve
13    Dinkytown   12thAve        3     2  Dinkytown 12thAve
Другие вопросы по тегам