0

I have some R that is, for example:

x<-c(-3,1,-5,7,-10)
y<-c(1,2,3,4,5)

I want to check the elements of x against some condition, i.e. <0, and if true, manipulate y based on that.

For example, if my logical check was x<0, then elements [0],[2],[4] of y would be modified, i.e.:

print(y)
y=[0,2,0,3,0]

I've googled around a bit and cant find anything that does it element-wise. I'm sure that is a failing of google-fu, but help much appreciated.

Henry
  • 1,646
  • 12
  • 28
  • 2
    In R, indexing starts at 1. You can try `y[x < 0] <- 0`. Your desired output also seems off. Are you looking for `y=[0,2,0,4,0]`? – Pierre L Sep 23 '15 at 15:06
  • I think there is a mistake. The expected output should probably be `0 2 0 4 0`. – RHertel Sep 23 '15 at 15:08
  • Sorry, yes, I mean elements 1 3 and 5, if R counts from 1. – Henry Sep 23 '15 at 15:09
  • Your suggested method works well in the test case above, but it doesnt seem to be working in my script. Will investigate further, must be a screw up by me. – Henry Sep 23 '15 at 15:11
  • I found the problem. I was logically checking if it was <-5, so I was doing y[x<-5]... which of course is an assignment operator. Thanks! – Henry Sep 23 '15 at 15:13

3 Answers3

10
y[x < 0] <- 0
y
#[1] 0 2 0 4 0

Indexing starts at 1 in R. We can subset y by the logical index of x < 0. One strength of R is the ability to subset by names, booleans, and numbers.

These two functions return the same output y[c(TRUE, FALSE, TRUE, FALSE, TRUE)] and y[c(1,3,5)]. The function attempts to determine which type of subsetting you are doing.

The third case for subsetting can't be used in this example because y doesn't have names. But if we named the vector, we can subset that way too.

names(y) <- c("A", "B", "C", "D", "E")
y[c("A", "C", "E")]

It also appears that you were slowed down by spacing and assignment operators. It is unique to R, but <- is similar to =.

x<-5

In this case, <- gets priority in the order of operations and is equivalent to x = 5, not x < -5.

Pierre L
  • 28,203
  • 6
  • 47
  • 69
3

For instance this would add 1 to those values.

y[x < 0] <- y[x < 0] + 1

Assuming you want to keep all of the Y elements:

y <- ifelse(x < 0, 0, y)
Rich Scriven
  • 97,041
  • 11
  • 181
  • 245
Badger
  • 1,043
  • 10
  • 25
  • 1
    My answer is very similar to @Pierre Lafortune, notably his is far more elegant. Lots of ways to get work done in R! Enjoy! – Badger Sep 23 '15 at 15:14
  • Thanks, I got it working. I was logically checking against -5, i.e. y[x<-5]... Dumb. Thanks! – Henry Sep 23 '15 at 15:14
3

Due to the way boolian variables are implemented, you can use them in arithmetic as if they are 0 or 1, and therefore for your example you can use:

y*(x>=0)
[1] 0 2 0 4 0

For a more general purpose method, the replace function exists:

replace(y,x<0,0)
[1] 0 2 0 4 0
James
  • 65,548
  • 14
  • 155
  • 193
  • This first one has the advantage of having no copies made. And I imagine it's also faster. – Rich Scriven Sep 23 '15 at 15:19
  • @RichardScriven If you want to get all benchmarky about it, this operation does replacement by reference: `library(data.table); setDT(list(y))[x<0, V1 := 0]` (as far as I can tell, looking at `address` before and after). Taken from eddi's answer: http://stackoverflow.com/questions/30344192/sub-assign-by-reference-on-vector-in-r – Frank Sep 23 '15 at 15:26
  • Not too concerned about it. But I do like this first answer. With all the code golf going on around here I figured this would get more votes. – Rich Scriven Sep 23 '15 at 15:28