【问题标题】:Find three or more consecutive negative numbers and remove the rows from data frame查找三个或更多连续负数并从数据框中删除行
【发布时间】:2016-04-11 00:23:23
【问题描述】:

这是我的示例数据:

df = data.frame(id=rep(c(123,456,789),each=5),day=rep(c(1:5),3),measure=c(2.2,3.4,2.1,-0.2,-1.2,3.4,2.4,-2.2,-3.1,-1.7,3.9,5.4,-1,3.2,4.2))

    id day measure
1  123   1     2.2
2  123   2     3.4
3  123   3     2.1
4  123   4    -0.2
5  123   5    -1.2
6  456   1     3.4
7  456   2     2.4
8  456   3    -2.2
9  456   4    -3.1
10 456   5    -1.7
11 789   1     3.9
12 789   2     5.4
13 789   3    -1.0
14 789   4     3.2
15 789   5     4.2

每个人都有五天的数据。

我想在 df$measure 中为每个人找到位置,其中每个人中有三个或更多连续的负值,然后删除这些行。如果有两个或更少的连续负值,只需将值设置为 0。

个别123末尾有两个负值,所以把值改成0 个人 456 最后有三个负值,所以删除这些行 个人 789 在第 3 天有一个负值,因此将值更改为 0

结果:

    id day measure
1  123   1     2.2
2  123   2     3.4
3  123   3     2.1
4  123   4    0
5  123   5    0
6  456   1     3.4
7  456   2     2.4
8 789   1     3.9
9 789   2     5.4
10 789   3    0
11 789   4     3.2
12 789   5     4.2

到目前为止我所拥有的:

如果我首先将 df$measure 中的所有负值变为 0..

df$measure[df$measure < 0] <- 0

然后以某种方式使用 rle:

m = rle(df$measure)

Run Length Encoding
  lengths: int [1:12] 1 1 1 2 1 1 3 1 1 1 ...
  values : num [1:12] 2.2 3.4 2.1 0 3.4 2.4 0 3.9 5.4 0 ...

并从 m$lengths 和 m$values 中计算出连续 3 个或更多的 0 的索引 - 需要删除这些索引。

但是需要对每个ID分别进行检查吗?

实现这一目标的最有效方法是什么?

