сгруппировать и найти индекс первой ненулевой в каждой группе в таблице данных - PullRequest
3 голосов
/ 23 мая 2019

У меня есть таблица данных в 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))

Я хотел бы сгруппировать их по city иyear и найдите индекс первого ненулевого элемента в столбце 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 дней, а во 2-й день 2001 года мы отличны от нуля, он возвращает 2 для (NYC, 2001) вместо 365 + 2.Не удивительно!

Ответы [ 3 ]

3 голосов
/ 23 мая 2019

Поскольку набор данных уже является data.table, может быть более эффективно использовать методы data.table.Сгруппированные по 'city', 'year', получают индекс строки (.I) первого ненулевого элемента ('i1'), используют его в 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
1 голос
/ 23 мая 2019

Используя dplyr, вы можете найти индекс первого ненулевого элемента, используя which.max в группе и replace его на 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))
0 голосов
/ 23 мая 2019

С помощью 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
...