How does the all function work in R using two expressions? - r

I have an issue with the all function in R.
let a and b two vectors:
a <- c(Inf,0)
b <- c(1,0)
When I try to evaluate the expression all(a==b) the function returns FALSE, is OK, if it is evaluated the expression all(a==Inf) the function returns FALSE, so far all is working OK, but if I try to evaluate the expression all((a==b) | (a==Inf)) the function returns TRUE.
Could someone explain me why?

The OR is done column wise:
a <- c(Inf,0)
b <- c(1,0)
(a==b)
#> [1] FALSE TRUE
(a==Inf)
#> [1] TRUE FALSE
(a==Inf)|(a==b)
#> [1] TRUE TRUE
In each column there's a TRUE so each column is TRUE

When you type help("|"), you will see that | is element-wise OR.
In this case, given
> (a == b)
[1] FALSE TRUE
> (a == Inf)
[1] TRUE FALSE
the expression (a == b) | (a == Inf) is equivalent to
c(FALSE, TRUE) | c(TRUE, FALSE)
and the resultant logic array is c(TRUE, TRUE), which gives you TRUE when you apply all over it.

Related

Dealing with missing values when writing logical expressions

If you are familiar with SAS you know that missing values are considered as -inf, therefore, for an expression like this:
If a < 2 then c=1 ;
else c= 5;
Where "a" is missing; value of 1 will be assigned to c, because the logical expression "a < 2" will be "True". Please notice that my question is about the outcome of the logical expression. I do not care about "c".
I would like to get the same thing in R but the result of the logical expression will be "NA" :
a <-NA
a < 2
[1] NA
How can I change the output of this logical expression to "True" ?
I know I can do this:
output < ifelse( is.na(a), False, a <2)
But I am looking for something simple. Any ideas?
If you use this frequently enough, then you could define an infix operator to wrap around your ifelse:
`%<%` <- function(a, b) { ifelse(is.na(a), TRUE, a < b) }
So if a is
a <- c(NA, 1, 3, 5, NA)
Then you only need do:
a %<% 2
#> [1] TRUE TRUE FALSE FALSE TRUE
You can use the fact that NA is a logical object.
(a < 2) | is.na(a)
Just for fun, and I am absolutely not recommending this approach:
Ops.sas <- function (e1, e2) {
comparison <- switch(.Generic, `<` = , `>` = , `==` = , `!=` = ,
`<=` = , `>=` = TRUE, FALSE)
if (comparison) {
e1[is.na(e1)] <- -Inf
e2[is.na(e2)] <- -Inf
}
NextMethod(.Generic)
}
And now:
> foo <- structure(c(NA, 2,3,2, NA), class = "sas")
> bar <- structure(c(2,3,2, NA, NA), class = "sas")
> foo < bar
[1] TRUE TRUE FALSE FALSE FALSE
> foo <= bar
[1] TRUE TRUE FALSE FALSE TRUE
> foo == bar
[1] FALSE FALSE FALSE FALSE TRUE
> foo != bar
[1] TRUE TRUE TRUE TRUE FALSE
> foo > bar
[1] FALSE FALSE TRUE TRUE FALSE
> foo >= bar
[1] FALSE FALSE TRUE TRUE TRUE
if(is.na(a) | a < 2){
c=1
} else {
c=2
}
I think that the simplest way is just to add a new condition in your test. In R the | symbol stands for OR.
I think you will have to modify the values in a for example like this
a <- c(NA, 1, 3, 4, NA)
a
#> [1] NA 1 3 4 NA
a < 2
#> [1] NA TRUE FALSE FALSE NA
a[is.na(a)] <- -Inf
a < 2
#> [1] TRUE TRUE FALSE FALSE TRUE
Created on 2022-02-04 by the reprex package (v2.0.1)

Is there a better way to check if all elements in a list are named?

I want to check if all elements in a list are named. I've came up with this solution, but I wanted to know if there is a more elegant way to check this.
x <- list(a = 1, b = 2)
y <- list(1, b = 2)
z <- list (1, 2)
any(stringr::str_length(methods::allNames(x)) == 0L) # FALSE, all elements are
# named.
any(stringr::str_length(methods::allNames(y)) == 0L) # TRUE, at least one
# element is not named.
# Throw an error here.
any(stringr::str_length(methods::allNames(z)) == 0L) # TRUE, at least one
# element is not named.
# Throw an error here.
I am not sure if the following base R code works for your general cases, but it seems work for the ones in your post.
Define a function f to check the names
f <- function(lst) length(lst) == sum(names(lst) != "",na.rm = TRUE)
and you will see
> f(x)
[1] TRUE
> f(y)
[1] FALSE
> f(z)
[1] FALSE
We can create a function to check if the the names attribute is NULL or (|) there is blank ("") name, negate (!)
f1 <- function(lst1) is.list(lst1) && !(is.null(names(lst1))| '' %in% names(lst1))
-checking
f1(x)
#[1] TRUE
f1(y)
#[1] FALSE
f1(z)
#[1] FALSE
Or with allNames
f2 <- function(lst1) is.list(lst1) && !("" %in% allNames(lst1))
-checking
f2(x)
#[1] TRUE
f2(y)
#[1] FALSE
f2(z)
#[1] FALSE

How can I change values froma vector with a previous condition?

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

What is the behavior of the ampersand operator in R's sum(...) function

Below, a line from a script I'm translating from R into Python. I'm more experienced at Python than I am at R, and I'm running into a little trouble here:
val = sum(l & f==v)
Let l be a vector of true/false values. Let f be a vector of trivial values, and v some possible value of f to test against. I expect l and f to be of the same length. The f==v part will also yield a boolean array. Now I am left with the question what the &/ampersand (Logical AND, according to the R documentation) will do in this context. Will the sum() function return the sum of a boolean array that indicates where both the l and f==v boolean arrays are true? Or wil it sum all true values for both arrays and add them up?
Thank you in advance!
Let define several vectors :
l <- c(TRUE, FALSE, TRUE, FALSE, TRUE)
v <- 1:5
f <- rep(c(1, 4), c(3, 2))
now let see what we have when we decompose your line sum(l & f==v):
In this line, == has precedence over &:
fev <- f==v
fev
[1] TRUE FALSE FALSE TRUE FALSE
Then we do l & fev:
lafev <- l & fev
[1] TRUE FALSE FALSE FALSE FALSE
lastly, we sum:
sum(lafev)
[1] 1
The sum tells us how many simultaneous TRUE there are in l and f==v by converting the logical values to numeric: TRUE becomes 1 and FALSE becomes 0. So, in this example, 1.
Here is a sample python version:
l = [True, True, False]
f = [True, False, True]
v = [True, True, True]
f_eq_v = [f[i] == v[i] for i in range(len(f))] # f == v in R
val = sum([l[i] & f_eq_v[i] for i in range(len(l))]) # val = sum(l & f==v) in R

How to group same values in column in R

How to get index number in a Boolean vector? For instance, my vector looks like this:
vector = (TRUE TRUE FALSE TRUE FALSE TRUE FALSE FALSE FALSE TRUE TRUE FALSE)
How to get index number for all TRUEs? vector["TRUE"] doesn't work.
Try using the which function (type ?which):
> my.vec <- c(TRUE, FALSE, FALSE, TRUE)
> which(my.vec)
> [1] 1 4

Resources