L. Rattis
L. Rattis

Reputation: 69

Changing the conditions to replace elements in a vector

Consider the vector:

use = c(1,1,2,2,5,1,2,1,2,5,1)

I'm trying to replace all the numbers different from 5 to NA before the first number 5 shows up in the sequence: ifelse(use != 5,NA,1). After that the condition should be ifelse(use != 5,0,1).

The output would be:

after = c(NA,NA,NA,NA,1,0,0,0,0,1,0)

Any tips?

Upvotes: 6

Views: 157

Answers (9)

akrun
akrun

Reputation: 886938

We can use match

replace(use, seq_len(match(5, use) - 1), NA)
#[1] NA NA NA NA  5  1  2  1  2  5  1

Or as @M-- commented, this can be changed to binary with

+(replace(use, seq_len(match(5, use) - 1), NA)==5)

Upvotes: 2

utubun
utubun

Reputation: 4520

Weird subsetting:

c(NA[!cumsum(use == 5)], +(use[!!cumsum(use == 5)] == 5))
#[1] NA NA NA NA  1  0  0  0  0  1  0

Upvotes: 2

ThomasIsCoding
ThomasIsCoding

Reputation: 101024

Here is a base R solution

after <- replace(v<- ifelse(use !=5,NA,1),
        which(head(which(v==1),1)<seq_along(v) & is.na(v)),
        0)

such that

> after
 [1] NA NA NA NA  1  0  0  0  0  1  0

Upvotes: 2

Onyambu
Onyambu

Reputation: 79188

You should try:

`is.na<-`(match(use, 5, 0), seq(match(5, use) - 1))
 [1] NA NA NA NA  1  0  0  0  0  1  0

Upvotes: 3

Richard Telford
Richard Telford

Reputation: 9923

You can use which to find the location of the target, and then case_when

use <- c(1,1,2,2,5,1,2,1,2)

first_five <- min(which(use == 5))
dplyr::case_when(
  seq_along(use) < first_five ~ NA_real_,
  seq_along(use) == first_five ~ 1, 
  TRUE ~ 0
)
#> [1] NA NA NA NA  1  0  0  0  0
use
#> [1] 1 1 2 2 5 1 2 1 2

Created on 2020-01-14 by the reprex package (v0.3.0)

Upvotes: 1

Filipe Lauar
Filipe Lauar

Reputation: 444

The following code solves the problem:

use[1:(which(use == 5)[1]-1)] = NA
use[(which(use == 5)[1]+1):length(use)] = 0
use[which(use == 5)[1]] = 1
use
[1] NA NA NA NA  1  0  0  0  0

Upvotes: 1

AndS.
AndS.

Reputation: 8110

Here is another variation. I through in some error handling in case there are no 5's in the vector.

test1 <-  c(1,1,1,1,2,3,3)
test2 <-  c(5,1,1,2,5,1,2,7,8)
test3 <-  c(1,1,3,5,6,7,8,2)
test4 <-  c(1,2,3,4,5,5,1,5,5,5,1,1,7,8,1)



find_and_replace <- function(vec, target){
  tryCatch(
    ifelse( seq_along(vec) %in% 1:{(which(vec == target)[[1]])-1}, NA, ifelse(vec == 5, 1, 0)),
    error = function(x) {
      warning(paste("Warning: No", target))
      vec
    }
  )
}

find_and_replace(test1, 5)
#> Warning: No 5
#> [1] 1 1 1 1 2 3 3
find_and_replace(test2, 5)
#> [1] NA  0  0  0  1  0  0  0  0
find_and_replace(test3, 5)
#> [1] NA NA NA  1  0  0  0  0
find_and_replace(test4, 5)
#> [1] NA NA NA NA  1  1  0  1  1  1  0  0  0  0  0

Upvotes: 1

Brian Davis
Brian Davis

Reputation: 992

This will work if there's only one 5 in your vector

use = c(1,1,2,2,5,1,2,2,2)
use <- findInterval(use,5)*5
i <- which(use > 0)
if(i > 1) use[1:(i-1)] <- NA

Upvotes: 1

Karsten W.
Karsten W.

Reputation: 18400

You could detect the first 5,

first_pos <- which(use==5)

and, if such elements exist, set all entries before the first occurence to NA:

if(length(first_pos)>0) {
    use[seq(1,first_pos[1]-1)] <- NA
    use[seq(1,first_pos[1])] <- 1
    use[seq(first_pos[1]+1, length(use)] <- 0
}

Note that first_pos[1] is called in case there are more than one 5.

Upvotes: 0

Related Questions