【问题讨论】:

    标签: r dataframe


    【解决方案1】:

    另一个带有ave 的基本 R 版本使用旧的“反转否定逻辑检查的反转”技巧来获得适当的计数器。

    自:

    with(df, rev(cumsum(!(rev(measure) < 0))) )
    #[1] 9 8 7 6 6 6 5 4 4 4 4 3 2 2 1
    # compare the equivalent of df$id groups
    #[1] 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3
    

    当与id结合时,你可以只检查长度:

    df[with(df, ave(measure, list(id, rev(cumsum(!(rev(measure) < 0)))), FUN=length) < 3 ),]
    
    #    id day measure
    #1  123   1     2.2
    #2  123   2     3.4
    #3  123   3     2.1
    #4  123   4    -0.2
    #5  123   5    -1.2
    #6  456   1     3.4
    #7  456   2     2.4
    #11 789   1     3.9
    #12 789   2     5.4
    #13 789   3    -1.0
    #14 789   4     3.2
    #15 789   5     4.2
    

    【讨论】:

      【解决方案2】:

      我们可以使用data.tablerleid,将run-length-encoding按id分组

      library(data.table)
      setDT(df)
      
      ## indicate wich measure values are negative
      df[, neg := measure < 0]
      ## use run-length-encoding by each id, on the 'neg' column
      df[, rl := rleid(neg), by = id]
      
      ## identify how many of each 'rl' are in each group
      df[, rl_len := .N, by=.(id, rl)]
      
      ## drop values
      df <- df[!(neg & rl_len >= 3)]
      
      ## set to 0
      df[neg == 1, measure := 0]
      df
      #      id day measure   neg rl rl_len
      #  1: 123   1     2.2 FALSE  1      3
      #  2: 123   2     3.4 FALSE  1      3
      #  3: 123   3     2.1 FALSE  1      3
      #  4: 123   4     0.0  TRUE  2      2
      #  5: 123   5     0.0  TRUE  2      2
      #  6: 456   1     3.4 FALSE  1      2
      #  7: 456   2     2.4 FALSE  1      2
      #  8: 789   1     3.9 FALSE  1      2
      #  9: 789   2     5.4 FALSE  1      2
      # 10: 789   3     0.0  TRUE  2      1
      # 11: 789   4     3.2 FALSE  3      2
      # 12: 789   5     4.2 FALSE  3      2
      

      【讨论】:

        【解决方案3】:

        我们从 'measure' 获得逻辑向量的 rle!df$measure - 为 0 值给出 TRUE,所有其他值为 FALSE),分配具有 'lengths' 的 'values' 向量(来自 rle)小于 3 为 FALSE,取反 (!) 并对数据集进行子集化。

        df[!inverse.rle(within.list(rle(!df$measure), values[lengths<3] <- FALSE)),]
        #    id day measure
        #1  123   1     2.2
        #2  123   2     3.4
        #3  123   3     2.1
        #4  123   4     0.0
        #5  123   5     0.0
        #6  456   1     3.4
        #7  456   2     2.4
        #11 789   1     3.9
        #12 789   2     5.4
        #13 789   3     0.0
        #14 789   4     3.2
        #15 789   5     4.2
        

        注意:上述结果与 OP 的预期输出相匹配,因为 0 值在相邻的“id”之间不连续。如果我们需要在每个 'id' 中执行此操作,请使用任何 group by 技术。在base R 中,我们可以使用ave 来做到这一点

        indx <- with(df, !ave(!measure, id, FUN = function(x) {
                         inverse.rle(within.list(rle(x), values[lengths<3] <- FALSE))
                      }))
        df[indx,]
        #    id day measure
        #1  123   1     2.2
        #2  123   2     3.4
        #3  123   3     2.1
        #4  123   4     0.0
        #5  123   5     0.0
        #6  456   1     3.4
        #7  456   2     2.4
        #11 789   1     3.9
        #12 789   2     5.4
        #13 789   3     0.0
        #14 789   4     3.2
        #15 789   5     4.2
        

        或者我们可以使用来自data.tablerleid。将 'data.frame' 转换为 'data.table' (setDT(df)),按 'id' 和取反的 'measure' 的 run-length-id 分组,得到一个逻辑索引列 (!(!measure &amp; .N &gt;2)) 到子集数据集中的行。

        library(data.table)
        setDT(df)[df[, !(!measure & .N >2), .(id, rleid(!measure))]$V1]
        #     id day measure
        # 1: 123   1     2.2
        # 2: 123   2     3.4
        # 3: 123   3     2.1
        # 4: 123   4     0.0
        # 5: 123   5     0.0
        # 6: 456   1     3.4
        # 7: 456   2     2.4
        # 8: 789   1     3.9
        # 9: 789   2     5.4
        #10: 789   3     0.0
        #11: 789   4     3.2
        #12: 789   5     4.2
        

        或者我们可以使用dplyr

        library(dplyr)
        df %>% 
          group_by(id, gr = cumsum(c(0,abs(diff(!measure))))) %>% 
          filter(!(all(!measure) & n() >2)) %>% 
          ungroup() %>% 
          select(-gr)
        #      id   day measure
        #    (dbl) (int)   (dbl)
        #1    123     1     2.2
        #2    123     2     3.4
        #3    123     3     2.1
        #4    123     4     0.0
        #5    123     5     0.0
        #6    456     1     3.4
        #7    456     2     2.4
        #8    789     1     3.9
        #9    789     2     5.4
        #10   789     3     0.0
        #11   789     4     3.2
        #12   789     5     4.2
        

        注意2:使用0替换负值后的数据。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-06-25
          • 2012-12-12
          • 1970-01-01
          • 2015-07-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多