Как создать групповые индексы для вложенных групп в r - PullRequest
2 голосов
/ 21 апреля 2019

У меня есть набор данных с несколькими наблюдениями, вложенными в отдельных людей.Этот пример набора данных включает столбцы для идентификатора и дня недели (dayweek, 1-7).У меня есть наблюдения от 3 дней от каждого человека.Таким образом, один человек мог отправлять отчеты только для Sun / Wed / Thu (1, 4, 5), а другой мог представлять отчеты для Sun / Mon / Tue (1, 2, 3), как в этом примере:

df <- data.frame(
  id = c(rep(1:2, each = 6),2),
  dayweek = c(rep(c(1, 4, 5), each = 2),rep(c(1, 2, 3), each = 2), 3)
)

Я хочу настроить столбец, который будет отмечать первый, второй и третий день каждого человека, например:

df2 <- data.frame(
  id = c(rep(1:2, each = 6),2),
  dayweek = c(rep(c(1, 4, 5), each = 2),rep(c(1, 2, 3), each = 2), 3),
  daynum = c(rep(1:3, each = 2, times = 2), 3)
)

Я пытался использовать

df %>% group_indices(id, dayweek) 

но это создает новый идентификатор для каждой комбинации дня.Какой хороший способ сделать это?

Заранее спасибо!

Ответы [ 3 ]

4 голосов
/ 21 апреля 2019

dplyr

Использование cumsum и !duplicated с dplyr

df %>%
  group_by(id) %>%
  mutate(daynum = cumsum(!duplicated(dayweek)))


# A tibble: 13 x 3
# Groups:   id [2]
      id dayweek daynum
   <dbl>   <dbl>  <int>
 1     1       1      1
 2     1       1      1
 3     1       4      2
 4     1       4      2
 5     1       5      3
 6     1       5      3
 7     2       1      1
 8     2       1      1
 9     2       2      2
10     2       2      2
11     2       3      3
12     2       3      3
13     2       3      3

tapply от базы R

unlist(tapply(df$dayweek, df$id, function(x) cumsum(!duplicated(x))))

 1  1  2  2  3  3  1  1  2  2  3  3  3 
4 голосов
/ 21 апреля 2019

Мы могли бы group_by id и создать уникальный id для каждого dayweek

library(dplyr)

df %>%
  group_by(id) %>%
  mutate(daynum = as.integer(factor(dayweek, levels = unique(dayweek))))

#      id dayweek daynum
#   <dbl>   <dbl>  <int>
# 1     1       1      1
# 2     1       1      1
# 3     1       4      2
# 4     1       4      2
# 5     1       5      3
# 6     1       5      3
# 7     2       1      1
# 8     2       1      1
# 9     2       2      2
#10     2       2      2
#11     2       3      3
#12     2       3      3
#13     2       3      3

В базе R мы можем использовать ave для того же

with(df, ave(dayweek, id, FUN = function(x) 
         as.integer(factor(x, levels = unique(x)))))
#[1] 1 1 2 2 3 3 1 1 2 2 3 3 3
2 голосов
/ 21 апреля 2019

Согласно комментарию OP , строки расположены по порядку.

Тогда, вот два разных подхода, которые также будут обрабатывать случай "пятница, суббота, воскресенье" (dayweek 6, 7, 1), упомянутый в комментариях.

  1. rleid()
  2. fct_inorder()

rleid()

Используется функция rleid() из пакета data.table:

library(dplyr)
df2 %>% 
  group_by(id) %>% 
  mutate(daynum2 = data.table::rleid(dayweek)) 
      id dayweek daynum daynum2
   <dbl>   <dbl>  <dbl>   <int>
 1     1       1      1       1
 2     1       1      1       1
 3     1       4      2       2
 4     1       4      2       2
 5     1       5      3       3
 6     1       5      3       3
 7     2       1      1       1
 8     2       1      1       1
 9     2       2      2       2
10     2       2      2       2
11     2       3      3       3
12     2       3      3       3
13     2       3      3       3
14     3       6      1       1
15     3       7      2       2
16     3       1      3       3

Обратите внимание, что используется расширенный набор данных, который также охватывает случай "пятница, суббота, воскресенье" (dayweek 6, 7, 1).

fct_inorder()

Это расширенная версия ответа Ронака , в котором также рассматривается случай "пятница, суббота, воскресенье". Он использует fct_inorder() из пакета forcats, который переупорядочивает уровни факторов при первом появлении.

df2 %>% 
  group_by(id) %>% 
  mutate(daynum2 = 
           dayweek %>% 
           as.character() %>% 
           forcats::fct_inorder() %>% 
           as.integer()
         ) 

Вывод такой же, как указано выше.

Данные

Это расширенный набор данных, который включает также случай «пятница, суббота, воскресенье» (dayweek 6, 7, 1):

df2 <- data.frame(
  id = c(rep(1:2, each = 6), 2, rep(3, 3)),
  dayweek = c(rep(c(1, 4, 5), each = 2),rep(c(1, 2, 3), each = 2), 3, 6, 7, 1),
  daynum = c(rep(1:3, each = 2, times = 2), 3, 1:3)
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...