【问题标题】:How to remove subsequent values after first instance only when other values are absent仅当其他值不存在时,如何在第一次实例后删除后续值
【发布时间】:2018-08-13 07:48:45
【问题描述】:

当所有未来值均为 0 时,我试图在第一个零实例之后删除零。最终,我很想做这个 group_by 物种,但只是小步。这是一个例子;

# Sample
library(tidyverse)
id<-c("a","b","c","d","e","f","g","h","i","j")
time<-c(1,2,3,4,5,6,7,8,9,10)
value<-c(90, 50, 40, 0, 30, 30, 0, 10, 0, 0)
df<-data.frame(id, time, value)
df

   id time value
1   a    1    90
2   b    2    50
3   c    3    40
4   d    4     0
5   e    5    30
6   f    6    30
7   g    7     0
8   h    8    10
9   i    9     0
10  j   10     0

我想查看观察 ID“j”,并且只删除观察 ID“j”。我什至不知道从哪里开始。任何建议都非常感谢!

【问题讨论】:

    标签: r dplyr subset


    【解决方案1】:

    仅在基数 R 中。它使用 rle 来获取尾随零的数量(如果有)。然后使用head 对数据框进行子集化。

    r <- rle(df$value == 0)
    if(r$values[length(r$values)]) head(df, -(r$lengths[length(r$values)] - 1))
    #  id time value
    #1  a    1    90
    #2  b    2    50
    #3  c    3    40
    #4  d    4     0
    #5  e    5    30
    #6  f    6    30
    #7  g    7     0
    #8  h    8    10
    #9  i    9     0
    

    你可以用上面的代码写一个函数,也许*apply它到组。

    trailingZeros <- function(DF, col = "value"){
        r <- rle(DF[[col]] == 0)
        if(r$values[length(r$values)] && r$lengths[length(r$values)] > 1)
            head(DF, -(r$lengths[length(r$values)] - 1))
        else
            DF
    }
    
    trailingZeros(df)
    

    请注意,这也适用于大量尾随零。

    id2 <- c("a","b","c","d","e","f","g","h","i","j","k")
    time2 <- c(1,2,3,4,5,6,7,8,9,10,11)
    value2 <- c(90, 50, 40, 0, 30, 30, 0, 10, 0, 0, 0)    # One more zero at end
    df2 <- data.frame(id = id2, time = time2, value = value2)
    
    trailingZeros(df2)
    

    【讨论】:

      【解决方案2】:

      这是 tidyverse 中的一个解决方案,它也适用于大量尾随零:

      df <- tibble(id = letters[1:11], time = 1:11, 
                   value = c(90,50,40,0,30,30,0,10,0,0,0))
      df %>% 
        slice(n():1) %>% 
        slice(c(which(cumsum(value > 0) > 0)[1] - 1, which(cumsum(value > 0) > 0))) %>% 
        slice(n():1)
      

      【讨论】:

      • 这似乎一直有效并且适用于分组。谢谢你塞特!!
      【解决方案3】:

      也适用于群组的 Tidyverse 解决方案

      基于样本数据(未分组) 代码可以缩短,但这看起来非常可读;-)

      df %>% 
        #arrange by id
        arrange( id ) %>%
        #no grouping valiable in sample data.. so don't use group_by here
        #group_by( group) %>%
        #create dummy's: position in group, last value of group, position of last non-zero in group, previous value (within group)
        mutate( pos_in_group = 1:n() ) %>%
        mutate( last_value = last( value ) ) %>%
        mutate( pos_last_not_zero = max( which( value != 0) ) ) %>%
        mutate( prev_value = lag( value ) ) %>%
        #filter all rows where: 
        #   the last value of the group != 0 AND 
        #   the previous row (within the group) != 0 AND 
        #  the position of the row is 'below' the last non-zero measurement (in the group)
        filter( !(last_value == 0 & prev_value == 0 & pos_in_group >= pos_last_not_zero + 1 ) ) %>%
        #throw away the dummy's
        select( -c( pos_in_group, last_value, pos_last_not_zero, prev_value ) )
      
      #   id time value
      # 1  a    1    90
      # 2  b    2    50
      # 3  c    3    40
      # 4  d    4     0
      # 5  e    5    30
      # 6  f    6    30
      # 7  g    7     0
      # 8  h    8    10
      # 9  i    9     0
      

      涉及一些分组的示例

      # Sample
      library(tidyverse)
      id<-c("a","b","c","d","e","f","g","h","i","j","k")
      group<-c(1,1,1,1,1,1,2,2,2,2,2)
      time<-c(1,2,3,4,5,6,7,8,9,10,11)
      value = c(90,0,0,40,0,0,30,30,0,0,0)
      df<-data.frame(id, group, time, value)
      
      df
      #    id group time value
      # 1   a     1    1    90
      # 2   b     1    2     0
      # 3   c     1    3     0
      # 4   d     1    4    40
      # 5   e     1    5     0
      # 6   f     1    6     0
      # 7   g     2    7    30
      # 8   h     2    8    30
      # 9   i     2    9     0
      # 10  j     2   10     0
      # 11  k     2   11     0
      
      df %>% 
        #arrange by id
        arrange( id ) %>%
        #group
        group_by( group) %>%
        #create dummy's: position in group, last value of group, position of last non-zero in group, previous value (within group)
        mutate( pos_in_group = 1:n() ) %>%
        mutate( last_value = last( value ) ) %>%
        mutate( pos_last_not_zero = max( which( value != 0) ) ) %>%
        mutate( prev_value = lag( value ) ) %>%
        #filter all rows where: 
        #   the last value of the group != 0 AND 
        #   the previous row (within the group) != 0 AND 
        #  the position of the row is 'below' the last non-zero measurement (in the group)
        filter( !(last_value == 0 & prev_value == 0 & pos_in_group >= pos_last_not_zero + 1 ) ) %>%
        #throuw away the dummy's
        select( -c( pos_in_group, last_value, pos_last_not_zero, prev_value ) )
      
      # # A tibble: 8 x 4
      # # Groups:   group [2]
      #   id    group  time value
      #   <fct> <dbl> <dbl> <dbl>
      # 1 a         1     1    90
      # 2 b         1     2     0
      # 3 c         1     3     0
      # 4 d         1     4    40
      # 5 e         1     5     0
      # 6 g         2     7    30
      # 7 h         2     8    30
      # 8 i         2     9     0
      

      【讨论】:

      • 如果有两个连续的零不在末尾,这将不起作用:例如value = c(90,50,40,0,0,0,30,30,0,0)
      • @cett 我更新了我的答案,现在也与分组兼容
      • 我喜欢这个解释!我收到以下错误;选择错误(。,-c(pos_in_group,last_value,pos_last_not_zero,prev_value)):未使用的参数(-c(pos_in_group,last_value,pos_last_not_zero,prev_value))
      • @Dustin;也许您正在尝试取消选择 data.frame 中没有的字段/列?
      • 有效!!!并与分组!我之前的错误与 v.3.4.2 中的 Sys.setenv 有关。非常感谢!!!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-05
      • 2022-10-02
      • 2023-03-22
      相关资源
      最近更新 更多