3

(sorry, really don't know how to better phrase this question)

I have a column "have" with 1s and 0s. I want to create a new column "want" where, each time a 1 has occurred, the value of 0 increases to 2, then 3, then 4, etc. 0 should never be 1.

Example:

data <- data.frame(have = (c('0', '0', '0', '0', '1', '0', '1', '0', '0', '1')), 
                   want = (c('0', '0', '0', '0', '1', '2', '1', '3', '3', '1')))                       
user303287
  • 131
  • 5

5 Answers5

2

You could do:

data <- data.frame(have = (c('0', '0', '0', '0', '1', '0', '1', '0', '0', '1')))  

data$want <- cumsum(as.numeric(data$have)) + 1
data$want[data$want == "1"] <- "0"
data$want[data$have == "1"] <- "1"

data
#>    have want
#> 1     0    0
#> 2     0    0
#> 3     0    0
#> 4     0    0
#> 5     1    1
#> 6     0    2
#> 7     1    1
#> 8     0    3
#> 9     0    3
#> 10    1    1

Created on 2022-04-06 by the reprex package (v2.0.1)

Allan Cameron
  • 147,086
  • 7
  • 49
  • 87
2

Using the rle

f <- \(x) {
  rl <- rle(x)
  rl0 <- which(rl$values == 0)
  rl$values[rl0[-1]] <- seq_along(rl$values[rl0[-1]]) + 1
  rep(rl$values, rl$lengths)
}

transform(data, want=f(have))
#    have want
# 1     0    0
# 2     0    0
# 3     0    0
# 4     0    0
# 5     1    1
# 6     0    2
# 7     1    1
# 8     0    3
# 9     0    3
# 10    1    1
jay.sf
  • 60,139
  • 8
  • 53
  • 110
2

Here's another alternative:

transform(data,
          want = pmin(cumsum(have) + cummax(have), 0^-(have != 1)))

   have want
1     0    0
2     0    0
3     0    0
4     0    0
5     1    1
6     0    2
7     1    1
8     0    3
9     0    3
10    1    1
Ritchie Sacramento
  • 29,890
  • 4
  • 48
  • 56
1
df <- data.frame(have = (c('0', '0', '0', '0', '1', '0', '1', '0', '0', '1')), 
                   want = (c('0', '0', '0', '0', '1', '2', '1', '3', '3', '1')))


df$want2 <- ifelse(df$have == 1, 1, ifelse(cumsum(df$have) == 0, 0, 1 + cumsum(df$have == 1)))

df
Lennyy
  • 5,932
  • 2
  • 10
  • 23
1

What about this?

transform(
    df,
    want = replace(
        replace(
            cumsum(have == 1) + 1,
            have == 1,
            1
        ),
        seq_along(have) < min(which(have == 1)),
        0
    )
)

Output

   have want
1     0    0
2     0    0
3     0    0
4     0    0
5     1    1
6     0    2
7     1    1
8     0    3
9     0    3
10    1    1
ThomasIsCoding
  • 96,636
  • 9
  • 24
  • 81
  • Thanks very much, this works, the only thing is that if there are numerous consecutive 1s in the "have", then it then "amplifies" the next value (so if two 1s, then the value inerted goes from 1 to 3). This is not a problem for my purpose though, as I am just after a unique id, which it still is. :-) – user303287 Apr 06 '22 at 09:47
  • @user303287 Good feedback. I guess you can put this info (better with an example) in your post. – ThomasIsCoding Apr 06 '22 at 11:35