【问题标题】:Finding the first number after consecutive zeros in data frame查找数据帧中连续零后的第一个数字
【发布时间】:2020-04-09 14:03:54
【问题描述】:

我有以下数据框

data <- tibble(ID=rep(c(1:2), each= 9), time = rep(1:9, 2), event = c(1,1,1,0,0,0,0,1,1,1,1,0,0,0,1,0,1,0))

我想检索每个主题的第一行,该主题在第一个主题的 data.frame 中的连续零 ierow 编号 8 和第二个主题的 data.frame 中的第 15 行之后具有“1”

【问题讨论】:

  • 到目前为止你尝试了什么?

标签: r dataframe filter dplyr extract


【解决方案1】:

1) oneAfter0 采用 0 和 1 的向量并将它们粘贴在一起。然后它使用regexpr 查找01 的第一次出现,并返回一个与输入长度相同的逻辑向量。该结果对于第一个 1 的位置为 TRUE,在其他位置为 FALSE。

ave 用于将其应用于每个组,subset 用于子集对应于 TRUE 的行。

没有使用任何包。

oneAfter0 <- function(x) regexpr("01", paste(x, collapse = "")) + 1 == seq_along(x)
subset(data, ave(event, ID, FUN = oneAfter0) == 1)

2) 也可以像这样使用 dplyr 编写:

library(dplyr)

data %>%
  group_by(ID) %>%
  filter(regexpr("01", paste(event, collapse = "")) + 1 == 1:n()) %>%
  ungroup

【讨论】:

    【解决方案2】:

    这是base R 解决方案rle()

    r <- rle(data$event)
    df <- data[cumsum(r$lengths)[r$lengths > 1 & r$values==0]+1,]
    

    这样

    > df
       ID time event
    8   1    8     1
    15  2    6     1
    

    【讨论】:

      【解决方案3】:

      这是Ronak Shah's1 答案的故意教学版本,以不雅但逐步的方式展示如何使用来自rle 的运行长度来捕获行索引以用于识别零运行和以下非运行-零events

      library(dplyr)
      #> 
      #> Attaching package: 'dplyr'
      #> The following objects are masked from 'package:stats':
      #> 
      #>     filter, lag
      #> The following objects are masked from 'package:base':
      #> 
      #>     intersect, setdiff, setequal, union
      data <- tibble(ID=rep(c(1:2), each= 9), time = rep(1:9, 2), event = c(1,1,1,0,0,0,0,1,1,1,1,0,0,0,1,0,1,0))
      runs <- rle(data$event)
      runs <- tibble(runs$lengths, runs$values)
      colnames(runs) <- c("lengths", "values")
      sequences <- sequences <- tibble(lengths = runs$lengths, values = runs$values) %>% mutate(indices = cumsum(runs$lengths))
      post_zero <- sequences %>%  filter(values == 0)
      result <- left_join(sequences, post_zero, by = "indices") %>% select(1:3) %>% filter(values.x == 1)
      colnames(result) <- c("lengths", "runs", "indices")
      data[result$indices,]
      #> # A tibble: 4 x 3
      #>      ID  time event
      #>   <int> <int> <dbl>
      #> 1     1     3     1
      #> 2     2     2     1
      #> 3     2     6     1
      #> 4     2     8     1
      

      reprex package (v0.3.0) 于 2019 年 12 月 16 日创建

      【讨论】:

        【解决方案4】:

        我的答案与 Eric 的非常相似,但需要 2 个零而不是 1。

        -- 编辑以将结果限制为仅第一次出现而不是全部。

        library(dplyr)
        
        data <- tibble(ID=rep(c(1:2), each= 9), time = rep(1:9, 2), event = c(1,1,1,0,0,0,0,1,1,1,1,0,0,0,1,0,1,0))
        
        data %>%
          group_by(ID) %>%
          filter(
            event == 1,
            dplyr::lag(event) == 0,
            dplyr::lag(event, 2) == 0,
            cumsum(event == 1 &          # this limits the results to the first occurrence
                dplyr::lag(event, default = 1) == 0 &
                dplyr::lag(event, default = 1, n = 2) == 0) == 1
          )
        

        【讨论】:

          【解决方案5】:

          如果我正确理解您的问题,请提供一个整洁的答案:

          library(dplyr)
          data %>% 
            filter(event==1,lag(event)==0)
          

          【讨论】:

          • 这给出了每个组的所有出现的 0,后跟 1,而不仅仅是第一个。
          【解决方案6】:

          我们可以使用rle 选择每组中第一个连续零之后的第一行 (ID)。

          library(dplyr)
          
          data %>%
           group_by(ID) %>%
           slice(with(rle(event == 0), sum(lengths[1:which.max(values)])) + 1)
          
          #     ID  time event
          #  <int> <int> <dbl>
          #1     1     8     1
          #2     2     6     1
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-12-06
            • 1970-01-01
            • 1970-01-01
            • 2016-02-20
            相关资源
            最近更新 更多