如何在一个时间 window 中找到多个变量的同步增加?

How to find synchronous increases of multiple variables in a time window?

我有一个非常大的数据框,其中包含在连续时间内对不同对象进行的测量。我需要过滤掉那些 在特定时间 window.

所有受试者同步增加的测量值

这是一些模拟数据; v1v2 是对两个对象进行的测量:

df <- data.frame(
  time = 1:30,
  v1 = c(4,4,4,4,4,   2,4,5,5,6,  
         6,6,6,6,6,   5,5,6,7,7,  
         7,6,5,6,4,   5,5,5,5,4),
  v2 = c(0.93,0.82,0.99,1.01,1.01,   1.01,1.01,1.56,1.80,1.99,  
         1.01,0.05,1.05,1.02,0.01,   1.11,1.11,1.40,1.42,1.45,  
         1.00,1.00,1.11,1.99,1.34,   2.45,3.00,3.67,3.67,3.88)
)

让我们假设时间 window 为 5 秒。我如何检测 df 中的那些行,在 5 秒内 window,v1v2 中的值同步增加?通过“增加”我的意思是: 5 值序列中的任何值都不得小于序列第一个值,并且至少序列最后一个值必须大于序列第一个值。也就是说,1,1,1,1,2 算作增加,而 1,0,1,2,3 则不算。我还想通过一些分组标签对每个同步增加进行分组,例如 ab 等。所需的输出将是:

df1
   time v1   v2 group
6     6  2 1.01     a
7     7  4 1.01     a
8     8  5 1.56     a
9     9  5 1.80     a
10   10  6 1.99     a
16   16  5 1.11     b
17   17  5 1.11     b
18   18  6 1.40     b
19   19  7 1.42     b
20   20  7 1.45     b
25   25  4 1.34     c
26   26  5 2.45     c
27   27  5 3.00     c
28   28  5 3.67     c
29   29  5 3.67     c

如何做到这一点?非常感谢帮助。

你可以试试这个方法:

保持它的灵活性以适应任意数量的测量(第 v1v2...vn 列)。

library(dplyr)
library(data.table)

window_size <- 5

result1 <- df %>%
  mutate(across(c(v1, v2), ~lead(.) - ., .names = '{col}_diff')) %>%
  mutate(result = {tmp <- select(., ends_with('diff')); 
                   rowSums(tmp >= 0) == length(tmp)},
         group = rleid(result)) %>%
  group_by(group) %>%
  filter(n() >= window_size - 1)

result1

# A tibble: 12 x 7
# Groups:   group [3]
#    time    v1    v2 v1_diff v2_diff result group
#   <int> <dbl> <dbl>   <dbl>   <dbl> <lgl>  <int>
# 1     6     2  1.01       2   0     TRUE       4
# 2     7     4  1.01       1   0.55  TRUE       4
# 3     8     5  1.56       0   0.24  TRUE       4
# 4     9     5  1.8        1   0.190 TRUE       4
# 5    16     5  1.11       0   0     TRUE       8
# 6    17     5  1.11       1   0.290 TRUE       8
# 7    18     6  1.4        1   0.02  TRUE       8
# 8    19     7  1.42       0   0.03  TRUE       8
# 9    25     4  1.34       1   1.11  TRUE      12
#10    26     5  2.45       0   0.550 TRUE      12
#11    27     5  3          0   0.67  TRUE      12
#12    28     5  3.67       0   0     TRUE      12

请注意,我们在 filter 中有 window_size - 1,这是必需的,因为我们用 lead 行减去当前行,这对于每组中的最后一行来说是负数.这也是最后一行不包含在同一组中的原因。如果时间是连续的,您可以从每个组中获得下一个值为 time 的行。

result2 <- df %>%
  filter(time %in% (result1 %>% slice(n()) %>% pull(time) + 1))
result2
#  time v1   v2
#1   10  6 1.99
#2   20  7 1.45
#3   29  5 3.67

现在 rbind result1result2 仅保留 result1.

中的相关列

以下方法将每隔 n 行将数据分成不同的组。因此,如果您想检查 0-5、6-10、11-16 的条件,...这将起作用

library(dplyr)

#storing the window size
n1 <- 5L

#code for result
df %>% group_by(dummy = (row_number()-1) %/% n1) %>%
  filter((last(v1) > first(v1) & 
                         v1 >= first(v1) &
                         last(v2) > first(v2) &
                         v2 >= first(v2))) %>%
  ungroup() %>%
  mutate(grp = letters[dense_rank(dummy)])

# A tibble: 10 x 5
    time    v1    v2 dummy grp  
   <int> <dbl> <dbl> <dbl> <chr>
 1     6     2  1.01     1 a    
 2     7     4  1.01     1 a    
 3     8     5  1.56     1 a    
 4     9     5  1.8      1 a    
 5    10     6  1.99     1 a    
 6    16     5  1.11     3 b    
 7    17     5  1.11     3 b    
 8    18     6  1.4      3 b    
 9    19     7  1.42     3 b    
10    20     7  1.45     3 b