2 conditions for creating a boolean vector - r

I have 2 vectors and single a number.
a <- rnorm(40,10,4)
d <- rep(0,length(a)
filling_limit <- 8
Now, I want a 40*1 boolean vector (has.room) giving me info if the 2 conditions are satisfied:
has.room <- a > 0 && d < filling_limit
instead of returning a vector with 40 times TRUE I get just a single TRUE.
What's the reason for this? If you are wondering about the zero vector: This thing is part of a loop and d will change within time. Thanks!

Try:
has.room <- a > 0 & d < filling_limit

has.room <- a > 0 & d < filling_limit
From the help page for logical operators:
& and && indicate logical AND and | and || indicate logical OR. The shorter form performs elementwise comparisons in much the same way as arithmetic operators. The longer form evaluates left to right examining only the first element of each vector. Evaluation proceeds only until the result is determined.

Related

How to check whether a vector is subset of another one in R?

Say, I have two vectors:
A <- c(1,0,0,1,0,0,0)
and
B <- c(1,0,0,1,0,1,1)
By my definition, A is subset of B, (both vectors contain binary values only) if and only if
A and B have the same length and thus have the same number of elements;
A should have either 0 or 1 at all places wherever B has 1
A can have only 0s at all places where B has 0s.
Now I wish to write a code that would verify something within the lines of
if(A subset of B){}
Thank you!
You can test if length is == and if any values of A have a 1 on positions where B has a 1 and combine the conditions with &&.
length(A) == length(B) && any(A[B==1]==1)
#[1] TRUE
Fulfilling the condition in the original question: A and B have the same length and thus have the same number of elements; yet, A is a subset of B, since A has elements 1 in the same place as B.
To fulfill:
A and B have the same length and thus have the same number of elements;
A should have at least one 1 at places wherever B has 1
A can have only 0s at all places where B has 0s.
length(A) == length(B) && any(A[B==1]==1) && all(A[B==0]==0)
To fulfill:
A and B have the same length and thus have the same number of elements;
A can have only 0s at all places where B has 0s.
length(A) == length(B) && all(A[B==0]==0)
First condition checks for same length, second checks that A doesn't have 1 on position on which B has 0.
if(length(A) == length(B) && all(B - A >= 0)) TRUE else FALSE

get length of character matching between two string in R

I have a dataframe where i need to compare two columns and find the number of matching characters between two elements.
For eg: x and y are two elements to be compared which look like below:
x<- "1/2"
y<-"2/3"
I did unlisted and splitted them by '/' as below:
unlist(strsplit(x,"/"))->a
unlist(strsplit(y,"/"))->b
Then i used pmatch:
pmatch(a,b,nomatch =0)
[1] 0 1
Used sum() to know how many characters are matching:
sum(pmatch(a,b,nomatch =0))
[1] 1
However, when the comparison is done the other way:
pmatch(b,a,nomatch = 0)
[1] 2 0
Since there is only one match between the two string, why is it showing 2. It could be index. But i would need to get how many characters are same between the strings irrespective of the comparison a vs b or b vs a.
Could someone help how to get this.
Per ?pmatch, pmatch seeks matches for the elements of its first argument among those of its second.
For example, "2" in the first list matches the second element in the second list.
> pmatch(c("2", "1"),c("3","2"),nomatch =0)
# [1] 2 0
One way to know the number of elements got matched is to sum non-zero elements:
sum(pmatch(c("2", "1"),c("3","2"),nomatch =0) != 0)
# [1] 1
Both
sum(pmatch(b, a, nomatch = 0) != 0) # 1
sum(pmatch(a, b, nomatch = 0) != 0) # 1
return the same value.
Another option could be
sum(b %in% a)
[1] 1
sum(a %in% b)
[1] 1

Accessing the object referenced in a logical condition

I am writing an xor function for a class, so although any recommendations on currently existing xor functions would be nice, I have to write my own. I have searched online, but have not been able to find any solution so far. I also realize my coding style may be sub-optimal. All criticisms will be welcomed.
I writing a function that will return an element-wise TRUE iff one condition is true. Conditions are given as strings, else they will throw an error due to unexpected symbols (e.g. >). I would like to output a list of the pairwise elements of a and b in which my xor function is true.
The problem is that, while I can create a logical vector of xor T/F based on the conditions, I cannot access the objects directly to subset them. It is the conditions that are function arguments, not the objects themselves.
'%xor%' <- function(condition_a, condition_b) {
# Perform an element-wise "exclusive or" on the conditions being true.
if (length(eval(parse(text= condition_a))) != length(eval(parse(text= condition_b))))
stop("Objects are not of equal length.") # Objects must be equal length to proceed
logical_a <- eval(parse(text= condition_a)) # Evaluate and store each logical condition
logical_b <- eval(parse(text= condition_b))
xor_vector <- logical_a + logical_b == 1 # Only one condition may be true.
xor_indices <- which(xor_vector == TRUE) # Store a vector which gives the indices of the elements which satisfy the xor condition.
# Somehow access the objects in the condition strings
list(a = a[xor_indices], b = b[xor_indices]) # Desired output
}
# Example:
a <- 1:10
b <- 4:13
"a < 5" %xor% "b > 4"
Desired output:
$a
[1] 1 5 6 7 8 9 10
$b
[1] 4 8 9 10 11 12 13
I have thought about doing a combination of ls() and grep() to find existing object names in the conditions, but this would run into problems if the objects in the conditions were not initialized. For example, if someone tried to run "c(1:10) < 5" %xor% "c(4:13) > 4".

Get index of vector between 1nd and 2nd appearance of number 1

Suppose we have a vector:
v <- c(0,0,0,1,0,0,0,1,1,1,0,0)
Expected output:
v_index <- c(5,6,7)
v always starts and ends with 0. There is only one possibility of having cluster of zeros between two 1s.
Seems simple enough, can't get my head around...
I think this will do
which(cumsum(v == 1L) == 1L)[-1L]
## [1] 5 6 7
The idea here is to separate all the instances of "one"s to groups and select the first group while removing the occurrence of the "one" at the beginning (because you only want the zeroes).
v <- c(0,0,0,1,0,0,0,1,1,1,0,0)
v_index<-seq(which(v!=0)[1]+1,which(v!=0)[2]-1,1)
> v_index
[1] 5 6 7
Explanation:I ask which indices are not equal to 0:
which(v!=0)
then I take the first and second index from that vector and create a sequence out of it.
This is probably one of the simplest answers out there. Find which items are equal to one, then produce a sequence using the first two indexes, incrementing the first and decrementing the other.
block <- which(v == 1)
start <- block[1] + 1
end <- block[2] - 1
v_index <- start:end
v_index
[1] 5 6 7

Vector creation and modification based on other vectors

I would like to make the code more efficient.
The example creates a vector (called 'new_vector'). The values of this 'new_vector' are changed based on if/else-conditions that refer to the values of three other vectors of the same length.
If the conditions are fulfilled, the corresponding elements of the 'new_vector' are updated using values from one of the other vectors (in the example elements of M_date are written into new_vector).
Here is the example code:
new_vector<-c(9,9,9)
S_date<-c(1,1,as.Date('2010/08/01'))
V_date<-c(1,as.Date('2010/09/01'),1)
M_date<-c(2,as.Date('2010/07/01'),1)
for (i in 1:3) {
if ( (S_date[i]==1) & (V_date[i]==1 | M_date[i] < V_date[i]) ) {
new_vector[i]<-M_date[i]
}
}
The result of the example is:
> new_vector
[1] 2 14791 9
The example is simplified and in reality the vectors are larger and there are additional if/else-conditions.
How can I avoid the loop and use implicit methods for vector operations instead?
If you write the expression without the [i] bits you get a vector True/False result:
> S_date==1 & (V_date==1 | M_date < V_date)
[1] TRUE TRUE FALSE
assign that to a vector, and replace in new_vector by that result:
> result = S_date==1 & (V_date==1 | M_date < V_date)
> new_vector[result]=M_date[result]
> new_vector
[1] 2 14791 9
Its a fairly general pattern. Compute a boolean vector, then replace those matching values with the corresponding values from another vector.
It works because the FALSE value in the third element of result means that new_vector[3] doesn't get touched.
Use ifelse instead of if:
new_vector<-c(9,9,9)
S_date<-c(1,1,as.Date('2010/08/01'))
V_date<-c(1,as.Date('2010/09/01'),1)
M_date<-c(2,as.Date('2010/07/01'),1)
vec <- ifelse((S_date==1) & (V_date==1 | M_date < V_date), M_date, new_vector)
vec
#[1] 2 14791 9
HTH

Resources