【问题标题】:group by and find index of first non-zero in each group in data table分组并查找数据表中每组中第一个非零的索引
【发布时间】:2019-10-09 15:09:33
【问题描述】:

我在 R 中有一个数据表,看起来像:

   city year target
1:  NYC 2000      0
2:  NYC 2000      1
3:  NYC 2000      1
4:   LA 2000      0
5:   LA 2000      0
6:   LA 2000      1
7:   LA 2000      1

可以通过以下方式创建:

data = data.table(city = c("NYC", "NYC", "NYC", "LA", "LA", "LA", "LA"),
                  year = c(2000, 2000, 2000, 2000, 2000, 2000, 2000),
                  target = c(0, 1, 1, 0, 0, 1, 1))

我想按cityyear 对它们进行分组,并在target列中找到第一个非零元素的索引,这样我就可以对其进行修改,所需的结果应该如下所示:

   city year target
1:  NYC 2000      0
2:  NYC 2000    666
3:  NYC 2000      1
4:   LA 2000      0
5:   LA 2000      0
6:   LA 2000    666
7:   LA 2000      1

感谢任何帮助。

以下不起作用:

cutoff_thresh <- function(x, cutoff) {x > cutoff}

helper <- data %>% 
          group_by(city, year) %>%
          mutate(thresh = detect_index(.x = target,
                 .f = cutoff_thresh,
                  cutoff = 0)
                 )

它产生给定年份中第一个非零元素出现的确切日期, 它从每年的第一天开始计算。因此,如果 2000 有 365 天,并且 2001 的第二天我们是非零的,它返回 2 代表 (NYC, 2001) 而不是 365 + 2。不足为奇!

【问题讨论】:

    标签: r group-by dplyr data.table


    【解决方案1】:

    由于数据集已经是data.table,使用data.table 方法可能更有效。按'city'、'year'分组,获取第一个非零元素('i1')的行索引(.I),在i中使用它并分配(:=)'target'的值到 666

    library(data.table)
    i1 <- data[, .I[target != 0][1], .(city, year)]$V1
    data[i1, target := 666][]
    #    city year target
    #1:  NYC 2000      0
    #2:  NYC 2000    666
    #3:  NYC 2000      1
    #4:   LA 2000      0
    #5:   LA 2000      0
    #6:   LA 2000    666
    #7:   LA 2000      1
    

    使用tidyverse 的选项是

    library(tidyverse)
    data %>%
       group_by(city, year) %>% 
       mutate(target = replace(target, which(target != 0)[1], 666))
    # A tibble: 7 x 3
    # Groups:   city, year [2]
    #  city   year target
    #  <chr> <dbl>  <dbl>
    #1 NYC    2000      0
    #2 NYC    2000    666
    #3 NYC    2000      1
    #4 LA     2000      0
    #5 LA     2000      0
    #6 LA     2000    666
    #7 LA     2000      1
    

    或者match

    data %>% 
       group_by(city, year) %>%
       mutate(target = replace(target, match(1, target), 666))
    

    注意:即使特定组的“目标”中没有 1,所有解决方案都有效

    例如

    data$target[6:7] <- 0
    data %>%
        group_by(city, year) %>% 
        mutate(target = replace(target, which(target != 0)[1], 666))
    # A tibble: 7 x 3
    # Groups:   city, year [2]
    #  city   year target
    #  <chr> <dbl>  <dbl>
    #1 NYC    2000      0
    #2 NYC    2000    666
    #3 NYC    2000      1
    #4 LA     2000      0
    #5 LA     2000      0
    #6 LA     2000      0
    #7 LA     2000      0
    

    【讨论】:

      【解决方案2】:

      使用dplyr,您可以在组中使用which.maxreplace找到第一个非零元素的索引666。

      library(dplyr)
      
      data %>%
        group_by(city, year) %>%
        mutate(target = replace(target, which.max(target != 0), 666))
      
      
      #  city   year target
      #  <chr> <dbl>  <dbl>
      #1 NYC    2000      0
      #2 NYC    2000    666
      #3 NYC    2000      1
      #4 LA     2000      0
      #5 LA     2000      0
      #6 LA     2000    666
      #7 LA     2000      1
      

      ifelse也可以使用同样的东西

      data %>%
        group_by(city, year) %>%
        mutate(target = ifelse(row_number() == which.max(target != 0), 666, target))
      

      【讨论】:

      • 不错的技巧,使用which.max 查找第一个非零元素。
      • 另一种data.table 使用replace 的方式类似于您的第一种方法:data[, target := replace(target, cumsum(target != 0) == 1L, 666L), by = .(city, year)][]
      【解决方案3】:

      使用 data.table,使用 mult= 参数连接以仅编辑满足连接条件的第一行(如果有)

      > data[.(unique(city), 1), on=.(city, target), mult="first", target := 999]
      > data
         city year target
      1:  NYC 2000      0
      2:  NYC 2000    999
      3:  NYC 2000      1
      4:   LA 2000      0
      5:   LA 2000      0
      6:   LA 2000    999
      7:   LA 2000      1
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-06-03
        • 1970-01-01
        • 1970-01-01
        • 2018-01-17
        • 1970-01-01
        • 1970-01-01
        • 2013-01-29
        • 2018-12-06
        相关资源
        最近更新 更多