Check if numbers in a vector are alternating in R - 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)

Related

Longest conditional run in a vector in R

Given a single vector, I would like to find the longest run, which meets this: the count is being stopped when there is a run of x>1 for the first time, which has got length of at least 5.
For example, I got a vector X:
X <- c(2,3,4,0,1,0,0,0,3,2,2,0,3,3,3,3,3,0,0,0)
My desired run has got length of 12, its end is the beggining of the first run of x>1 which is at least 5 numbers long.
I know my question is not asked in the most aesthetic way, but I think that I explained it sufficiently.
Maybe you are looking for this -
with(rle(X > 1), {
val <- max(lengths[values & lengths >= 5])
inds <- which(values & lengths == val) - 1
cumsum(lengths)[inds]
})
#[1] 12

Find position of closest value to another value given a condition in R

let's say I have a vector that increases and then decreases like the simple example below. I want to identify the position (index) in the vector that is closest to a value - but with the condition that the following value must be lower (I always want to pick up the closest value on the downslope of the data).
In the example below, I want the answer to be 13 (rather than 6).
I can't think of a solution using which.min() or match.closest() which would reliably work for this.
Any help gratefully received!
# example vector which increases then decreases
vector <- c(1,2,3,4,5,6,7,8,9,9,8,7,6,5,4,3,2,1)
# index
index <- c(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18)
value <- 6.2
Maybe you can use cummax + rev like below
which.min(abs(rev(cummax(rev(vector)))-value))
which gives
[1] 13
Assuming your points always continue to decrease in value after the first decrease, and value is between the point of the first decrease and the last point, you could do this:
closest <- function(value, vec, next_is){
lead_fun <- function(x) c(tail(x, -1), NA)
meets_cond <- get(next_is)(lead_fun(vec), vec)
which.min(abs(vec[meets_cond] - value)) + which.max(meets_cond) - 1
}
closest(6.2, vec = vector, next_is = '<')
# [1] 13
Check which elements in the vector meet your condition, find the index of the closest element in that vector, then add back the number of elements before the first which meets your condition.
Edit: ----------------------------------------
Another version of the function which accepts an arbitrary logical vector which is TRUE for indices meeting a condition:
closest <- function(value, vec, cond_vec){
which.min(abs(vec[cond_vec] - value)) + which.max(cond_vec) - 1
}
Note that this assumes the values matching your condition are all in one contiguous region (not e.g. the first matches, then the third, then the sixth, etc.)
If your condition is that the point comes after the max value:
closest(6.2, vec = vector, cond_vec = seq_along(vector) > which.max(vector))
# [1] 13

sampling bug in R? [duplicate]

This question already has answers here:
Sample from vector of varying length (including 1)
(4 answers)
Closed 4 years ago.
I am trying to sample one element out of a numeric vector.
When the length of the vector > 1, the result is one of the numbers of the vector, as expected. However when the vector contains one element, it samples a number between 0 and this single number.
For example:
sample(c(100, 1000), 1)
results in either 100 or 1000, however
sample(c(100), 1)
results in different numbers smaller than 100.
What is going on?
Have a look at the Details of the sample function:
"If x has length 1, is numeric (in the sense of is.numeric) and x >= 1, sampling via sample takes place from 1:x"
This is (unfortunately) expected behavior. See ?sample. The first line of the Details section:
If x has length 1, is numeric (in the sense of is.numeric) and x >= 1, sampling via sample takes place from 1:x. Note that this convenience feature may lead to undesired behaviour when x is of varying length in calls such as sample(x). See the examples.
Luckily the Examples section provides a suggested fix:
# sample()'s surprise -- example
x <- 1:10
sample(x[x > 8]) # length 2
sample(x[x > 9]) # oops -- length 10!
sample(x[x > 10]) # length 0
## safer version:
resample <- function(x, ...) x[sample.int(length(x), ...)]
resample(x[x > 8]) # length 2
resample(x[x > 9]) # length 1
resample(x[x > 10]) # length 0
You could, of course, also just use an if statement:
sampled_x = if (length(my_x) == 1) my_x else sample(my_x, size = 1)

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.

R ifelse sequence always 0

I want to have a sequence for a certain case. For this I use an ifelse statement, but I always receive zero. Here is a simple example:
seq(0,10, by=1)
[1] 0 1 2 3 4 5 6 7 8 9 10
while
ifelse (1==1, seq(0,10, by=1), seq(0,10, by=1))
[1] 0
I don't see, why I would get 0 in the second case.
Best,
Mat
Your first argument is of length one - so the output will be of length 1. It is true, so is returning the first element of your second argument, which is 0.
Maybe you want
if (1==1) {
seq(0,10, by=1)
} else {
seq(0,10, by=1)
}
Neither is a very realistic piece of code, though
I don't think you understand the use of ifelse completely. Your condition (1 == 1) is always true, so you know the answer in advance. Moreover the result for positive and negative examples is the same.
You use ifelse to test a vector on a certain condition. If a value in the vector abides to the condition the first value is returned, if it doesn't the second one is returned. For example;
test <- sample(letters[1:2], 100, replace = T)
ifelse(test == "a", 'is a', 'is b')
The result will always be of the same length as the input vector. If your return values have a length longer than 1, the ifelse will be aborted if the length of the input vector is reached. This implies that values in the import vector remain unevaluated. So you typically don't want to use the ifelse when your return values are longer than 1.

Resources