Marius
Marius

Reputation: 1060

r - replacing groups of elements in vector

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

Upvotes: 2

Views: 126

Answers (3)

akrun
akrun

Reputation: 887901

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

Upvotes: 0

Roland
Roland

Reputation: 132969

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.

Upvotes: 2

A5C1D2H2I1M1N2O1R2T1
A5C1D2H2I1M1N2O1R2T1

Reputation: 193687

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.

Upvotes: 2

Related Questions