Это сложный вопрос. Я нашел решение, которое использует cumsum()
и rowid()
, чтобы вернуть ожидаемый результат для данного образца набора данных.
library(data.table)
setDT(DT)[, loop := cumsum((ZoneOfHome == start_zone) - rowid(start_zone, end_zone) + 1L),
by = .(Household, person)][]
Household person trip ZoneOfHome start_zone end_zone loop
1: 1 1 1 22 22 13 1
2: 1 1 2 22 13 22 1
3: 1 1 3 22 22 34 2
4: 1 1 4 22 34 22 2
5: 1 2 1 22 22 13 1
6: 1 2 2 22 13 22 1
7: 2 1 1 15 15 15 1
8: 2 1 2 15 15 15 1
9: 2 1 3 15 15 45 2
10: 2 1 4 15 45 15 2
11: 3 1 1 17 6 17 0
12: 3 1 2 17 17 10 1
13: 3 1 3 17 10 17 1
Объяснение
Сначала мы создаем текущий счетчик для каждого person
в household
всякий раз, когда человек покидает свою домашнюю зону :
DT[, loop1 := cumsum(ZoneOfHome == start_zone), by = .(Household, person)][]
Household person trip ZoneOfHome start_zone end_zone loop1
1: 1 1 1 22 22 13 1
2: 1 1 2 22 13 22 1
3: 1 1 3 22 22 34 2
4: 1 1 4 22 34 22 2
5: 1 2 1 22 22 13 1
6: 1 2 2 22 13 22 1
7: 2 1 1 15 15 15 1
8: 2 1 2 15 15 15 2
9: 2 1 3 15 15 45 3
10: 2 1 4 15 45 15 3
11: 3 1 1 17 6 17 0
12: 3 1 2 17 17 10 1
13: 3 1 3 17 10 17 1
Это очень близко к ожидаемому результату, за исключением случая, когда пункт назначения поездки находится в домашней зоне. Итак, нам нужна коррекция для этого случая. Поправка основана на наблюдении, что start_zone
и end_zone
домашней зоны l oop идентичны в последующих строках. Это можно посчитать с помощью функции rowid()
, которая увеличивает счетчик при изменении одного из параметров:
DT[, corr_local := cumsum(rowid(start_zone, end_zone) - 1L), by = .(Household, person)][]
Household person trip ZoneOfHome start_zone end_zone loop1 corr_local
1: 1 1 1 22 22 13 1 0
2: 1 1 2 22 13 22 1 0
3: 1 1 3 22 22 34 2 0
4: 1 1 4 22 34 22 2 0
5: 1 2 1 22 22 13 1 0
6: 1 2 2 22 13 22 1 0
7: 2 1 1 15 15 15 1 0
8: 2 1 2 15 15 15 2 1
9: 2 1 3 15 15 45 3 1
10: 2 1 4 15 45 15 3 1
11: 3 1 1 17 6 17 0 0
12: 3 1 2 17 17 10 1 0
13: 3 1 3 17 10 17 1 0
Наконец, оба вспомогательных столбца необходимо объединить
DT[, loop := loop1 - corr_local, by = .(Household, person)][]
Household person trip ZoneOfHome start_zone end_zone loop1 corr_local loop
1: 1 1 1 22 22 13 1 0 1
2: 1 1 2 22 13 22 1 0 1
3: 1 1 3 22 22 34 2 0 2
4: 1 1 4 22 34 22 2 0 2
5: 1 2 1 22 22 13 1 0 1
6: 1 2 2 22 13 22 1 0 1
7: 2 1 1 15 15 15 1 0 1
8: 2 1 2 15 15 15 2 1 1
9: 2 1 3 15 15 45 3 1 2
10: 2 1 4 15 45 15 3 1 2
11: 3 1 1 17 6 17 0 0 0
12: 3 1 2 17 17 10 1 0 1
13: 3 1 3 17 10 17 1 0 1
Данные
library(data.table)
DT <- fread(
"Household person trip ZoneOfHome start_zone end_zone
1 1 1 22 22 13
1 1 2 22 13 22
1 1 3 22 22 34
1 1 4 22 34 22
1 2 1 22 22 13
1 2 2 22 13 22
2 1 1 15 15 15
2 1 2 15 15 15
2 1 3 15 15 45
2 1 4 15 45 15
3 1 1 17 6 17
3 1 2 17 17 10
3 1 3 17 10 17")