4

I have a data frame with 10 items and I want to negate the even numbered rows. I came up with this monstrosity:

change_even <- data.frame(val=runif(10))
change_even$val[row(  as.matrix(change_even[,'val']) ) %% 2 == 0 ] <- -change_even$val[row(  as.matrix(change_even[,'val']) ) %% 2 == 0 ]

is there a better way?

catastrophic-failure
  • 3,759
  • 1
  • 24
  • 43
Andrew
  • 6,231
  • 2
  • 29
  • 37
  • 11
    Just `change_even$val*c(1,-1)`. – nicola Jan 04 '17 at 16:00
  • 1
    @nicola got the best answer actually, making the stupid R vector recycling rules look like a feature haha :) – catastrophic-failure Jan 04 '17 at 16:10
  • 3
    @catastrophic-failure Stupid? It's one of the greatest things of R IMO. – nicola Jan 04 '17 at 16:15
  • If @nicola's response were an answer I'd accept it. – Andrew Jan 04 '17 at 16:19
  • @nicola Recycling is handy in many situation (such as this one), but I wouldn't ever depend on it. It actually makes debugging harder, because the multiplication of vectors of different lengths works, so you'd have to catch that somehow. At least it shouldn't be default behavior. – catastrophic-failure Jan 04 '17 at 17:02
  • @catastrophic-failure Couldn't disagree more. I did depend on it on so many occasions I can't count and it allowed me to write code that would have been rather complicated otherwise in litterally seconds. It's one of the main reasons that keeps me to stick with R. My bet: play with R long enough and you'll eventually laugh at your own comment above and wonder how you could ever think that way. – nicola Jan 05 '17 at 07:29
  • @nicola as I said it's handy, but can cause much more harm than you perceive. I don't deny how useful it can be, but it can, and often will, make thinks harder to fix. Especially in collaborative coding. – catastrophic-failure Jan 05 '17 at 13:07
  • @catastrophic-failure It's been several years that I work with R with many others and would put recycling on the bottom of any list of "bug sources" in R. But the net total is hugely on the good side and I'm sure that every R expert agrees with me. Calling "stupid" this feature is LOL. Guess you have some strong other language background and you are trying to adapt other language's logic into R. That's a mistake. If you perceive this danger is because you are not "natively" thinking in R and didn't get deeply what recycling means and allows. – nicola Jan 05 '17 at 13:28

6 Answers6

8

Simply you can use recycling:

change_even$val*c(1,-1)
#[1]  0.1077468 -0.5418167  0.8319609 -0.7230043  0.6649786 -0.7232669
#[7]  0.2677659 -0.4035824  0.6880934 -0.5600653

(values are not reproducible since seed was not set; however the alternating sign can be seen clearly).

nicola
  • 24,005
  • 3
  • 35
  • 56
3

You can simply do,

change_even[c(FALSE,TRUE),] <- change_even[c(FALSE,TRUE),]*(-1)
Sotos
  • 51,121
  • 6
  • 32
  • 66
2

With a data.table, you can get similar with data.frame. Similar to here Selecting multiple odd or even columns/rows for dataframe in R

library(data.table)   
change_even <- data.table(val=runif(10))
even_indexes<-seq(2,nrow(change_even),2)
change_even <- change_even[even_indexes,val:=val*-1]
Community
  • 1
  • 1
iboboboru
  • 1,112
  • 2
  • 10
  • 21
2

Use the remainder operator to find the even numbered rows, then simply negate

change_even <- data.frame(val=runif(10))
change_even[seq(nrow(change_even)) %% 2 != 1,] = -change_even[seq(nrow(change_even)) %% 2 != 1,]
catastrophic-failure
  • 3,759
  • 1
  • 24
  • 43
1

This is what I came up with:

change_even$val = change_even$val * c(rep(-1,nrow(change_even))^((row(change_even)+1)))
d.b
  • 32,245
  • 6
  • 36
  • 77
1

Another one:

(-1)^(0:(nrow(change_even)-1))*change_even$val
Sandipan Dey
  • 21,482
  • 2
  • 51
  • 63