Vector creation and modification based on other vectors - r

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

Related

Making a list in R which has only 1 value in each index

so im trying to make a list where each index ( listname[[i]]) has only 1 value.
when I assign each value manually it works but when i try assigning in a for loop it puts all of the list in index 1 (and not assigning the values i want, it assigns NULL) clarify: I DONT want a nested list. i want a normal list with length(force1[[2]]) and in each index to assign 0 or 1 according to a condition
force1 is a list of 2. index 1 has a string list and index 2 has a numeric list
code for testing:
temp_bool <- FALSE
birth_binary <- list()
birth_binary[[length(force1[[2]])]] <- 1
for (i in seq_len(length((force1[[2]])))){
temp_bool <- as.integer(force1[[2]][i]) < as.integer(45)
if (temp_bool == TRUE){
append(birth_binary,list('1'))
}
else{
append(birth_binary,list('0'))
}
}
temp_bool <- TRUE
if (temp_bool == TRUE){
birth_binary[[5]] <- 90
[force 1][1]
I have tried using append() with both a value to add and a vector to add.
also tried using the assignment <- to the i'th index.
Instead of creating a loop, extract the second element of 'force1' list (force1[[2]]), check whether it is less than 45 (< 45), convert the logical to binary (+ or as.integer) and convert the binary vector to list with as.list and assign to a new object 'birth_binary'
birth_binary <- as.list(+(force1[[2]] < 45))

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

2 conditions for creating a boolean vector

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.

Resources