Существует ли эквивалент dplyr для data.table::rleid?

data.table предлагает удобную функцию rleid для кодирование длин серий:

library(data.table)
DT = data.table(grp=rep(c("A", "B", "C", "A", "B"), c(2, 2, 3, 1, 2)), value=1:10)
rleid(DT$grp)
# [1] 1 1 2 2 3 3 3 4 5 5

Я могу имитировать это в базе R с помощью:

df <- data.frame(DT)
rep(seq_along(rle(df$grp)$values), times = rle(df$grp)$lengths)
# [1] 1 1 2 2 3 3 3 4 5 5

Кто-нибудь знает эквивалент dplyr (?) Или "лучший" способ создать поведение rleid с dplyr - это сделать что-то вроде следующего

library(dplyr)

my_rleid = rep(seq_along(rle(df$grp)$values), times = rle(df$grp)$lengths)

df %>%
  mutate(rleid = my_rleid)

person JasonAizkalns    schedule 03.11.2015    source источник
comment
Dplyr совместим с data.table. Если по какой-то причине вы не хотите загружать data.table, я думаю, что ваше базовое решение хорошее. Вы можете попробовать отправить запрос функции в dplyr, но я бы сказал, что шансы на хороший прием не выше 50/50.   -  person Frank    schedule 03.11.2015
comment
cumsum(c(1L, df$grp[-nrow(df)] != df$grp[-1])) также для базы   -  person rawr    schedule 28.04.2016


Ответы (4)


Вы можете просто сделать (когда у вас есть оба данные. table и dplyr загружены):

DT <- DT %>% mutate(rlid = rleid(grp))

это дает:

> DT
    grp value rlid
 1:   A     1    1
 2:   A     2    1
 3:   B     3    2
 4:   B     4    2
 5:   C     5    3
 6:   C     6    3
 7:   C     7    3
 8:   A     8    4
 9:   B     9    5
10:   B    10    5

Если вы не хотите загружать data.table отдельно вы также можете использовать (как упомянул @DavidArenburg в комментариях):

DT <- DT %>% mutate(rlid = data.table::rleid(grp))

И, как сказал @RichardScriven в своем комментарии, вы можете просто скопировать/украсть его:

myrleid <- data.table::rleid
person Jaap    schedule 03.11.2015
comment
Согласен, но я стараюсь избегать вызова data.table::rleid, если это возможно. - person JasonAizkalns; 03.11.2015
comment
@JasonAizkalns Почему? Могу ли я спросить? - person Jaap; 03.11.2015
comment
Чтобы остаться полностью в dplyr, tidyr, стране хедли-стиха. - person JasonAizkalns; 03.11.2015
comment
Укради... myrleid <- data.table::rleid - person Rich Scriven; 03.11.2015
comment
@RichardScriven, вероятно, я прибегну к этому, но посмотрю, есть ли у кого-нибудь другие идеи. Другая причина — оставаться в одной парадигме в целях обучения/образования и избегать введения слишком большого количества пакетов для новых пользователей. - person JasonAizkalns; 03.11.2015
comment
@JasonAizkalns Если вы собираетесь использовать только стих Хэдли, то вы очень сильно себя ограничите. - person Jaap; 03.11.2015
comment
Не пытаясь начать какие-либо дебаты / войны, я думаю, что приму @Jaap, прежде чем это выйдет из-под контроля ... - person JasonAizkalns; 03.11.2015
comment
Это работает как чемпион с shift(), для которого нет эквивалента dplyr без кучи уродливого кода. - person TheProletariat; 17.08.2017
comment
@TheProletariat Правда, но это будет очень похоже на ответ Алекса. - person Jaap; 19.08.2017

Если вы хотите использовать только базовый R и dplyr, лучший способ — обернуть свою собственную одно- или двухстрочную версию rleid() в качестве функции, а затем применять ее всякий раз, когда вам это нужно.

library(dplyr)

myrleid <- function(x) {
    x <- rle(x)$lengths
    rep(seq_along(x), times=x)
}

## Try it out
DT <- DT %>% mutate(rlid = myrleid(grp))
DT
#   grp value rlid
# 1:   A     1    1
# 2:   A     2    1
# 3:   B     3    2
# 4:   B     4    2
# 5:   C     5    3
# 6:   C     6    3
# 7:   C     7    3
# 8:   A     8    4
# 9:   B     9    5
#10:   B    10    5
person Josh O'Brien    schedule 03.11.2015
comment
Небольшое примечание: rleid() также предназначен для работы со списками/data.frames/data.tables, например, rleid(c(1,1,1,2,2,2), c(3,4,4,5,5,6)). Ничего особенного в его реализации, но просто отметить разницу. - person Arun; 04.11.2015
comment
@ Арун Должен ли data.table::rleid(mtcars) работать? (Для меня это не так, хотя его справочный файл заставляет меня поверить, что он должен...) - person Josh O'Brien; 04.11.2015
comment
Да, но это rleidv(mtcars) (версия SE). rleid() принимает ... в качестве входных данных, поэтому нам придется предоставлять каждый столбец отдельно.. (для интерактивных случаев). - person Arun; 04.11.2015
comment
будьте осторожны: в случае NA это решение не дает того же решения, что и data.table::rleid. Проверьте x <- c(1,1,1,NA,NA,2,2); myrleid(x); data.table::rleid(x). rle рассматривать каждый NA как часть своей группы. - person Edo; 17.11.2020

Вы можете сделать это с помощью функции lag из dplyr.

DT <-
    DT %>%
    mutate(rleid = (grp != lag(grp, 1, default = "asdf"))) %>%
    mutate(rleid = cumsum(rleid))

дает

> DT
    grp value rleid
 1:   A     1     1
 2:   A     2     1
 3:   B     3     2
 4:   B     4     2
 5:   C     5     3
 6:   C     6     3
 7:   C     7     3
 8:   A     8     4
 9:   B     9     5
10:   B    10     5
person Alex    schedule 03.11.2015

Упрощение (без дополнительного пакета) подхода, используемого OP, может быть следующим:

DT %>%
 mutate(rleid = with(rle(grp), rep(seq_along(lengths), lengths)))

   grp value rleid
1    A     1     1
2    A     2     1
3    B     3     2
4    B     4     2
5    C     5     3
6    C     6     3
7    C     7     3
8    A     8     4
9    B     9     5
10   B    10     5

Or:

DT %>%
 mutate(rleid = rep(seq(ls <- rle(grp)$lengths), ls))
person tmfmnk    schedule 04.05.2019