Selecting observations within a data frame and reversing their order
Using data.table
:
library(data.table)
setDT(dat)
ids.to.reverse <- c('b', 'e', 'g')
dat[, if(ID %in% ids.to.reverse) .SD[.N:1] else .SD, by='ID']
One option is to group_split
by ID and do the arrange
by looping over the list
with map
based on whether any
of the values 'b', 'e', 'g' are %n%
the 'ID'
library(dplyr)
library(purrr)
out <- dat %>%
group_split(ID) %>%
map_dfr(~ if(any(c('b', 'e', 'g') %in% first(.x$ID)))
.x %>%
arrange(desc(time)) else .x)
out %>%
filter(ID %in% c('a', 'b'))
# A tibble: 20 x 3
# ID time var1
# <fct> <int> <dbl>
# 1 a 1 -0.560
# 2 a 2 -0.230
# 3 a 3 1.56
# 4 a 4 0.0705
# 5 a 5 0.129
# 6 a 6 1.72
# 7 a 7 0.461
# 8 a 8 -1.27
# 9 a 9 -0.687
#10 a 10 -0.446
#11 b 10 -0.473
#12 b 9 0.701
#13 b 8 -1.97
#14 b 7 0.498
#15 b 6 1.79
#16 b 5 -0.556
#17 b 4 0.111
#18 b 3 0.401
#19 b 2 0.360
#20 b 1 1.22
Or we can make use of arrange
in a hacky way i.e. change the time
to negative based on the ID 'b', 'e', 'g' while the rest is positive
out1 <- dat %>%
arrange(ID, time * c(1, -1)[c(1 + (ID %in% c('b', 'e', 'g')))])
-checking
all.equal(out, out1, check.attributes = FALSE)
#[1] TRUE
Here is an approach with base R using split
, order
and rev
:
rev.ids <- c("b", "e", "g")
split <- split(dat, dat$ID)
dat <- do.call(rbind,lapply(split,function(x){
if(x[1,1] %in% rev.ids)
x[order(rev(x$time)),]
else
x
}))
dat
ID time var1
1 a 1 -0.560475647
2 a 2 -0.230177489
...
8 a 8 -1.265061235
9 a 9 -0.686852852
10 a 10 -0.445661970
11 b 10 -0.472791408
12 b 9 0.701355902
...
18 b 3 0.400771451
19 b 2 0.359813827
20 b 1 1.224081797
21 c 1 -1.067823706
Edit
I think this data.table
approach will be faster:
library(data.table)
rev.ids <- c("b", "e", "g")
setDT(dat)[,.SD[order(time,decreasing = (unlist(.BY) %in% rev.ids))],by = ID]
ID time var1
1: a 1 -0.560475647
2: a 2 -0.230177489
...
8: a 8 -1.265061235
9: a 9 -0.686852852
10: a 10 -0.445661970
11: b 10 -0.472791408
12: b 9 0.701355902
...
19: b 2 0.359813827
20: b 1 1.224081797
21: c 1 -1.067823706
22: c 2 -0.217974915