Я работаю в R и пытаюсь понять, как лучше объединить кадры данных, когда один из них очень большой.
У меня есть фрейм данных, который не является мучительно большим, но и не маленьким (~ 80K наблюдений 8 переменных, 144 МБ). Мне нужно сопоставить наблюдения из этого фрейма данных с наблюдениями из другого меньшего фрейма данных на основе диапазона дат. Конкретно у меня есть:
events.df <- data.frame(individual=c('A','B','C','A','B','C'),
event=c(1,1,1,2,2,2),
time=as.POSIXct(c('2014-01-01 08:00:00','2014-01-05 13:00:00','2014-01-10 07:00:00','2014-05-01 01:00:00','2014-06-01 12:00:00','2014-08-01 10:00:00'),format="%Y-%m-%d %H:%M:%S"))
trips.df <- data.frame(individual=c('A','B','C'),trip=c('x1A','CA1B','XX78'),
trip_start = as.POSIXct(c('2014-01-01 06:00:00','2014-01-04 03:00:00','2014-01-08 12:00:00'),format="%Y-%m-%d %H:%M:%S"),
trip_end=as.POSIXct(c('2014-01-03 06:00:00','2014-01-06 03:00:00','2014-01-11 12:00:00'),format="%Y-%m-%d %H:%M:%S"))
В моем случае events.df содержит около 80 000 уникальных событий, и я хочу сопоставить их с событиями из фрейма данных trips.df , который содержит около 200 уникальных поездок. Каждая поездка имеет уникальный идентификатор поездки («поездка»). Я хотел бы провести сопоставление в зависимости от того, имело ли место событие в диапазоне дат, определяющем поездку.
Сначала я попробовал fuzzy_inner_join из библиотеки fuzzyjoin . Это прекрасно работает в принципе:
fuzzy_inner_join(events.df,trips.df,by=c('individual'='individual','time'='trip_start','time'='trip_end'),match_fun=list(`==`,`>=`,`<=`))
individual.x event time individual.y trip trip_start trip_end
1 A 1 2014-01-01 08:00:00 A x1A 2014-01-01 06:00:00 2014-01-03 06:00:00
2 B 1 2014-01-05 13:00:00 B CA1B 2014-01-04 03:00:00 2014-01-06 03:00:00
3 C 1 2014-01-10 07:00:00 C XX78 2014-01-08 12:00:00 2014-01-11 12:00:00
>
но не хватает памяти, когда я пытаюсь применить его к большим кадрам данных.
Вот второе решение, которое я собрал вместе:
trip.match <- function(tripid){
individual <- trips.df$individual[trips$trip==tripid]
start <- trips.df$trip_start[trips$trip==tripid]
end <- trips.df$trip_end[trips$trip==tripid]
tmp <- events.df[events.df$individual==individual &
events.df$time>= start &
events.df$time<= end,]
tmp$trip <- tripid
return(tmp)
}
result <- data.frame(rbindlist(lapply(unique(trips.df$trip),trip.match)
Это решение также выходит из строя, поскольку объект списка, возвращаемый lapply, равен 25 ГБ, а попытка привести этот список к фрейму данных также исчерпывает доступную память.
Я смог сделать то, что мне нужно, используя цикл for. По сути, я добавляю столбец к events.df , перебираю уникальные идентификаторы поездок и заполняю новый столбец в events.df соответственно:
events.df$trip <- NA
for(i in unique(trips.df$trip)){
individual <- trips.df$individual[trips.df$trip==i]
start <- min(trips.df$trip_start[trips.df$trip==i])
end <- max(trips.df$trip_end[trips.df$trip==i])
events.df$trip[events.df$individual==individual & events.df$time >= start & events.df$time <= end] <- i
}
> events.df
individual event time trip
1 A 1 2014-01-01 08:00:00 x1A
2 B 1 2014-01-05 13:00:00 CA1B
3 C 1 2014-01-10 07:00:00 XX78
4 A 2 2014-05-01 01:00:00 <NA>
5 B 2 2014-06-01 12:00:00 <NA>
6 C 2 2014-08-01 10:00:00 <NA>
У меня такой вопрос: я не очень продвинутый программист на R, поэтому я ожидаю, что есть более эффективный способ памяти для выполнения того, что я пытаюсь сделать. Есть ли?