Changing values at specific indices - R - r

I have two vectors a & b.
a <- c(1,0,1,0,0,0,1)
b <- c(.2,.9,.3,.9,.8,.78,.3)
and I want to subtract 1 from all values in b that correspond to indices for 1 in a. I can extract the indices of all values that are 1 in a by doing which(a == 1). I tried doing something like b <- 1 - b[which(a == 1)] but this didn't work. Is there some way to do this without using a for loop?

We can convert the binary vector 'a' to logical by double negation (!! - converts 1 to TRUE and 0 to FALSE) or by just wrapping with as.logical or as in the OP's code (a==1). This will subset the values in 'b' that corresponds to TRUE/1 in 'a'. Subtract 1 from those values and assign the output back to those values in 'b'
b[a==1] <- 1 - b[a==1]
Or we can use ifelse
ifelse(a==1, 1-b, b)
In the OP's code, wrapping with which is not needed and also assigning to 'b' with a subset of elements of 'b' replaces the original vector 'b' with the subset 'b'

Your a vector is 0's and 1's. If you want to subtract 1 from b whenever a is 1, and do nothing (aka subtract 0) from b whenever a is 0, then this is just subtraction:
b - a
If your a vector has values other than 0 or 1, then you'll need a slightly more complicated, more general method as in #akrun's answer.
Another "more complex" variant would use the implicit meaning of TRUE as 1 and FALSE as 0 to do
b - (a == 1)
Upon re-reading, you might need to clarify what you want. Your text says subtract 1 from all values in b, which implies b - (1 or 0). However, you code attempt is 1 - b, subtracting b from 1 not 1 from b, in which case akrun's answer is perfect and mine would need some adjustments.

Related

assign values to vector in a dataframe based on conditions from other vectors in R

so I have a partially empty dataframe and I need to assign values to a vector that we may call "C" based on different outcomes of an other vector which we may call B. The values to assign to C are taken, in some determined cases, from a third vector, "A". How can I do that? I tried if statements and for loops but don't know how to do them properly. Here's summarized my problem.
Thank you for your answers
A = (1,2,3,4,5,6,7,8,9,10)
B = (1,0,1,2,1,0,0,2,0,1)
C = 0 if B = 0
=A(same row) if B = 1
=-A(same row) if B =-1
An option is to get the sign of 'B' and multiply with 'A'
C <- sign(B) * A

How to find if two or more continuously elements of a vector are equal in R

I want to find a way to determine if two or more continuously elements of a vector are equal.
For example, in vector x=c(1,1,1,2,3,1,3), the first, the second and the third element are equal.
With the following command, I can determine if a vector, say y, contains two or more continuously elements that are equal to 2 or 3
all(rle(y)$lengths[which( rle(y)$values==2 | rle(y)$values==3 )]==1)
Is there any other faster way?
EDIT
Let say we have the vector z=c(1,1,2,1,2,2,3,2,3,3).
I want a vector with three elements as output. The first element will refer to value 1, the second to 2 and the third one to 3. The values of the elements of the output vector will be equal to 1 if two or more continuously elements of z are the same for one value of 1,2,3 and 0 otherwise. So, the output for the vector z will be (1,1,1).
For the vector w=c(1,1,2,3,2,3,1) the output will be 1,0,0, since only for the value 1 there are two continuously elements, that is in the first and in the second position of w.
I'm not entirely sure if I'm understanding your question as it could be worded better. The first part just asks how you find if continuous elements in a vector are equal. The answer is to use the diff() function combined with a check for a difference of zero:
z <- c(1,1,2,1,2,2,3,2,3,3)
sort(unique(z[which(diff(z) == 0)]))
# [1] 1 2 3
w <- c(1,1,2,3,2,3,1)
sort(unique(w[which(diff(w) == 0)]))
# [1] 1
But your edit example seems to imply you are looking to see if there are repeated units in a vector, of which will only be the integers 1, 2, or 3. Your output will always be X, Y, Z, where
X is 1 if there is at least one "1" repeated, else 0
Y is 2 if there is at least one "2" repeated, else 0
Z is 3 if there is at least one "3" repeated, else 0
Is this correct?
If so, see the following
continuously <- function(x){
s <- sort(unique(x[which(diff(x) == 0)]))
output <- c(0,0,0)
output[s] <- s
return(output)
}
continuously(z)
# [1] 1 2 3
continuously(w)
# [1] 1 0 0
Assuming your series name is z=c(1,1,2,1,2,2,3,2,3,3) then you can do:
(unique(z[c(FALSE, diff(z) == 0)]) >= 0)+0 which will output to 1, 1, 1,
When you run the above command on your other sequenc:
w=c(1,1,2,3,2,3,1)
then (unique(w[c(FALSE, diff(w) == 0)]) >= 0)+0 will return to 1
You may also try this for an exact output like 1,1,1 or 1,0,0
(unique(z[c(FALSE, diff(z) == 0)]) == unique(z))+0 #1,1,1 for z and 1,0,0 for w
Logic:
diff command will take difference between corresponding second and prior items, since total differences will always 1 less than the number of items, I have added first item as FALSE. Then subsetted with your original sequences and for boolean comparison whether the difference returned is zero or not. Finally we convert them to 1s by asking if they are greater than or equal to 0 (To get series of 1s, you may also check it with some other conditions to get 1s).
Assuming your sequence doesn't have negative numbers.

