如何提取开始信号和结束信号之间的所有行?

时间:2015-09-30 21:22:44

标签: r dataframe filtering

我有以下df,我想根据以下开始和结束信号提取所有行。

启动信号:当状态从1变为0时 结束信号:当状态从0变为-1时。

df <- data.frame(time = rep(1:14), status = c(0,1,1,0,0,0,-1,0,1,0,0,0,-1,0))

   time status
1     1      0
2     2      1
3     3      1
4     4      0
5     5      0
6     6      0
7     7     -1
8     8      0
9     9      1
10   10      0
11   11      0
12   12      0
13   13     -1
14   14      0

欲望:

   time status    
4     4      0
5     5      0
6     6      0
10   10      0
11   11      0
12   12      0

4 个答案:

答案 0 :(得分:6)

这是使用data.table包的可能解决方案。我基本上首先按status == 1个出现进行分组,然后检查每个组是否还有status == -1,如果有的话,我将该组从第二个事件分组到{{1}事件减去1

-1

答案 1 :(得分:2)

我们计算开始和结束标记,然后使用这些值和(开始 - 结束)的累积和来过滤行。 (cumsum(start)-cumsum(end)>1)是一个轻微的小提琴,以避免第2行开始但不会结束累积计数;否则第14行会被包含在内。

require(dplyr)

df %>% mutate(start=(status==1), end=(status==-1)) %>%
       filter(!start & !end & (cumsum(start)-cumsum(end)>1) ) %>%
       select(-start, -end)

#   time status
# 1    4      0
# 2    5      0
# 3    6      0
# 4   10      0
# 5   11      0
# 6   12      0

答案 2 :(得分:1)

有点难看,但是你总是可以循环遍历这些值并保留一个标志来确定是否应该保留该元素。

keepers <- rep(FALSE, nrow(df))
flag <- FALSE
for(i in 1:(nrow(df)-1)) {
    if(df$status[i] == 1 && df$status[i+1] == 0) { 
        flag <- TRUE
        next  # keep signal index false
    }
    if(df$status[i] == -1 && df$status[i+1] == 0) {
        flag <- FALSE
        next  # keep signal index false
    }
    keepers[i] <- flag
}
keepers[nrow(df)] <- flag  # Set the last element to final flag value
newdf <- df[keepers, ]  # subset based on the T/F values determined

答案 3 :(得分:1)

您是否有更多数据(或者您可以生成更多您知道结果的数据),看看这些/这些是否概括?

两种类似的方法:

library(stringr)

df <- data.frame(time = rep(1:14), status = c(0,1,1,0,0,0,-1,0,1,0,0,0,-1,0))

dfr <- rle(df$status)

# first approach 

find_seq_str <- function() {
  str_locate_all(paste(gsub("-1", "x", dfr$values), collapse=""), "10")[[1]][,2]
}

df[as.vector(sapply(find_seq_str(), 
  function(n) {
    i <- sum(dfr$lengths[1:(n-1)])
    tail(i:(i+dfr$lengths[n]), -1)
  })),]


# second approach

find_seq_ts <- function() {
  which(apply(embed(dfr$values, 2), 1, function(x) all(x == c(0, 1))))
}

df[as.vector(sapply(find_seq_ts(), 
  function(n) {
    i <- sum(dfr$lengths[1:(n)])+1
    head(i:(i+dfr$lengths[n+1]), -1)
  })),]

两种方法都需要status向量的行程编码。

第一个为-1替换单个字符,因此我们可以创建一个明确的连续字符串,然后使用str_locate找到告诉我们目标序列何时开始然后重建范围的对来自rle长度的零。

如果它需要是基础R我可以尝试使用regexpr

第二个构建配对矩阵并比较相同的目标序列。

警告:

  • 我没有进行基准测试
  • 如果status很大,两者都会产生很大的影响。
  • 我并不完全肯定它(因此我最初的q)。
  • 大卫的可读性和维护性更强可转移代码,但您可以处理使用data.table所带来的所有“善意”; - )

我将这些方法包装在函数中,因为它们可能会被参数化,但您可以轻松地将值分配给变量或将其推送到sapply(呃,tho)。