How to find if two or more continuously elements of a vector are equal in R - 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.

Related

R condtional replace in a 3d array

I want to conditionally replace values in a specific vector in a 3d array, the replacement value being a value from a probability calculation. For some reason the replacement value is the same for all values of the vector, rather than being calculated on an individual vector element basis. I must have something simple incorrect in my syntax
library (abind)
pop <- array(c (1,0,1,1,1,0,0,0,0,0,2,0,2,3,5), dim = c(1,5,3))
pop <- abind(pop,pop, along = 1)
so the particular vector I want to work on is
pop[dim(pop)[1], ,1]
[1] 1 0 1 1 1
what I want to achieve is to leave the zero value alone, and if the value is one, then run a random binomial test, to see if it changes to zero, and if it does change, do the insertion. I'm told that the ifelse is vectorized but with this syntax it is not operating individually on each element of the vector. When I try to produce a new vector as such
ifelse (pop[dim(pop)[1], ,1] == 1, rbinom(1,1,0.5), 0)
I get either no change
> ifelse (pop[dim(pop)[1], ,1] == 1, rbinom(1,1,0.5), 0)
[1] 1 0 1 1 1
or alternatively it changes all values.
> ifelse (pop[dim(pop)[1], ,1] == 1, rbinom(1,1,0.5), 0)
[1] 0 0 0 0 0
I'm expecting some of the values in the array to be changed, but not "all or nothing". What am I doing wrong? Also if there is a simple elegant way to do the substitution back into the original 3d array I'd be grateful. Thx. J
I think I did find a solution using the "modify_if" function of the dplyr package.
pop[dim(pop)[1], ,1] %<>% modify_if(~ .x == 1, ~ rbinom(1,1,pliv1))
HTH, J

Randomly sampling from each element of a vector

Let's say I have a numeric vector X
X <- c(1,42,1,23,5,7)
I would like to create another vector Y with the same number of elements, each of which is a randomly generated whole number from a sequence in which 1 is the lower bound and the element in X is the upper bound e.g for Y[2] the number would be a randomly generated number selected from between 1 and 42 and for Y[4] the number would be randomly selected from between 1 and 23.
I have tried to use the apply function to do this
Y<-apply(C, 1, sample)
but I am having no luck and generating the error message
Error in apply(X, 1, sample) : dim(X) must have a positive length1,
sample
Is there a better way to do this?
You can't use apply for a vector, but for multidimensional objects only (e.g., matrices). You have to use sapply instead. Futhermore, you need the argument size = 1 since you want to sample one value for each entry of X.
sapply(X, sample, size = 1)
[1] 1 7 1 16 3 6

Check if numbers in a vector are alternating in R

i need to check if the first number of a vector is smaller than the second number and the second number is greater than the third number and so on. I got so far that i can calculate the differences of the numbers of a vector like this:
n <- sample(3) #may n = 132
diff(n) # outputs 2 -1
I need to check if the first number is positive, the second negative etc. The problem i have is that i need the program to do it for a vector of length n. How can i implement this?
As it is not very clear what i am trying to do here i will give a better example:
May v be a vector c(1,2,4,3).
I need to check if the first number of the vector is smaller than the second, the second greater than the third, the third smaller than the fourth.
So i need to check if 1 < 2 > 4 < 3. (This vector wouldn´t meet the requirements) Every number i will get will be > 0 and is guaranteed to just be there once.
This process needs to be generalized to a given n which is > 0 and a natural number.
v <- c(1, 2, 4, 3)
all(sign(diff(v)) == c(1, -1))
# [1] FALSE
# Warning message:
# In sign(diff(v)) == c(1, -1) :
# longer object length is not a multiple of shorter object length
We can safely ignore the warning message, since we make deliberate use of "recycling" (which means c(1, -1) is implicitly repeated to match the length of sign(diff(v))).
Edit: taking #digEmAll's comment into account, if you want to allow a negative difference rather than a positive one at the start of the sequence, then this naive change should do it:
diffs <- sign(diff(v))
all(diffs == c(1, -1)) || all(diffs == c(-1, 1))
If we need to find whether there are alternative postive, negative difference, then
all(rle(as.vector(tapply(n, as.integer(gl(length(n),
2, length(n))), FUN = diff)))$lengths==1)
#[1] TRUE
Also, as #digEmAll commented and the variation of my initial response
all(rle(sign(diff(n)) > 0)$lengths == 1)
data
n <- c(1, 2, 4, 3)

Changing values at specific indices - 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.

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