R dplyr оконная функция, получить первое значение в следующем окне x, которое удовлетворяет некоторому условию - PullRequest
1 голос
/ 07 августа 2020

У меня есть фрейм данных dplyr и какое-то условие. Я хочу знать для каждой ячейки, каков индекс первой ячейки, которая соответствует условию в следующих x строках.

В моем случае я хочу иметь дополнительный столбец, содержащий индекс первого значения которое было больше, чем текущее значение, по крайней мере, по z.

Пример: здесь мы ищем индекс первого значения в следующих 3 строках, который по крайней мере на 3 больше текущего значения. В случае первой строки значение равно 0, а первое значение в следующих 3 ячейках, которое больше по крайней мере на 3, является ячейкой номер 4, где его значение = 3.

В третьей строке value = 2, а в следующих 3 строках нет значения, соответствующего условию, поэтому мы получаем значение NA

  value index_of_matched_cell
1     0                       4
2     0                       4
3     2                      NA
4     3                       7
5     3                       7
6     3                       7
7     6                      NA
8     6                      NA
9     6                      NA

Спасибо!

Ответы [ 3 ]

2 голосов
/ 07 августа 2020

Вот один из способов использования rollapply из zoo:

next_rows <- 3
larger_than <- 3

with(df, zoo::rollapply(seq_along(value), next_rows + 1, function(x) 
               x[which(value[x] >= (value[x[1]] + larger_than))[1]],
               align = 'left', fill = NA))

#[1]  4  4 NA  7  7  7 NA NA NA

В rollapply мы перебираем индекс каждой строки с размером окна next_rows + 1 (поскольку мы хотим рассмотреть следующие 3 строки и rollapply также учитывает текущую строку). Мы сравниваем текущее value со следующими 3 значениями и возвращаем первый индекс, где он больше или равен larger_than значению, и возвращаем его индекс.

1 голос
/ 07 августа 2020

Здесь я предлагаю вам другое решение с lapply.

find_match_index <- function(x, larger_than, within){

    ii <- seq_along(x)  

    unlist(lapply(ii, 
                  function(i, v, n, w) {

                    # here you find all positions that respect your condition
                    res <- which(v[i]+n<=v)  

                    # here you get only the positions in your range of interest
                    res <- res[res>i & res <= i+w]

                    # return only one
                    res[1]
                                    
                 }, 
                 v = x,
                 n = larger_than,
                 w = within))
}

df$index_of_matched_cell <- find_match_index(df$value, larger_than = 3, within = 3)

df
0 голосов
/ 08 августа 2020

Ручная l oop версия, сравнивающая исходный вектор и затем «ведущий» вектор на 3,2,1 вперед и последовательно перезаписывая вывод:

looplook <- function(x, dst, n) {
    lead <- function(x,n) c(tail(x,-n), rep(NA,n))
    out <- rep(NA, length(x))
    for(i in n:1) {
        sel <- which(lead(x, i) >= (x + dst))
        out[sel] <- sel + i
    }
    out
}

vec <- c(0L, 0L, 2L, 3L, 3L, 3L, 6L, 6L, 6L)

looplook(vec, dst=3, n=3)
#[1]  4  4 NA  7  7  7 NA NA NA

Кажется относительно быстрым при запуске некоторых тестов на вектор biggi sh длиной 900K:

vec <- c(0L, 0L, 2L, 3L, 3L, 3L, 6L, 6L, 6L)
vec <- rep(vec, 1e5)

system.time(looplook(vec, dst=3, n=3))
#   user  system elapsed 
#  0.031   0.000   0.031 

value <- vec

next_rows <- 3
larger_than <- 3
system.time({
zoo::rollapply(seq_along(value), next_rows + 1, function(x) 
               x[which(value[x] >= (value[x[1]] + larger_than))[1]],
               align = 'left', fill = NA)
})
#   user  system elapsed 
#  5.492   0.028   5.519 

system.time(find_match_index(vec, larger_than = 3, within = 3))
#  C-c C-c
#Timing stopped at: 39.08 0 39.08
...