2

I am trying to replace all the groups of elements in a vector that sum up to zero with NAs. The size of each group is 3. For instance:

a = c(0,0,0,0,2,3,1,0,2,0,0,0,0,1,2,0,0,0)

should be finally:

c(NA,NA,NA,0,2,3,1,0,2,NA,NA,NA,0,1,2,NA,NA,NA)

Until now, I have managed to find the groups having the sum equal to zero via:

b = which(tapply(a,rep(1:(length(a)/3),each=3),sum) == 0)

which yields c(1,4,6)

I then calculate the starting indexes of the groups in the vector via: b <- b*3-2. Probably there is a more elegant way, but this is what I've stitched together so far. Now I am stuck at "expanding" the vector of start indexes, to generate a sequence of the elements to be replaced. For instance, if vector b now contains c(1,10,16), I will need a sequence c(1,2,3,10,11,12,16,17,18) which are the indexes of the elements to replace by NAs. If you have any idea of a solution without a for loop or even a more simple/elegant solution for the whole problem, I would appreciate it. Thank you.

Marius

Marius
  • 990
  • 1
  • 14
  • 34

3 Answers3

2

You can use something like this:

a[as.logical(ave(a, 0:(length(a)-1) %/% 3, 
             FUN = function(x) sum(x) == 0))] <- NA
a
#  [1] NA NA NA  0  2  3  1  0  2 NA NA NA  0  1  2 NA NA NA

The 0:(length(a)-1) %/% 3 creates groups of your desired length (in this case, 3) and ave is used to check whether those groups add to 0 or not.

A5C1D2H2I1M1N2O1R2T1
  • 190,393
  • 28
  • 405
  • 485
2

To designate the values to the same group turn your vector into (a three-row) matrix. You can then calculate the column-wise sums and compare with 0. The rest is simple.

a <- c(0,0,0,0,2,3,1,0,2,0,0,0,0,1,2,0,0,0)
a <- as.integer(a)
is.na(a) <- rep(colSums(matrix(a, 3L)) == 0L, each = 3L)
a
#[1] NA NA NA  0  2  3  1  0  2 NA NA NA  0  1  2 NA NA NA

Note that I make the comparison with integers to indicate that if your vector is not an integer, you need to consider this FAQ.

Community
  • 1
  • 1
Roland
  • 127,288
  • 10
  • 191
  • 288
  • 1
    @Marius My answer is a one-liner too (actually it's shorter than Ananda's code) and can be made more general by using `apply`. Probably, it's also faster. (This is just a reply to your remarks. I don't need the tick mark.) – Roland Sep 25 '14 at 10:45
0

Or using gl, ave and all

n <- length(a)
a[ave(!a, gl(n, 3, n), FUN=all)] <- NA
a
#[1] NA NA NA  0  2  3  1  0  2 NA NA NA  0  1  2 NA NA NA
akrun
  • 874,273
  • 37
  • 540
  • 662