【问题标题】:grouping continuous data with specific pattern对具有特定模式的连续数据进行分组
【发布时间】:2020-06-01 10:57:52
【问题描述】:

我有一个这样的列的数据框(我没有发布其他列)

Value
1
1
1
0
0
1
0
0
1
1
2
2
0
0
1
0
0
1
1
1
0
0
2
2
1
1
2
0
0
1
0

我正在尝试根据特定条件对其进行分组。当我有 1 和 2 时,必须进行分组。但是像这样的条件是一组:

1 1 0 0 1 1 0 0 

基本上我需要对出现的1 进行分组,但在0s 之间是允许的

预期输出:

Value   Group
    1   1
    1   1 
    1   1
    0   1
    0   1
    1   1
    0   1 
    0   1
    1   1
    1   1
    2   2
    2   2
    0   2
    0   2
    1   3
    0   3
    0   3
    1   3 
    1   3
    1   3
    0   3
    0   3
    2   4 
    2   4
    1   5
    1   5
    2   6
    0   6
    0   6
    1   7
    0   7 
    2   8
    0   8
    2   8
    1   9

【问题讨论】:

    标签: r dataframe data.table


    【解决方案1】:

    这是另一个使用data.table的选项:

    DT[, Group := .GRP, .(date, rleid(nafill(replace(Value, Value==0L, NA_integer_), "locf")))]
    

    【讨论】:

    • 我怎样才能把它分成两组?只有1和2
    • 什么意思?请添加到您想要的输出
    • 实际上我想获得允许在 0 之间提供的值中从 1 到 2 的转变次数(与分组标准相同)
    • 与您在帖子中发布的内容有什么不同?
    • 是的...我应该把它作为一个新问题来问吗?
    【解决方案2】:

    这是另一种基本方法,它使用ave() 计算12 之间的变化,然后在结果上使用cummax() 来给出最终分组。

    dat$Group <- cummax(ave(dat$Value, dat$Value == 0, FUN = function(x) cumsum(c(x[1], diff(x) != 0))))
    
    dat
       Value Group
    1      1     1
    2      1     1
    3      1     1
    4      0     1
    5      0     1
    6      1     1
    7      0     1
    8      0     1
    9      1     1
    10     1     1
    11     2     2
    12     2     2
    13     0     2
    14     0     2
    15     1     3
    16     0     3
    17     0     3
    18     1     3
    19     1     3
    20     1     3
    21     0     3
    22     0     3
    23     2     4
    24     2     4
    25     1     5
    26     1     5
    27     2     6
    28     0     6
    29     0     6
    30     1     7
    31     0     7
    

    针对您的评论,如果您希望按日期分组结果,您可以使用嵌套的ave()

    ave(ave(dat$Value, dat$Value == 0, dat$date, FUN = function(x) cumsum(c(x[1], diff(x) != 0))), dat$date, FUN = cummax)
    

    【讨论】:

    • 如果我有一个日期列,如何根据每一天对它进行分组?
    • 我得到了重复组。
    • 请发布您的预期输出 - 您的问题应该完全代表您的问题。
    • 我怎样才能把它分成两组?只有1和2
    【解决方案3】:

    Base-R 中的这个循环可以解决问题

    group <- 0
    lastgroupvalue <- NA
    data$Group <- NA
    
    for(i in 1:nrow(data)){
        if(!data$Value[i] %in% c(lastgroupvalue, 0)){
            group <- group + 1
            lastgroupvalue <- data$Value[i]
        }
        data$Group[i] <- group
    }
    
    > data
       Value Group
    1      1     1
    2      1     1
    3      1     1
    4      0     1
    5      0     1
    6      1     1
    7      0     1
    8      0     1
    9      1     1
    10     1     1
    11     2     2
    12     2     2
    13     0     2
    14     0     2
    15     1     3
    16     0     3
    17     0     3
    18     1     3
    19     1     3
    20     1     3
    21     0     3
    22     0     3
    23     2     4
    24     2     4
    25     1     5
    26     1     5
    27     2     6
    28     0     6
    29     0     6
    30     1     7
    31     0     7
    

    数据:

    data <- structure(list(Value = c(1L, 1L, 1L, 0L, 0L, 1L, 0L, 0L, 1L, 
    1L, 2L, 2L, 0L, 0L, 1L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 2L, 2L, 1L, 
    1L, 2L, 0L, 0L, 1L, 0L)), class = "data.frame", row.names = c(NA, 
    -31L))
    

    【讨论】:

    • 如果我有日期列,如何根据每一天对其进行分组?
    • 如果您希望解决方案能够处理您的数据,您必须提供一个具有代表性的示例。
    【解决方案4】:

    另一种避免循环的解决方案,与 Limey 的解决方案类似,但使用 cumsum 创建组。

    df$Group <- dplyr::na_if(df$Value, 0)
    df <- tidyr::fill(df, Group, .direction = "down")
    df$Group <- cumsum(df$Group != dplyr::lag(df$Group, default = -1))
    
    > df
    
       Value Group
    1      1     1
    2      1     1
    3      1     1
    4      0     1
    5      0     1
    6      1     1
    7      0     1
    8      0     1
    9      1     1
    10     1     1
    11     2     2
    12     2     2
    13     0     2
    14     0     2
    15     1     3
    16     0     3
    17     0     3
    18     1     3
    19     1     3
    20     1     3
    21     0     3
    22     0     3
    23     2     4
    24     2     4
    25     1     5
    26     1     5
    27     2     6
    28     0     6
    29     0     6
    30     1     7
    31     0     7
    

    【讨论】:

    • 如果我有一个日期列,如何根据每一天对它进行分组?
    【解决方案5】:

    或避免循环的 tidyverse 解决方案:

    x <- tibble(Value=c(1,1,1,0,0,1,0,0,1,1,2,2,0,0,1,0,0,1,1,1,
                        0,0,2,2,1,1,2,0,0,1,0,2,0,2,1)) %>% 
           mutate(ModValue=ifelse(Value == 0, NA, Value)) %>%
           fill(ModValue, .direction="down")
    
    runLengths <- rle(x$ModValue)
    groupIndex <- unlist(lapply(1:length(runLengths$lengths), 
                                function(x) rep(x, runLengths$lengths[x]))
                        )
    
    x <- x %>% add_column(Group=groupIndex) %>% select(-ModValue)                                      
    

    您的输入数据与预期输出的长度不同。我花了一些时间来解决这个问题... :)

    ** 编辑 **

    还有一个不优雅的解决方案来解释不断变化的日子(或其他超级分组......

    x <- tibble(
           RowNumber=1:35,
           Date=lubridate::ymd(c(rep("2020-05-31", 20), rep("2020-06-01", 15))),
           Value=c(1,1,1,0,0,1,0,0,1,1,2,2,0,0,1,0,0,1,1,1,0,0,2,2,1,1,2,0,0,1,0,2,0,2,1))
    
    # Check we have a change of date mid-sequence
    x %>% filter(row_number() > 15 & row_number() < 25)   
    
    x <- x %>% 
           mutate(ModValue=ifelse(Value == 0, NA, Value)) %>%
           fill(ModValue, .direction="down")
    
    # Inelegantly compute the groups
    make_groups <- function(x) {
      runs <- rle(x)
      return(tibble(GroupWithinDay=unlist(
                                     lapply(1:length(runs$lengths), 
                                            function(x) rep(x, runs$lengths[x])))))
    }
    
    y <- x %>% group_by(Date) %>% do(make_groups(.$ModValue))
    x <- x %>% add_column(GroupWithinDay=y$GroupWithinDay) %>% select(-ModValue)
    
    # Check the change of date is handled correctly
    x %>% filter(row_number() > 15 & row_number() < 25)   
    

    给予

    # A tibble: 9 x 4
      RowNumber Date       Value GroupWithinDay
          <int> <date>     <dbl>          <int>
    1        16 2020-05-31     0              3
    2        17 2020-05-31     0              3
    3        18 2020-05-31     1              3
    4        19 2020-05-31     1              3
    5        20 2020-05-31     1              3
    6        21 2020-06-01     0              1
    7        22 2020-06-01     0              1
    8        23 2020-06-01     2              2
    9        24 2020-06-01     2              2
    

    【讨论】:

    • 如果我有日期列,如何根据每一天对其进行分组?
    • 正如@DanielO 所说,您需要给我们一些测试数据和样本输出来回答这个新问题。例如,日期的更改是否会触发一个新组,即使它位于 1 的序列中?
    • 是的,它将是新组
    • 我怎样才能把它分成两组?只有1和2
    • 请提供输入数据和预期输出的示例。
    猜你喜欢
    • 2023-04-06
    • 1970-01-01
    • 2021-12-22
    • 1970-01-01
    • 2021-07-19
    • 1970-01-01
    • 2015-08-24
    • 1970-01-01
    • 2022-07-17
    相关资源
    最近更新 更多