1

This is my data:

ID  dist
1   23
1   10
2   12
2   20
3   14
3   33

I want to go through each ID, and create a new column ("state") for the larger value for each ID call it "high" and for the lower value, call it "low".

What's the best way to do this?

R-MASHup
  • 365
  • 2
  • 9

3 Answers3

2

Using R base

> transform(df1, state = ave(dist, ID, FUN= function(x)ifelse(x==max(x), "high", "low")))

  ID dist state
1  1   23  high
2  1   10   low
3  2   12   low
4  2   20  high
5  3   14   low
6  3   33  high
Jilber Urbina
  • 58,147
  • 10
  • 114
  • 138
  • 1
    If it is inside `transform`, you don't need the `df1$` Could be made a bit more compact ith `transform(df1, state = c('low', 'high')[(ave(dist, ID, FUN = max) == dist) + 1])` – akrun Sep 25 '18 at 16:19
1

We can create a condition with max/min

library(dplyr)
df1 %>%
  group_by(ID) %>%
  mutate(state = case_when(dist == max(dist) ~  "high",
                           dist == min(dist) ~ "low",
                           TRUE  ~ NA_character_))

As there are two values per each 'ID', the second condition is not needed

df1 %>%
  group_by(ID) %>%
  mutate(state = case_when(dist == max(dist) ~  "high",
                         TRUE  ~"low"))

data

df1 <- structure(list(ID = c(1L, 1L, 2L, 2L, 3L, 3L), dist = c(23L, 
10L, 12L, 20L, 14L, 33L)), class = "data.frame", row.names = c(NA, 
-6L))
akrun
  • 874,273
  • 37
  • 540
  • 662
0

With data.table...

library(data.table)
setDT(DF)

DF[order(ID, dist), v := c("lo", "hi")]

   ID dist  v
1:  1   23 hi
2:  1   10 lo
3:  2   12 lo
4:  2   20 hi
5:  3   14 lo
6:  3   33 hi
Frank
  • 66,179
  • 8
  • 96
  • 180