【问题标题】:How to create index column for set of values in other column如何为其他列中的一组值创建索引列
【发布时间】:2021-04-20 09:37:45
【问题描述】:

我有一个数据框:

ID      operation
A1       open
A1       open
A1       close
A1       
A1       open
A1       close
B2      
B2       open
B2       open
B2       open
B2       close
B2       upload
B2       open
B2       close
B2       open
B2       close

我想在列操作中为每个“打开”和“关闭”捆绑添加索引。因此,对于打开和关闭之间的每一行,必须具有相同的索引。所以想要的结果是:

ID      operation    index
A1       open         1
A1       open         1
A1       close        1
A1       
A1       open         2
A1       close        2
B2      
B2       open         3
B2       open         3
B2       open         3
B2       close        3
B2       upload
B2       open         4
B2       close        4
B2       open         5
B2       close        5

我怎么能这样做?哪些功能可以用于这些以及如何应用它?最好使用data.table

【问题讨论】:

    标签: r function dataframe indexing data.table


    【解决方案1】:

    这是data.table的一种方法:

    dt[, index := .GRP, by = .(rev(cumsum(rev(operation) == 'close')))]
    dt[, index := ifelse(cumsum(operation == 'open') > 0, index, NA), by = .(ID, index)]
    dt
    #     ID operation index
    #  1: A1      open     1
    #  2: A1      open     1
    #  3: A1     close     1
    #  4: A1              NA
    #  5: A1      open     2
    #  6: A1     close     2
    #  7: B2              NA
    #  8: B2      open     3
    #  9: B2      open     3
    # 10: B2      open     3
    # 11: B2     close     3
    # 12: B2    upload    NA
    # 13: B2      open     4
    # 14: B2     close     4
    # 15: B2      open     5
    # 16: B2     close     5
    

    由于cumsum有两条路径,如果一个操作不在c('open', 'close')中,它会:

    • 如果索引在openclose 之间,则获取正确的索引;
    • 如果在closeopen 之间,则获取NA

    【讨论】:

    • 引人入胜的答案!我花了一段时间才明白这一点,但值得称赞。感谢分享
    • 是否可以使用“关闭”添加另一个价值选项?喜欢“关闭”还是“检查”?
    • @reredf,尝试提出一个新问题。数据框在评论中不可读。
    • @mt1022 以及如何使该索引按 ID 分组?因此,对于每个 ID,它都从头开始 (1,2,3,...)?这不起作用dt[, index := .GRP, by = .(ID, rev(cumsum(rev(operation) == 'close')))]
    • @reredf, dt[!is.na(index), index := rleid(index), by = .(ID)].
    【解决方案2】:

    这里有一个data.table 选项,可能会有所帮助

    setDT(df)[
      ,
      index := ifelse(
        operation %in% c("open", "close"),
        cumsum(shift(operation == "close", fill = TRUE)),
        NA
      )
    ]
    

    给予

    > df
        ID operation index
     1: A1      open     1
     2: A1      open     1
     3: A1     close     1
     4: A1              NA
     5: A1      open     2
     6: A1     close     2
     7: B2              NA
     8: B2      open     3
     9: B2      open     3
    10: B2      open     3
    11: B2     close     3
    12: B2    upload    NA
    13: B2      open     4
    14: B2     close     4
    15: B2      open     5
    16: B2     close     5
    

    数据

    > dput(df)
    structure(list(ID = c("A1", "A1", "A1", "A1", "A1", "A1", "B2",
    "B2", "B2", "B2", "B2", "B2", "B2", "B2", "B2", "B2"), operation = c("open",
    "open", "close", "", "open", "close", "", "open", "open", "open",
    "close", "upload", "open", "close", "open", "close")), class = "data.frame", row.names = c(NA,
    -16L))
    

    【讨论】:

      【解决方案3】:

      mt1022 的 出色的解决方案中获取线索,我正在为dplyr 用户翻译答案

      
      df %>% mutate(index = dense_rank(-rev(cumsum(rev(operation) == 'close')))) %>%
        group_by(ID, index) %>% mutate(index = ifelse(cumsum(operation == 'open') > 0, index, NA)) %>%
        ungroup()
      
      # A tibble: 16 x 3
         ID    operation index
         <chr> <chr>     <int>
       1 A1    open          1
       2 A1    open          1
       3 A1    close         1
       4 A1    <NA>         NA
       5 A1    open          2
       6 A1    close         2
       7 B2    <NA>         NA
       8 B2    open          3
       9 B2    open          3
      10 B2    open          3
      11 B2    close         3
      12 B2    upload       NA
      13 B2    open          4
      14 B2    close         4
      15 B2    open          5
      16 B2    close         5
      

      【讨论】:

        【解决方案4】:

        这是for 循环的解决方案:

        df$index <- NA
        index <- 0
        flag <- FALSE
        
        for(i in seq_len(nrow(df))) {
          if(df$operation[i] == '') next
          else if(df$operation[i] == 'open' & !flag) {
            index <- index + 1
            flag <- TRUE
          }
          else if(df$operation[i] == 'close' & flag) flag <- FALSE
          df$index[i] <- index
        }
        df
        
        #   ID operation index
        #1  A1      open     1
        #2  A1      open     1
        #3  A1     close     1
        #4  A1              NA
        #5  A1      open     2
        #6  A1     close     2
        #7  B2              NA
        #8  B2      open     3
        #9  B2      open     3
        #10 B2      open     3
        #11 B2     close     3
        #12 B2      open     4
        #13 B2     close     4
        #14 B2      open     5
        #15 B2     close     5
        

        数据

        df <- structure(list(ID = c("A1", "A1", "A1", "A1", "A1", "A1", "B2", 
        "B2", "B2", "B2", "B2", "B2", "B2", "B2", "B2"), operation = c("open", 
        "open", "close", "", "open", "close", "", "open", "open", "open", 
        "close", "open", "close", "open", "close")), 
        class = "data.frame", row.names = c(NA, -15L))
        

        【讨论】:

        • 谢谢,我稍微编辑了有问题的数据框。 “操作”列中可以有值,例如“上传”,它们不应该有索引。
        • 是否可以用 data.table 做到这一点?
        • 你可以通过if(df$operation[i] %in% c("", "upload")) next忽略'upload'
        【解决方案5】:

        这是一个幼稚的解决方案:

        rank <- df$operation == "close" & !is.na(df$operation)
        df$index <- cumsum(c(1, rank[-length(rank)]))
        df$index[!df$operation %in% c("open", "close")] <- NA
        df
        
           ID operation index
        1  A1      open     1
        2  A1      open     1
        3  A1     close     1
        4  A1      <NA>    NA
        5  A1      open     2
        6  A1     close     2
        7  B2      <NA>    NA
        8  B2      open     3
        9  B2      open     3
        10 B2      open     3
        11 B2     close     3
        12 B2      open     4
        13 B2     close     4
        14 B2      open     5
        15 B2     close     5
        

        【讨论】:

        • 谢谢,如何使用 data.table?
        猜你喜欢
        • 1970-01-01
        • 2022-11-18
        • 1970-01-01
        • 1970-01-01
        • 2023-01-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多