分组并在数据表的每个组中查找第一个非零的索引

时间:2019-05-23 05:22:26

标签: r group-by dplyr data.table

我在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中查找第一个非零元素的索引,以便我可以对其进行修改,期望的结果应如下所示:< / p>

   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的{​​{1}}而不是(NYC, 2001)。不足为奇!

3 个答案:

答案 0 :(得分:3)

由于数据集已经是data.table,因此使用data.table方法可能更有效。按“城市”,“年”分组,获取第一个非零元素('i1')的行索引(.I),在i中使用它并分配(:=) “目标”的值为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

答案 1 :(得分:1)

使用dplyr可以在组中使用which.max,然后在666之前replace来查找第一个非零元素的索引。

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))

答案 2 :(得分:0)

对于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