I have a logical vector
vector1 <- c(F,F,T,F,F)
and I want to create a vector2 with the same values as vector1 but when vector1[i] == TRUE vector2[i-1], vector2[i] and vector2[i+1] has to be also TRUE.
What is the best way to do this? the ideal would be to create a function also since I will have to this for many other vectors...
One way using boolean comparison is:
c(vector1[-1], FALSE) | vector1 | c(FALSE, vector1[-length(vector1)])
Value is TRUE at a position if the preceding is TRUE, or the position is TRUE or the next position is TRUE. First and last values are boundaries and have no preceding or next values, that is why positions are completed by FALSE.
For more than one position, here two:
lag <- 2
c(vector1[-(1:lag)], rep(FALSE, lag)) | vector1 | c(rep(FALSE, lag), vector1[-(length(vector1)-lag+1:length(vector1))])
[1] TRUE FALSE TRUE FALSE TRUE
You can also try dplyr:
case_when(lead(vector1) ~ TRUE,
lag(vector1) ~ TRUE,
TRUE ~ vector1)
[1] FALSE TRUE TRUE TRUE FALSE
You can do :
#Copy vector1 elements
vector2 <- vector1
#Get indices where vector has TRUE elements
inds <- which(vector2)
#Get +1 and -1 position of each TRUE value
inds1 <- unique(c(inds + 1, inds - 1))
#Remove values which are out of range
inds1 <- inds1[inds1 <= length(vector2) & inds1 >= 1]
#Assign TRUE values
vector2[inds1] <- TRUE
vector2
#[1] FALSE TRUE TRUE TRUE FALSE
Related
I've two vectors with different lengths and want to get all the occurrences of the first one in the second one.
I've tried:
vec <- c("jan-fev-mar", "abr-mai-jun", "jul-ago-set")
vec2 <- c("jan-fev-mar", "abr-mai-jun", "jul-ago-set", "out-nov-dez", "jan-fev-mar", "abr-mai-jun", "jul-ago-set", "out-nov-dez")
# It returns: TRUE TRUE TRUE
vec %in% vec2
I expect to get all the occurrences of vec on vec2, like: TRUE TRUE TRUE FALSE TRUE TRUE TRUE FALSE
vec %in% vec2 returns TRUE for each element in vec if there is a match in all elements of vec2. The result is a logical vector of length equal to length(vec).
It seems you want vec2 %in% vec, which returns:
vec2 %in% vec
[1] TRUE TRUE TRUE FALSE TRUE TRUE TRUE FALSE
You could interpret it like the following:
(vec2 %in% vec)[1]: There is a match of vec2[1] (= "jan-fev-mar") in vec? TRUE
(vec2 %in% vec)[2]: There is a match of vec2[2] (= "abr-mai-jun") in vec? TRUE
...
(vec2 %in% vec)[8]: There is a match of vec2[8] (= "out-nov-dez") in vec? FALSE
Am I missing a better way of doing this - or at least a way that allows to vary the window size?
Say I have a vector, v.
v <- c(T,T,F,F,F,F,F,T,T,T,T,F,F,F,F,T,F,F,F,F,F,F,T,F)
I wish to convert this vector such that FALSEs are turned to TRUEs if a TRUE appeared within the previous 3 elements. e.g. the F's at positions 3,4,5 would also switch to T's as there is a T at position 2. The F at position 6 would not.
Solution if only interested in a window of 3:
vlag1 <- lag(v)
vlag2 <- lag(vlag1)
vlag3 <- lag(vlag2)
ifelse(v==T|vlag1==T|vlag2==T|vlag3==T,T,F)
Gives the desired result:
TRUE TRUE TRUE TRUE TRUE FALSE FALSE TRUE TRUE TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE TRUE TRUE FALSE FALSE FALSE TRUE TRUE
But what if we wanted to vary the window to e.g. 4 or 5 - is there a better way?
You could do this with rollapply from the zoo package:
library(zoo)
rollapply(v,
width = 4, align = "right", partial = TRUE,
FUN = function(x) ifelse(TRUE %in% x, TRUE, FALSE))
Note that I have set width = 4 here, not 3. In your question, you said you wanted to check the previous 3 elements. Width includes the ith element. So, if you want to base the result on the previous 3, you have to set width to 4. You also need to include align = "right" to look back from the ith element (the default centers on the ith element, and you can also look ahead with align = "left").
This is a more manual solution:
# Input vector
v <- c(T,T,F,F,F,F,F,T,T,T,T,F,F,F,F,T,F,F,F,F,F,F,T,F)
# Size of the window
k <- 3
# Output vector
outp <- rep(F,length(v))
for(i in seq(length(v))){
# Checking values on variable window
aux <- v[seq(pmax(1,i-k),i)]
# Writing on output vector
outp[i] <- any(aux==T)
}
outp
Here is one option with data.table
library(data.table)
n <- 3
r1 <- Reduce(`|`, shift(v, seq_len(n), fill = FALSE))
identical(r1, r2)
#[1] TRUE
where 'r2' is the OP's output from ifelse
how can I check to see if vector exists inside a matrix. The vector will be of size 2. I have an approach but I would like something vectorized/faster.
dim(m)
[1] 30 2
x = c(1, -2)
for(j in 1:nrow(m)){
if ( isTRUE(as.vector(x[1]) == as.vector(m[j,1])) && as.vector(x[2] == as.vector(m[j,2]) )) {
print(TRUE)
}
}
note, x=c(1, -2) is not the same as -2, 1 in the matrix.
If we are comparing the rows of the matrix ('m') with 'x' having the same length as the number of columns of 'm', we can replicate 'x' (x[col(m)]) to make the lengths same, compare (!=), get the rowSums. If the sum is 0 for a particular row, it means that all the values in the vector matches that row of 'm'. Negate (!) to convert 0 to TRUE and all other values as FALSE.
indx1 <- !rowSums(m!=x[col(m)])
Or if we need a solution using apply, we can use identical
indx2 <- apply(m, 1, identical, y=x)
identical(indx1, indx2)
#[1] TRUE
If this to find only a single TRUE/FALSE, we can wrap any to 'indx1' or 'indx2'.
data
x <- c(1, -2)
set.seed(24)
m <- matrix(sample(c(1,-2,3,4), 30*2, replace=TRUE), ncol=2)
Try
m<-matrix(rnorm(60),30)
x<-m[8,]
m[9,]<-c(x[2],x[1]) # to prove 1,-2 not same -2,1
apply(m,1,function(n,x) all(n==x),x=x)
[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[24] FALSE FALSE FALSE FALSE FALSE FALSE FALSE
if you need just one T/F use any() you
any(apply(m,1,function(n,x) all(n==x),x=x))
[1] TRUE
if run this code with akrun's data
x <- c(1, -2)
set.seed(24)
m <- matrix(sample(c(1,-2,3,4), 30*2, replace=TRUE), ncol=2)
any(apply(m,1,function(n,x) all(n==x),x=x))
[1] TRUE
I have a matrix and a vector with values:
mat<-matrix(c(1,1,6,
3,5,2,
1,6,5,
2,2,7,
8,6,1),nrow=5,ncol=3,byrow=T)
vec<-c(1,6)
This is a small subset of a N by N matrix and 1 by N vector. Is there a way so that I can subset the rows with values in vec?
The most straight forward way of doing this that I know of would be to use the subset function:
subset(mat,vec[,1] == 1 & vec[,2] == 6) #etc etc
The problem with subset is you have to specify in advance the column to look for and the specific combination to do for. The problem I am facing is structured in a way such that I want to find all rows containing the numbers in "vec" in any possible way. So in the above example, I want to get a return matrix of:
1,1,6
1,6,5
8,6,1
Any ideas?
You can do
apply(mat, 1, function(x) all(vec %in% x))
# [1] TRUE FALSE TRUE FALSE TRUE
but this may give you unexpected results if vec contains repeated values:
vec <- c(1, 1)
apply(mat, 1, function(x) all(vec %in% x))
# [1] TRUE FALSE TRUE FALSE TRUE
so you would have to use something more complicated using table to account for repetitions:
vec <- c(1, 1)
is.sub.table <- function(table1, table2) {
all(names(table1) %in% names(table2)) &&
all(table1 <= table2[names(table1)])
}
apply(mat, 1, function(x)is.sub.table(table(vec), table(x)))
# [1] TRUE FALSE FALSE FALSE FALSE
However, if the vector length is equal to the number of columns in your matrix as you seem to indicate but is not the case in your example, you should just do:
vec <- c(1, 6, 1)
apply(mat, 1, function(x) all(sort(vec) == sort(x)))
# [1] TRUE FALSE FALSE FALSE FALSE
This question already has answers here:
Check which elements of a vector is between the elements of another one in R
(4 answers)
Closed 9 years ago.
I have two vectors. I want to check the first element of first vector is between first and second element of second vector , then check the second element of first vector is between the third and forth element of the second vector ,.....How can I do this in R?
For example, If we have tow vectors
a = c(1.5, 2, 3.5)
b = c(1, 2, 3, 5, 3, 8)
the final result in R should be for 1.5 is TRUE and 3.5 is TRUE and for 2 is FALSE.
x <- c(1.5,3.5,3.5,3.5,4)
y <- 1:5
x > y & x < c(y[-1],NA)
#[1] TRUE FALSE TRUE FALSE FALSE
You need to take care of vector lengths and think about, what you want the result to be for the last element of x and of course.
More robust solution:
x <- c(1.5,3.5,3.5,3.5,4)
findInterval(x,y) == seq_along(x)
#[1] TRUE FALSE TRUE FALSE FALSE
x1 <- c(1.5,3.5)
findInterval(x1,y) == seq_along(x1)
#[1] TRUE FALSE
x2 <- c(1.5,3.5,1:5+0.5)
findInterval(x2,y) == seq_along(x2)
#[1] TRUE FALSE FALSE FALSE FALSE FALSE FALSE
Here's one way.
s <- seq_along(a)
b[s] < a[s] & a[s] < b[s+1]
# [1] TRUE FALSE TRUE
Maybe this is not an ideal and fastest solution, but it works.
a <- rnorm(99)
b <- rnorm(100)
m <- cbind(b[-length(b)], b[-1])
a > m[,1] & a < m[,2]
You should check the lengths of both initial vectors.
Here is one-line solution:
sapply(1:length(a), function(i) {a[i] > b[i] & a[i] < b[i+1]})