2

I have a data frame as follows:

DF<-data.frame(a=c(1,1,1,2,2,2,3,3,4,4),b=c(43,23,45,65,43,23,65,76,87,4))

a  b
1 43
1 23
1 45
2 65
2 43
2 23
3 65
3 76
4 87
4  4

I want to set a flag like this:

a  b flag
1 43 A
1 23 B
1 45 C
2 65 A
2 43 B
2 23 C
3 65 A
3 76 B
4 87 A
4  4 B

How can I get this done in R?

David Arenburg
  • 91,361
  • 17
  • 137
  • 196
Next Door Engineer
  • 2,818
  • 4
  • 20
  • 33
  • 2
    `DF %>% group_by(a) %>% mutate(flag=LETTERS[row_number()])` – Khashaa Jan 14 '15 at 10:19
  • 2
    @Khashaa, nice one. You should post this as an answer. Similarly with data.table `setDT(DF)[, flag := LETTERS[1:.N], a]` – David Arenburg Jan 14 '15 at 10:30
  • And a soon to be vintage solution: `do.call("c", sapply(rle(DF$a)$lengths, FUN = function(x) LETTERS[1:x]))`. – Roman Luštrik Jan 14 '15 at 10:42
  • This is close to a FAQ, see e.g. [**here**](http://stackoverflow.com/questions/12925063/numbering-rows-within-groups-in-a-data-frame/12925090#12925090) and [**here**](http://stackoverflow.com/questions/6150968/adding-an-repeated-index-for-factors/6151333#6151333). Just add the `LETTERS` part, but see the comment of @James. – Henrik Jan 14 '15 at 11:18

2 Answers2

4

Using dplyr

library(dplyr)
DF %>% group_by(a) %>% mutate(flag=LETTERS[row_number()])

Using data.table(HT to @David Arenberg)

library(data.table)
setDT(DF)[, flag := LETTERS[1:.N], a]   

And a soon to be vintage solution (by @Roman Luštrik)

do.call("c", sapply(rle(DF$a)$lengths, FUN = function(x) LETTERS[1:x]))

Addendum

@akrun suggested following extension of the LETTERS to address the immediate question arose "What if there is more than 26 groups?" (by @James)

Let <- unlist(sapply(1:3, function(i) do.call(paste0,expand.grid(rep(list(LETTERS),i)))))

All above codes remain fully functional, when LETTERS replaced by Let.

Khashaa
  • 7,293
  • 2
  • 21
  • 37
  • What happens if you have more than 26 elements in a group? – James Jan 14 '15 at 10:50
  • 3
    @James I guess that's a question to the OP. – David Arenburg Jan 14 '15 at 10:52
  • 3
    @Khashaa In case, more than 26 elements in group, one option is `Let <- unlist(sapply(1:3, function(i) do.call(paste0,expand.grid(rep(list(LETTERS),i)))), use.names=FALSE); setDT(DF)[, flag:= Let[1:.N], a][]` – akrun Jan 14 '15 at 11:37
2

I'll thrown in one more in base R:

transform(DF, flag = LETTERS[ave(a,a,FUN=seq_along)])
talat
  • 68,970
  • 21
  • 126
  • 157