I have a sequence that looks like this
id ep value
1 1 1 a
2 1 2 a
3 1 3 b
4 1 4 d
5 2 1 a
6 2 2 a
7 2 3 c
8 2 4 e
and what I want to do is to reduce it to
id ep value n time total
1 1 0 a 2 20 40
2 1 1 b 1 10 40
3 1 2 d 1 10 40
4 2 0 a 2 20 40
5 2 1 c 1 10 40
6 2 2 e 1 10 40
The dplyrseems to be working ok
short = df %>% group_by(id) %>%
mutate(grp = cumsum(value != lag(value, default = value[1]))) %>%
count(id, grp, value) %>% mutate(time = n*10) %>% group_by(id) %>%
mutate(total = sum(time))
However, my database is really big and it takes forever.
Question 1
Could anyone help me to translate this line into data.table code?
Question 2
I am interested also then in going back to the long format and I am wondering what is the most efficient solution in terms of speed.
At the moment, I am using this line
short[rep(1:nrow(short), short$n), ] %>%
select(-n, -time, -total) %>%
group_by(id) %>%
mutate(ep = 1:n())
Any suggestions?
df = structure(list(id = structure(c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L
), .Label = c("1", "2"), class = "factor"), ep = structure(c(1L,
2L, 3L, 4L, 1L, 2L, 3L, 4L), .Label = c("1", "2", "3", "4"), class = "factor"),
value = structure(c(1L, 1L, 2L, 4L, 1L, 1L, 3L, 5L), .Label = c("a",
"b", "c", "d", "e"), class = "factor")), .Names = c("id",
"ep", "value"), row.names = c(NA, -8L), class = "data.frame")
An option would be to use rleid from data.table
library(data.table)
short1 <- setDT(df)[, .N,.(id, grp = rleid(value), value)
][, time := N*10
][, c('total', 'ep') := .(sum(time), seq_len(.N) - 1), id
][, grp := NULL][]
short1
# id value N time total ep
#1: 1 a 2 20 40 0
#2: 1 b 1 10 40 1
#3: 1 d 1 10 40 2
#4: 2 a 2 20 40 0
#5: 2 c 1 10 40 1
#6: 2 e 1 10 40 2
Deriving the 'long' format would be
short1[rep(seq_len(.N), N), -c('N', 'time', 'total', 'ep'),
with = FALSE][, ep1 := seq_len(.N), id][]
The direct translation of the dplyr code into data.table would be
setDT(df)[, grp := cumsum(value != shift(value, fill = value[1])), id
][, .(N= .N), .(id, grp, value)
][, time := N*10
][, c('total', 'ep') := .(sum(time), seq_len(.N) - 1), id
][, grp := NULL][]
# id value N time total ep
#1: 1 a 2 20 40 0
#2: 1 b 1 10 40 1
#3: 1 d 1 10 40 2
#4: 2 a 2 20 40 0
#5: 2 c 1 10 40 1
#6: 2 e 1 10 40 2
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With