Эффективное преобразование "журналов времени отдельных входов / выходов" в "общую занятость здания за определенное время"
Итак, у меня есть данные в формате.csv, показывающие время, за которое конкретные пользователи заходят в здание и выходят из него в течение нескольких месяцев. Я пытаюсь использовать R для расчета занятости здания каждые 15-30 минут для анализа.
Данные были очищены и находятся в форме большого ffdf
фрейм данных (~11 миллионов записей). Фрейм данных имеет numeric
а также factor
типы (включает строки символов и числа, которые потенциально могут быть полезны позже), а время включения / выключения указывается в столбцах, отформатированных как POSIXct
,
Если бы это был намного меньший набор данных, я бы сделал следующее:
- Создайте пустой файл.csv (т.е.
occupancy
) для хранения уровня занятости со временем в качестве заголовков столбцов и датой в виде строк. - Используйте цикл for для итерации следующего по всем строкам:
- Рассчитать общее время в здании (часы - время во времени)
- Извлечь дату из записи о времени, сохранить как
inDate
- использование
round_any
отplyr
пакет, чтобы найти ближайший 15-минутный потолок для времени начала, хранить какnearest15
- Найти количество завершенных 15-минутных блоков, которые здание заняло пользователем, через
floor(as.numeric((clockouttime - clockintime)/15))
- Добавьте 1 к соответствующему количеству временных блоков, в которых находился пользователь, начиная с
occupancy[inDate, nearest15]
,
Однако цикл for, который перебирает 11 миллионов строк, не будет эффективным вообще.
Кто-нибудь знает, как это сделать эффективно? Я в растерянности - apply
Насколько я знаю, семейство функций приведет все данные в один тип. Нет необходимости в особых командах, если вы не знакомы с ними, я просто хотел бы, чтобы кто-то указал мне правильный пакет и общую идею для реализации.
я использую ff
для доступа к данным в настоящее время, но если есть лучшие пакеты, которые могут сделать это, я открыт для предложений.
Благодарю.
РЕДАКТИРОВАТЬ: вот отредактированный фрагмент кода, на который я смотрю:
user_hash, section_hash, dept_id, col_a, col_b, clockin_datetime, clockout_datetime
EEDD1DA7F38CA42A35CF3C003B,85C7,TS,1,,2013-08-08 12:52:00,2013-08-08 23:00:00
2BCB6AA1603BB4357BC0D390C9,BFA3,VS,1,,2013-08-08 12:48:00,2013-08-08 22:58:00
46D859B55C4802DF51445025C5,943B,TS,1,,2013-08-08 11:58:00,2013-08-08 16:04:00
FE4EEA83AF6EA50CA5738B5610,00B3,VT,1,,2013-08-08 19:56:00,2013-08-08 23:04:00
8DB43D322F0AEF6D2B877862C3,DB1F,TS,1,,2013-08-08 12:49:00,2013-08-08 13:03:00
4E636571D425A74CA6B5FA7909,1860,VS,1,,2013-08-08 12:21:00,2013-08-08 14:01:00
26B41FA581408BDFD747234640,FDA4,VS,1,,2013-08-08 20:38:00,2013-08-08 23:03:00
A6C3C190BFFDCB4194774C1026,45C0,VT,1,,2013-08-08 12:58:00,2013-08-08 20:03:00
938506D977353EA65DC6BB5260,1819,VT,1,,2013-08-08 12:54:00,2013-08-08 16:01:00
E82F9350DA9FFC73EE6A66A286,04C1,VT,1,,2013-08-08 08:42:00,2013-08-08 12:45:00
6B92F1AB6B3EE193430B6B2793,6C2E,TS,1,,2013-08-08 09:58:00,2013-08-08 13:03:00
2B88836D8A4CA5183AAE5D3D9A,497C,TS,2,,2013-08-08 10:35:00,2013-08-08 16:06:00
Желаемый результат, который я имею в виду, примерно такой, хотя любая форма, которая показывает мне занятость в любой заданный период времени / дату, подойдет.
date 12.00 12.15 12.30 12.45 .......
2013-08-01 1344 1632 3742 1024
2013-08-02 342 435 435 435
2013-08-03
2013-08-04
...
1 ответ
Я работал с подобными данными в прошлом и обнаружил, что реорганизация данных может помочь. Во-первых, я буду предполагать, что ваши даты правильно закодированы как значения даты, а ваши данные образца находятся в файле data.frame. dd
, Например
dd <- structure(list(user_hash = structure(c(11L, 3L, 4L, 12L, 7L,
5L, 1L, 9L, 8L, 10L, 6L, 2L), .Label = c("26B41FA581408BDFD747234640",
"2B88836D8A4CA5183AAE5D3D9A", "2BCB6AA1603BB4357BC0D390C9", "46D859B55C4802DF51445025C5",
"4E636571D425A74CA6B5FA7909", "6B92F1AB6B3EE193430B6B2793", "8DB43D322F0AEF6D2B877862C3",
"938506D977353EA65DC6BB5260", "A6C3C190BFFDCB4194774C1026", "E82F9350DA9FFC73EE6A66A286",
"EEDD1DA7F38CA42A35CF3C003B", "FE4EEA83AF6EA50CA5738B5610"), class = "factor"),
section_hash = structure(c(8L, 10L, 9L, 1L, 11L, 4L, 12L,
5L, 3L, 2L, 7L, 6L), .Label = c("00B3", "04C1", "1819", "1860",
"45C0", "497C", "6C2E", "85C7", "943B", "BFA3", "DB1F", "FDA4"
), class = "factor"), dept_id = structure(c(1L, 2L, 1L, 3L,
1L, 2L, 2L, 3L, 3L, 3L, 1L, 1L), .Label = c("TS", "VS", "VT"
), class = "factor"), col_a = c(1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 2L), col_b = c(NA, NA, NA, NA, NA, NA, NA,
NA, NA, NA, NA, NA), clockin_datetime = structure(c(1375980720,
1375980480, 1375977480, 1376006160, 1375980540, 1375978860,
1376008680, 1375981080, 1375980840, 1375965720, 1375970280,
1375972500), class = c("POSIXct", "POSIXt"), tzone = ""),
clockout_datetime = structure(c(1376017200, 1376017080, 1375992240,
1376017440, 1375981380, 1375984860, 1376017380, 1376006580,
1375992060, 1375980300, 1375981380, 1375992360), class = c("POSIXct",
"POSIXt"), tzone = "")), .Names = c("user_hash", "section_hash",
"dept_id", "col_a", "col_b", "clockin_datetime", "clockout_datetime"
), row.names = c(NA, -12L), class = "data.frame")
Теперь, если вы упорядочите данные так, чтобы у них был поток времени входа / выхода и назначили значение +1 для людей, входящих в здание, и -1, когда они покидают здание, у вас будет что-то вроде
dx <- rbind(
data.frame(val=1, time=dd$clockin_datetime),
data.frame(val=-1, time=dd$clockout_datetime)
)
dx <- dx[order(dx$time), ]
Затем, чтобы узнать количество людей в любой момент времени, вам просто нужно накапливать сумму в столбце val.
transform(dx, pop=cumsum(val))
Затем вы можете разбить это на интервалы.
Работа с data.tables, а не с data.frames, вероятно, была бы лучше с точки зрения производительности для данных вашего масштаба, но для того, чтобы выяснить, что лучше всего будет работать с вашими данными, потребуется больший контрольный пример. Но я думаю, что эта общая стратегия может быть весьма полезной.