combine two vectors using cbind and either or argument

I have a simple question but don't know how to do it myself. I have two vectors where each contains '0' and '1' numeric values. My aim is to combine two vectors as one, and have something like this:
A <- c(1,1,0,0,0,1)
B <- c(0,1,1,0,0,1)
after combining two:
C <- c(1,1,1,0,0,1)
Basically, if either of them has 1, then it should be combined as 1, if both of them have 1, then it should be 1 too, if none of them have 1, then it should be 0.
Hope you can answer
Thank you much!
-G
We can use pmax to get the output
pmax(A, B)
Or with | to coerce the binary vectors to a logical vector and then change it to binary with + or (as.integer)
+(A|B)
#[1] 1 1 1 0 0 1

How to match elements in 2 matrices and create a new matrix with specific values dependent on previous matrices in R?

I have two matrices, A and B both are 100*100. Both these matrices have positive and negative numbers. I want to create a matrix C with the same dimensions and the elements in this matrix are dependent on the elements at the same position in matrices A and B.
For example if I have 22 and 1 in position [1,1] in matrix A and B, I want to assign a value 1 at the same position in matrix C because both A and B have values above 0. Similarly for every values in C they are all dependent on whether values in matrices A AND B (in the same position) are above 0 or not. This is how my code looks like at the moment,
C<-matrix(0,100,100) #create a matrix with same dimensions and populated with 0
C[A>0 && B>0] = 1
My matrix A satisfies the condition A>0 as there are some negative and some positive values, matrix B also satisfies the condition B>0 as some values are negative and some positive. However my code does not result in a matrix C with values of 0 and 1, even when I know there are some positions which meet the requirement of both matrix A and B being above 0. Instead the matrix C always contains 0 for some reason.
Could any one let me know what I am doing wrong and how do I correct it or perhaps a different way to achieve this? Thanks
Does C[A>0 & B>0] = 1 work? && returns a single value, but & is vectorized so it will work on each cell individually.
This may not be the most efficient way to do it, but it works.
C <- matrix(0, 100, 100)
for (i in seq_along(C))
if (A[i] > 0 && B[i] > 0)
C[i] <- 1
When you create a sequence along a matrix using seq_along(), it goes through all elements in column-major order. (Thereby avoiding a double for loop.) And since the elements of A, B, and C match up, this should give you what you want.

Select matrix column (resp. row) as Nx1 (resp. 1xD) matrix, as opposed to vector

Let X be an N by D matrix. Selecting a submatrix of size n by d returns a matrix of those dimensions unless at least one of n and d equals 1, in which case we get a vector instead. Interestingly, R still returns a matrix of the correct dimensions even if one of n and d are 0, and the other not 1.
Now, if we are certain that n!=1, then executing cbind(X[row.subset,col.subset]) will return a matrix of the correct dimensions regardless of whether d==1 or not (here n=length(row.subset) and d=length(col.subset)). If we are certain that d!=1, then we can use rbind(...). But if both n and d can be 1, neither approach will work since we could accidentally turn a row into a column or vice versa.
As far as I can tell, one way to always get a matrix of the right dimensions is to call matrix(X[row.subset,col.subset],nrow=n,ncol=d). However, it doesn't feel like that should be the right way to go about it, plus I'm not confident that there is no performance penalty. Is there a more "native" solution?
Here's a working example:
N <- 6
D <- 3
X <- matrix(rnorm(N*D),ncol=D)
dim(X[1:2,1:2]) #returns 2 2
dim(X[1:2,1]) #returns NULL, this is a vector
dim(cbind(X[1:2,1])) #returns 2 1
dim(cbind(X[1,1:2])) #returns 2 1, but we'd like it to be 1 2
dim(rbind(X[1,1:2])) #returns 1 2
dim(rbind(X[1:2,1])) #returns 1 2, but we'd like it to be 2 1
row.subset <- 1:4
col.subset <- 2
#I _think_ this is always correct, but it's verbose:
matrix(X[row.subset,col.subset],nrow=length(row.subset),ncol=length(col.subset))
Thanks in advance.
If you don't want to simplify matrix subsets to vectors just tell [ not to drop dimensions:
> dim(X[1:2,1, drop=FALSE])
[1] 2 1
> dim(X[1,1:2, drop=FALSE])
[1] 1 2
See ?"[" for details.

Resources