Создание уникальных групп в последовательных данных, которые повторяются во времени
Подобные вещи уже задавались, но не совсем так, как я могу найти.
Тема о создании последовательных идентификаторов, с несколькими дополнительными ссылками
Нетрудно создать идентификаторы в последовательности, но мои данные содержат временный элемент, который бросил меня в цикл. Следующие данные являются воображаемым набором данных, чтобы проиллюстрировать проблему в чем-то:
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