2017-02-07 5 views
2

У меня есть набор данных, который выглядит так.Консолидация строк по датам max и min

id1 = c(1,1,1,1,1,1,1,1,2,2) 
id2 = c(3,3,3,3,3,3,3,3,3,3) 
lat = c(-62.81559,-62.82330, -62.78693,-62.70136, -62.76476,-62.48157,-62.49064,-62.45838,42.06258,42.06310) 
lon = c(-61.15518, -61.14885,-61.17801,-61.00363, -59.14270, -59.22009, -59.32967, -59.04125 ,154.70579, 154.70625) 
start_date= as.POSIXct(c('2016-03-24 15:30:00', '2016-03-24 15:30:00','2016-03-24 23:40:00','2016-03-25 12:50:00','2016-03-29 18:20:00','2016-06-01 02:40:00','2016-06-01 08:00:00','2016-06-01 16:30:00','2016-07-29 20:20:00','2016-07-29 20:20:00'), tz = 'UTC') 
end_date = as.POSIXct(c('2016-03-24 23:40:00', '2016-03-24 18:50:00','2016-03-25 03:00:00','2016-03-25 19:20:00','2016-04-01 03:30:00','2016-06-02 01:40:00','2016-06-01 14:50:00','2016-06-02 01:40:00','2016-07-30 07:00:00','2016-07-30 07:00:00'),tz = 'UTC') 
speed = c(2.9299398, 2.9437502, 0.0220565, 0.0798409, 1.2824859, 1.8685429, 3.7927680, 1.8549291, 0.8140249,0.8287073) 
df = data.frame(id1, id2, lat, lon, start_date, end_date, speed) 

id1 id2  lat  lon   start_date   end_date  speed 
1 1 3 -62.81559 -61.15518 2016-03-24 15:30:00 2016-03-24 23:40:00 2.9299398 
2 1 3 -62.82330 -61.14885 2016-03-24 15:30:00 2016-03-24 18:50:00 2.9437502 
3 1 3 -62.78693 -61.17801 2016-03-24 23:40:00 2016-03-25 03:00:00 0.0220565 
4 1 3 -62.70136 -61.00363 2016-03-25 12:50:00 2016-03-25 19:20:00 0.0798409 
5 1 3 -62.76476 -59.14270 2016-03-29 18:20:00 2016-04-01 03:30:00 1.2824859 
6 1 3 -62.48157 -59.22009 2016-06-01 02:40:00 2016-06-02 01:40:00 1.8685429 
7 1 3 -62.49064 -59.32967 2016-06-01 08:00:00 2016-06-01 14:50:00 3.7927680 
8 1 3 -62.45838 -59.04125 2016-06-01 16:30:00 2016-06-02 01:40:00 1.8549291 
9 2 3 42.06258 154.70579 2016-07-29 20:20:00 2016-07-30 07:00:00 0.8140249 
10 2 3 42.06310 154.70625 2016-07-29 20:20:00 2016-07-30 07:00:00 0.8287073 

Фактический набор данных больше. То, что я хотел бы сделать, - это объединить этот набор данных на основе диапазонов дат и сгруппировать по id1 и id2, так что если диапазон даты и времени в одной строке находится в пределах 12 часов после следующего диапазона дат/времени «ABS (end_date [1] - start_date [2]) < 12hrs 'строки должны быть объединены с новым стартовым знаком, являющимся самой ранней датой, и конечной_датой последней. Все остальные значения (lat, lon, speed) будут усреднены. В этом смысле смысл «дедупликации», поскольку строки, которые находятся в течение 12 часов, фактически представляют одно и то же «событие». Для приведенного выше примера конечный результат будет

id1 id2  lat  lon   start_date   end_date  speed 
1 1 3 -62.7818 -61.12142 2016-03-24 15:30:00 2016-03-25 19:20:00 1.493897 
2 1 3 -62.76476 -59.14270 2016-03-29 18:20:00 2016-04-01 03:30:00 1.2824859 
3 1 3 -62.47686 -59.197 2016-06-01 02:40:00 2016-06-02 01:40:00 2.505413 
4 2 3 42.06284 154.706 2016-07-29 20:20:00 2016-07-30 07:00:00 0.8213661 

