【问题标题】:Flag rows between two values of a column in a group using dplyr使用 dplyr 标记组中列的两个值之间的行
【发布时间】:2018-12-06 18:01:42
【问题描述】:

我的虚拟数据如下所示

df = data.frame(name = c(rep("Anna",8),rep("Jenny",7)),
                id = c(100,100,100,100,100,100,100,100,250,250,250,250,250,250,250),
                time = c("t2","t3","t5","t1","t7","t2","t1","t5","t1","t2","t6","t2","t8","t6","t5"),                stringsAsFactors = F)

> df
    name  id time
1   Anna 100   t2
2   Anna 100   t3
3   Anna 100   t5
4   Anna 100   t1
5   Anna 100   t7
6   Anna 100   t2
7   Anna 100   t1
8   Anna 100   t5
9  Jenny 250   t1
10 Jenny 250   t2
11 Jenny 250   t6
12 Jenny 250   t2
13 Jenny 250   t8
14 Jenny 250   t6
15 Jenny 250   t5

我的预期输出是,对于每个 id 组,我想使用time 变量在 t2t5 之间的 flag 值 - 会有在每组中有多个这种情况,并且代码应该能够排除一些损坏的情况,如下例所示

 > df
    name  id time Flag
1   Anna 100   t2    1
2   Anna 100   t3    1
3   Anna 100   t5    1
4   Anna 100   t1    0
5   Anna 100   t7    0
6   Anna 100   t2    1
7   Anna 100   t1    1
8   Anna 100   t5    1
9  Jenny 250   t1    0
10 Jenny 250   t2    0
11 Jenny 250   t6    0
12 Jenny 250   t2    1
13 Jenny 250   t8    1
14 Jenny 250   t6    1
15 Jenny 250   t5    1

我使用dplyr()mode 提出这个问题,因为我将来可以添加更多分组变量以实现可扩展性。我搜索了如何在 dplyr 函数中使用which(),结果并不多,我在这里找到了一个等效的python Get rows between two values of a column using Python

Edit1:我在每个组中有多个 t2-t5 部分需要标记。感谢@ronak 提出来

提前致谢

【问题讨论】:

    标签: r filter dplyr


    【解决方案1】:

    应该有更好的选择,但这有效

    library(tidyverse)
    
    df %>%
      group_by(name) %>%
      mutate(flag  = +(row_number() %in% which(time == "t2"):which(time == "t5")))
    
    
    #  name     id time   flag
    #  <chr> <dbl> <chr> <dbl>
    #1 Anna    100 t2        1
    #2 Anna    100 t3        1
    #3 Anna    100 t5        1
    #4 Jenny   250 t1        0
    #5 Jenny   250 t2        1
    #6 Jenny   250 t3        1
    #7 Jenny   250 t4        1
    #8 Jenny   250 t5        1
    

    这是假设您在每个组中只有一个“t2”和“t5”。

    使用基本 R ave 的相同逻辑

    as.numeric(with(df, ave(time, name, FUN = function(x) 
          +(1:length(x) %in% which(x == "t2"):which(x == "t5")))))
    #[1] 1 1 1 0 1 1 1 1
    

    编辑

    如果您有多个“t2”和“t5”,则无需考虑组,因为无论如何您都想标记它们。我们可以使用mapply并创建一个索引序列来将flag标记为1。

    df$flag <- 0
    df$flag[unlist(mapply(":", which(df$time == "t2"), which(df$time == "t5")))] <- 1
    

    同样的dplyr版本是

    df %>%
      mutate(flag = +(row_number() %in% 
              unlist(map2(which(time == "t2"), which(time == "t5"), seq))))
    

    【讨论】:

    • 是的,我在每组中有多个 t2-t5 部分要标记,上面的代码有限制,只有一次出现
    • 那么,如果每组中有多个 t2-t5,输出会是什么?你能用那个更新你的例子吗?
    • 代码应该能够在每组中将 t2-t5 之间的所有部分标记为 1
    • 是的,代码在基本 R 模式下工作,我试图在 dplyr 中实现这一点。谢谢你
    • @SaiPrabhanjanReddy 更新为tidyverse 版本。
    【解决方案2】:

    以下是您可以考虑的简单方法:

    library(dplyr)
    
    df %>%
        mutate(flag = ifelse(time %in% c("t2", "t3", "t4", "t5"), 1, 0))
    

    这将像您描述的那样标记数据并且是可读的。

       name  id time flag
    1  Anna 100   t2    1
    2  Anna 100   t3    1
    3  Anna 100   t5    1
    4 Jenny 250   t1    0
    5 Jenny 250   t2    1
    6 Jenny 250   t3    1
    7 Jenny 250   t4    1
    8 Jenny 250   t5    1
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-24
      • 1970-01-01
      • 2020-04-27
      • 1970-01-01
      相关资源
      最近更新 更多