首页 > 解决方案 > 按条件过滤 data.table,但每 N 行至少保留一行

问题描述

假设我有这个微不足道的 data.table:

library(data.table)

dt <- data.table(
  day = 1:10,
  a = c(0, 1, 10, 2, 2.5, 2.3, 2.7, 2.9, 5, 8)
)

我想根据a. 在这种情况下,a变化超过 3 的时刻。这是微不足道的:

dt[abs(a - shift(a)) >= 3]

但是,我不想在很长一段时间内丢失信息。因此,如果上述条件没有受到影响,我需要确保没有超过 3 天的“过滤”延伸。

在上述情况下,基于的条件a满足:

dt[, abs(a - shift(a)) >= 3]
# [1]    NA FALSE  TRUE  TRUE FALSE FALSE FALSE FALSE FALSE  TRUE
                              -----------------------------

FALSE请注意,在接近尾声的地方有一段很长的时间。我想到的最好的是

dt[, abs(a - shift(a)) >= 3 | .I %% 3 == 0]
# [1]    NA FALSE  TRUE  TRUE FALSE  TRUE FALSE FALSE  TRUE  TRUE
                                     ----              ----

(即确保每第三行被接受)但它不会放置最好或最少的附加行。

最佳结果将是一个过滤器,它在中间FALSE有一个TRUE右(或尽可能多的)打破这条线。

# [1]    NA FALSE  TRUE  TRUE FALSE FALSE TRUE FALSE FALSE  TRUE
                                          ----

标签: rdata.table

解决方案


也许有人可以复制这一点,data.table但这是您可能正在寻找的逻辑。为了清楚起见,我分离了test,run_lengthresult,但如果需要,可以将逻辑组合或包装在一个函数中。

这将保留所有行

  1. testTRUE

    或者

  2. 和 的每一N行中的每一TRUEFALSE

这样,所有TRUEs 都由第一个条件保留,第二个条件捕获N每个条纹的每个元素,因此FALSE也捕获了一些 s。-

library(dplyr)

N <- 3

dt %>% 
  mutate(
    test = abs(a - lag(a)) >= N, # flag change(a) >= N
    run_length = sequence(rle(test)$lengths), # seq along streaks of TRUE and FALSE
    result = test | run_length %% N == 0 
  ) # %>% 
  # filter(result) # uncomment this to get final dt

   day    a  test run_length result
1    1  0.0    NA          1     NA
2    2  1.0 FALSE          1  FALSE
3    3 10.0  TRUE          1   TRUE
4    4  2.0  TRUE          2   TRUE
5    5  2.5 FALSE          1  FALSE
6    6  2.3 FALSE          2  FALSE
7    7  2.7 FALSE          3   TRUE
8    8  2.9 FALSE          4  FALSE
9    9  5.0 FALSE          5  FALSE
10  10  8.0  TRUE          1   TRUE

data.table(我猜) -

dt[, (test <- abs(a - shift(a)) >= N) | sequence(rle(test)$lengths) %% N == 0]

[1] NA FALSE  TRUE  TRUE FALSE FALSE  TRUE FALSE FALSE  TRUE

推荐阅读