С первых четырех строк консолидированных (в row1), 5 строк оставили в покое (row2), в 6-8 строк консолидированных (row3) и 9- 10 строк объединены (строка 4).

Я пытался сделать это с помощью dplyrgroup_by и summarize, но я не могу заставить получить диапазоны дат для правильного вывода.

Надеюсь, кто-то может определить простой способ решения проблемы. Дополнительные баллы, если вы знаете, как это сделать в SQL ;-), поэтому я могу дедупать, прежде чем даже потянуть его в R.

+1

[Collapse строк с перекрывающимися диапазонами] (http://stackoverflow.com/questions/41747742/collapse-rows-with-overlapping-ranges), [коллапс пересекающихся регионов в R] (http://stackoverflow.com/questions/16957293/collapse-intersecting-regions-in-r) должен вас поймать. – Henrik

ответ

0

Вот первая очень наивная реализация. Предупреждение: он медленный, не очень красивый и все еще отсутствует даты начала и окончания вывода! Обратите внимание, что он ожидает, что строки будут упорядочены по дате и времени. Если это не так в наборе данных, вы можете сделать это сначала в R или SQL. К сожалению, я не могу придумать решение dplyr или SQL. Я также хотел бы видеть этих двух, если у кого-то есть идея.

dedupe <- function(df) { 
    counter = 1 
    temp_vector = unlist(df[1, ]) 
    summarized_df = df[0, c(1, 2, 3, 4, 7)] 
    colnames(summarized_df) = colnames(df)[c(1, 2, 3, 4, 7)] 
    summarized_df$counter = NULL 
    for (i in 2:nrow(df)) { 
    if (((abs(difftime(df[i, "start_date"], df[i - 1, "end_date"], units = "h")) < 
      12) || 
     abs(difftime(df[i, "start_date"], df[i - 1, "start_date"], units = "h")) < 
     12) && 
     df[i, "id1"] == df[i - 1, "id1"] && 
     df[i, "id2"] == df[i - 1, "id2"]) { 
     #group events because id is the same and time range overlap 
     #sum up columns and select maximum end_date 
     temp_vector[c(3, 4, 7)] = temp_vector[c(3, 4, 7)] + unlist(df[i, c(3, 4, 7)]) 
     temp_vector["end_date"] = max(temp_vector["end_date"], df[i, "end_date"]) 
     counter = counter + 1 
     if (i == nrow(df)) { 
     #in the last iteration we need to create a new group 
     summarized_df[nrow(summarized_df) + 1, c(1, 2)] = df[i, c(1, 2)] 
     summarized_df[nrow(summarized_df), 3:5] = temp_vector[c(3, 4, 7)]/counter 
     summarized_df[nrow(summarized_df), "counter"] = counter 
     } 
    } else { 
     #new event so we calculate group statistics for temp_vector and reset its value as well as counter 
     summarized_df[nrow(summarized_df) + 1, c(1, 2)] = df[i, c(1, 2)] 
     summarized_df[nrow(summarized_df), 3:5] = temp_vector[c(3, 4, 7)]/counter 
     summarized_df[nrow(summarized_df), "counter"] = counter 
     counter = 1 
     temp_vector[c(3, 4, 7)] = unlist(df[i, c(3, 4, 7)]) 
    } 
    } 
    return(summarized_df) 
} 

вызов функции

> dedupe(df) 
    id1 id2  lat  lon  speed counter 
5 1 3 -62.78179 -61.12142 1.4938968  4 
6 1 3 -62.76476 -59.14270 1.2824859  1 
9 2 3 -62.47686 -59.19700 2.5054133  3 
10 2 3 42.06284 154.70602 0.8213661  2