0
votes

Is there is a way to group rows together based on a common column value (id), then, mutate a new column with a new id (new.id) based on whether within each group the values are above and/or below 1000? Such as:

  1. < 1000 = "low/low" (where all values in that groups are below 1000)
  2. < 1000 and > 1000 = "low/high" (where some are below and above 1000)
  3. > 1000 = "high/high" (where all values are above 1000)

Data

#Example
  id values
1   a    200
2   a    300
3   b    100
4   b   2000
5   b   3000
6   c   4000
7   c   2000
8   c   3000
9   d   2400
10  d   2000
11  d    400

#dataframe:
structure(list(id = c("a", "a", "b", "b", "b", "c", "c", "c", 
"d", "d", "d"), values = c(200, 300, 100, 2000, 3000, 4000, 2000, 
3000, 2400, 2000, 400)), class = "data.frame", row.names = c(NA, 
-11L))

Desired output

   id values    new.id
1   a    200   low/low
2   a    300   low/low
3   b    100  low/high
4   b   2000  low/high
5   b   3000  low/high
6   c   4000 high/high
7   c   2000 high/high
8   c   3000 high/high
9   d   2400  low/high
10  d   2000  low/high
11  d    400  low/high

A dplyr solution would be great, but open to any others!

2

2 Answers

0
votes
df %>% 
  group_by(id) %>%
  mutate(new.id = case_when(
    all(values < 1000) ~ "low/low",
    all(values > 1000) ~ "high/high",
    TRUE ~ "low/high"
  ))
0
votes

Alternatively, you can use the recode function from dplyr.


df %>% group_by(id) %>%
  mutate(
    new.id = dplyr::recode(
      sum(values > 1000) / length(values),
      `0` = "low/low",
      `1` = "high/high",
      .default = "low/high"
    )
  )

In case you like to keep a total count as well


df %>% group_by(id) %>%
  add_tally() %>%
  mutate(new.id = dplyr::recode(
    sum(values > 1000) / n,
    `0` = "low/low",
    `1` = "high/high",
    .default = "low/high"
  ))