Проверьте, находятся ли значения в определенном диапазоне отдельного кадра данных - PullRequest
0 голосов
/ 29 мая 2018

У меня есть два следующих фрейма данных:

df <- data.frame(id = c("AED","AED","CFR","DRR","DRR","DRR","UN","PO"),
             dates = as.POSIXct(c("2018-05-17 09:52:00","2018-05-17 10:49:00","2018-05-17 10:38:00","2018-05-17 11:29:00","2018-05-17 12:12:00","2018-05-17 13:20:00","2018-05-17 14:28:00","2018-05-17 15:59:00")))

events <- data.frame(id = c("AED","CFR","DRR","DRR","UN"),
                 start = as.POSIXct(c("2018-05-17 10:00:00","2018-05-17 10:18:00","2018-05-17 11:18:00","2018-05-17 13:10:00","2018-05-17 14:18:00")),
                 end = as.POSIXct(c("2018-05-17 11:56:00","2018-05-17 12:23:00","2018-05-17 12:01:00","2018-05-17 14:18:00",NA)))

По уникальному идентификатору я хочу сравнить каждую дату в df с соответствующими диапазонами дат, перечисленными в фрейме данных событий (каждая строка фрейма данных событий считаетсяего собственный диапазон времени), так что я получаю следующий результат:

result <- data.frame(id = c("AED","AED","CFR","DRR","DRR","DRR","UN","PO"),
                 dates = c("2018-05-17 09:52:00","2018-05-17 10:49:00","2018-05-17 10:38:00","2018-05-17 11:29:00","2018-05-17 12:12:00","2018-05-17 13:20:00","2018-05-17 14:28:00","2018-05-17 15:59:00"),
                 inRange = c(FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE),
                 outsideRange = c(TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE))

Если идентификатор из df отсутствует в событиях, возвращает FALSE как для inRange, так и outsideRange;если дата df больше, чем событие $ start, но событие $ end равно NA, тогда inRange должно быть ИСТИНА

Я надеюсь применить решение к гораздо большему набору данных, по крайней мере, 500 000 строк.

Ответы [ 3 ]

0 голосов
/ 29 мая 2018

Один из вариантов - использовать non-equi обновить объединение, используя data.table.Присоединяйтесь df и events к dates>=start и dates<=end.Установите для столбца inRange значение TRUE для соответствующих записей.

library(data.table)

setDT(df)
setDT(events)

df[events, on=c("dates>=start", "dates<=end"), inRange := TRUE]
df
#                  dates inRange
# 1: 2018-05-17 09:52:00      NA
# 2: 2018-05-17 09:56:00      NA
# 3: 2018-05-17 10:38:00    TRUE
# 4: 2018-05-17 11:29:00    TRUE
# 5: 2018-05-17 12:12:00      NA
# 6: 2018-05-17 13:20:00      NA
# 7: 2018-05-17 14:28:00    TRUE
# 8: 2018-05-17 15:59:00      NA
# 
0 голосов
/ 30 мая 2018

Если events не перекрываются, то сортировать начальную и конечную координаты и использовать findInterval(), чтобы определить те даты, которые находятся в нечетных интервалах

x = with(events, sort(c(start, end)))
df$inRange = findInterval(df$dates, x) %% 2 == 1

Если events сделать перекрытиезатем создайте вектор всех событий, выясните, как их упорядочить, и сделайте так:

times <- with(events, c(start, end))
o <- order(times)
times <- times[o]

создайте вектор event, равный 1 при запуске, -1 принаступает конец, и размещайте эти события в следующем порядке:

event <- rep(c(1, -1), each = nrow(events))[o]

вычисляет «охват», число событий, которые в настоящее время действуют.

cvg <- cumsum(event)

Наконец, создайте обновленный events кадр данных, где начинается и заканчивается, выводятся из значений 'start', где покрытие равно 1, а событие является событием 'start', а также для концов

times[ (event == 1 & cvg == 1) | (event == -1 & cvg == 0) ]

и продолжается, как указано выше.

Соединяя это, мы имеем

reduce_int <- function(start, end) {
    x <- c(start, end)
    o <- order(x)
    x <- x[o]

    event <- rep(c(1, -1), each = nrow(events))[o]
    cvg <- cumsum(event)

    x[ (event == 1 & cvg == 1) | (event == -1 & cvg == 0) ]
}

overlaps <- function(x, events) {
    vec <- reduce_int(event$start, event$end)
    findInterval(x, vec) %% 2 == 1
}

с использованием

df$inRange <- overlaps(df$dates, events)
0 голосов
/ 29 мая 2018

в базе R:

df2 <- merge(df,events)
df2 <- within(df2, inRange <- dates > start & dates < end)
df2 <- aggregate(inRange ~ dates,df2,any)
#                 dates inRange
# 1 2018-05-17 09:52:00   FALSE
# 2 2018-05-17 09:56:00   FALSE
# 3 2018-05-17 10:38:00    TRUE
# 4 2018-05-17 11:29:00    TRUE
# 5 2018-05-17 12:12:00   FALSE
# 6 2018-05-17 13:20:00   FALSE
# 7 2018-05-17 14:28:00    TRUE
# 8 2018-05-17 15:59:00   FALSE

Первое слияние - это декартово произведение здесь, если ваши данные велики, лучше было бы сначала извлечь день с обеих сторон, а затем объединить.

Это означает, что нужно сделать это до кода выше:

df$year <- as.Date(df$dates)
events$year <- as.Date(events$start) # assuming start and end are always on same day
...