Filter groups only by increasing, ascending order in R

Viewed 224

I am having trouble figuring out how to filter for groups in a dataframe that increase by descending order. I would start with an input:

df <- structure(list(Animal = c("Cat", "Cat", "Cat", "Cat", "Cat", 
"Cat", "Dog", "Dog", "Dog", "Dog", "Rat", "Rat", "Rat", "Rat", 
"Rat"), Value = c(2L, 3L, 5L, 8L, 19L, 20L, 4L, 8L, 19L, 33L, 
4L, 8L, 15L, 10L, 25L)), class = "data.frame", row.names = c(NA, 
-15L))

In this case, I want my output to only show groups "Dog" and "Cat" since it is consistently increasing. Rat, however, would be left out at it goes from 8 to 15 to 10.

Any help would be appreciated. Thanks!

3 Answers

One dplyr-based solution could be:

df %>%
 group_by(Animal) %>%
 filter(all(diff(Value) > 0))

   Animal Value
   <chr>  <int>
 1 Cat        2
 2 Cat        3
 3 Cat        5
 4 Cat        8
 5 Cat       19
 6 Cat       20
 7 Dog        4
 8 Dog        8
 9 Dog       19
10 Dog       33

Data:

df <- structure(list(Animal = c("Cat", "Cat", "Cat", "Cat", "Cat", 
"Cat", "Dog", "Dog", "Dog", "Dog", "Rat", "Rat", "Rat", "Rat", 
"Rat"), Value = c(2L, 3L, 5L, 8L, 19L, 20L, 4L, 8L, 19L, 33L, 
4L, 8L, 15L, 10L, 25L)), class = "data.frame", row.names = c(NA, 
-15L))

Code:

library(dplyr)

df %>% 
  filter(!Animal == "Rat") %>% 
  arrange(Animal, Value)

Output:

#>    Animal Value
#> 1     Cat     2
#> 2     Cat     3
#> 3     Cat     5
#> 4     Cat     8
#> 5     Cat    19
#> 6     Cat    20
#> 7     Dog     4
#> 8     Dog     8
#> 9     Dog    19
#> 10    Dog    33

Created on 2020-08-18 by the reprex package (v0.3.0)

I would define a function called increasing based on diff which returns a boolean. Here are versions with dplyr and data.table:

library(dplyr)
library(data.table)

df <- tibble::tribble(
~Animal,  ~Value,
"Cat", 2,
"Cat", 3,
"Cat", 5,
"Cat", 8,
"Cat", 19,
"Cat", 20,
"Dog", 4,
"Dog", 8,
"Dog", 19,
"Dog", 33,
"Rat", 4,
"Rat", 8,
"Rat", 15,
"Rat", 10,
"Rat", 25)
dt <- data.table(df)

increasing <- function(x) rep(all(diff(x) >= 0), length(x))

df %>% group_by(Animal) %>%
       filter(increasing(Value)) 

dt[, .SD[increasing(Value)], by=Animal]
Related