Grace Sutton
Grace Sutton

Reputation: 113

Create unique id for each binary section

I have made a binary column "y/n" represented by 1 and 0 (yes and no, respecively). I now want to give each section marked 1 a unique id based on the name of the file and the position in the column. Below is an example of what I would like it to look like. I have no preference for what 0 should be, just as long as the sections marked as 1 have a unique id.

> y/n         id                       
> 1                    catid_a                 
> 1                    catid_a                                      
> 1                    catid_a                 
> 0                    no_id                                     
> 1                    catid_b                                     
> 1                    catid_b                 
> 0                    no_id 

Usually to name an id I use data$id <- as.factor(substr(basename(files[i]),1,13)) but it doesn't work in this instance as I want to have multiple id's in a column this just gives one.. does anyone have any ideas?

Thanks! Grace

Upvotes: 1

Views: 154

Answers (2)

Sotos
Sotos

Reputation: 51592

Another idea (using @akrun's dataset),

y <- replace(paste0('catid_', cumsum(c(1, diff(df1$`y/n`) != 0))), df1$`y/n` == 0, 'no_id')

y
#[1] "catid_1" "catid_1" "catid_1" "no_id"   "catid_3" "catid_3" "no_id"

To get the values to be sequential, we need to add a couple of more lines and include a package,

yy <- as.numeric(gsub('\\D+', '', y[grepl('[0-9]+', y)]))
y[grepl('[0-9]+', y)] <- stringi::stri_replace_all_regex(y[grepl('[0-9]+', y)], '[0-9]+', 
                                                                 cumsum(c(1, diff(yy)!=0)))

y
#[1] "catid_1" "catid_1" "catid_1" "no_id"   "catid_2" "catid_2" "no_id"

Upvotes: 1

akrun
akrun

Reputation: 887501

We can use rle

df1$id <-inverse.rle(within.list(rle(df1$`y/n`), {val1 <- values
               val1[values!=0] <- paste0("catid_", letters[seq_along(values[values!=0])])
              val1[values==0] <- "no_id"
                values <- val1}))
df1$id
#[1] "catid_a" "catid_a" "catid_a" "no_id"   "catid_b" "catid_b" "no_id"  

Or another option is rleid from data.table

library(data.table)
setDT(df1)[, grp := rleid(`y/n`)][`y/n`==0,  id := 'no_id' ,grp
      ][is.na(id), id := paste0("catid_", letters[.GRP]), grp][, grp := NULL][]
#   y/n      id
#1:   1 catid_a
#2:   1 catid_a
#3:   1 catid_a
#4:   0   no_id
#5:   1 catid_b
#6:   1 catid_b
#7:   0   no_id

data

df1 <- structure(list(`y/n` = c(1, 1, 1, 0, 1, 1, 0)), .Names = "y/n", row.names = c(NA, 
 -7L), class = "data.frame")

Upvotes: 1

Related Questions