How can I pass NULL as an argument in R? - r

I have a vector arguments, where some values are NA. I would like to pass these arguments sequentially to a function like this:
myFunction(argument = ifelse(!is.na(arguments[i]),
arguments[i], NULL))
so that it will take the value in arguments[i] whenever it's not NA, and take the default NULL otherwise. But this generates an error.
If it makes any difference, the function in question is match_on(), from the optmatch package. The argument in question is caliper, because I would like to provide a caliper only when one is available (i.e. when the value in the vector of calipers is not NA). And the error message is this:
Error in ans[!test & ok] <- rep(no, length.out = length(ans))[!test & :
replacement has length zero
In addition: Warning message:
In rep(no, length.out = length(ans)) :'x' is NULL so the result will be NULL

You can use ?switch() instead of ifelse -
myFunction(argument = switch(is.na(arguments[i]) + 1, arguments[i], NULL))
Here's the help doc for switch -
switch(EXPR, ...)
Arguments
EXPR an expression evaluating to a number or a character string.
... the list of alternatives. If it is intended that EXPR has a
character-string value these will be named, perhaps except for one
alternative to be used as a ‘default’ value.
Details
switch works in two distinct ways depending whether the first argument
evaluates to a character string or a number.
If the value of EXPR is not a character string it is coerced to
integer. If the integer is between 1 and nargs()-1 then the
corresponding element of ... is evaluated and the result returned:
thus if the first argument is 3 then the fourth argument is evaluated
and returned
Basically, when argument is NA then EXPR evaluates to 2 which returns NULL and when it is not NA then EXPR evaluates to 1 and returns arguments[i].

Related

ifelse() behavior and related error: incompatible types in subassignment type fix (R)

I am trying to run a ifelse() command but getting some weird behavior...
Running:
1 <= 50
I get:
TRUE
Where typeof(1 <= 50) and class(1 <= 50) returns
[1] "logical"
However, once I put this into a ifelse() loop I get some weird behavior...
ifelse(1 <= 50, print("Yay"), print("Boo"))
[1] "Yay"
[1] "Yay"
It prints the true condition action twice....
I am thinking this is the reason I get this error:
Error in ans[ypos] <- rep(yes, length.out = len)[ypos] :
incompatible types (from S4 to logical) in subassignment type fix
When I write more complicated code:
ifelse(length(List[[1]]) >= 50, List[[1]][1], print("Error"))
Which is interesting because if I have the yes statementifelse() assign something to a variable, I still get the error but the resulting object is correct....
> ifelse(length(List[[1]]) >= 50, test <- List[[1]][1], print("Error"))
> test
What am I not understanding....
You are slightly misunderstanding the purpose of ifelse(): this function is made to pick elements from either of two vectors/matrices. The online help describes it as follows:
ifelse returns a value with the same shape as test which is filled
with elements selected from either yes or no depending on whether the
element of test is TRUE or FALSE.
Using arguments with side effects is allowed, but somewhat odd. I believe you should use if ... else for your case.
So what is going on for ifelse(1 <= 50, print("Yay"), print("Boo"))? The first argument is a number (vector of length 1) with just the value TRUE. So ifelse() returns a single element. Since the value is TRUE, it gets the value from the second argument. This prints "Yay", but also returns "Yay" to the ifelse() function. This returned "Yay" is then selected as the output and returned from the ifelse() call. After the call completes, this result is printed to the terminal, giving you the second line of "Yay".

FUN.VALUE argument in vapply

I don't really get the FUN.VALUE argument in vapply.
Here is my example:
a = list(list(1,2), list(1), list(1,2,3))
# give the lengths of each list in a
sapply(a, length)
Now, I try to make it type-safe using vapply instead of sapply
# gives me same result as sapply
vapply(a, length, FUN.VALUE=1)
# same result, but why?
vapply(a, length, FUN.VALUE=1000)
# gives me error
vapply(a, length, FUN.VALUE="integer")
# gives me error
vapply(a, length, FUN.VALUE="vector")
# gives me error
vapply(a, length, FUN.VALUE=c(1,2))
From ?vapply I read that FUN.VALUE can be a scalar, vector or matrix, and is used to match the type of the output. Any hints for why vapply behaves this way?
From the vapply documentation,
FUN.VALUE (generalized) vector; a template for the return value from FUN. See ‘Details’.
Notice that it says "a template for the return value", not "a character string describing the return value". Looking in the Details section provides more guidance:
This function checks that all values of FUN are compatible with the FUN.VALUE, in that they must have the same length and type. [Emphasis added]
The function in your example, length() returns a numeric of length 1, (an integer, if we want to be specific). When you use FUN.VALUE = 1, 1 has the same length and type as the output you expect, so the check passes. When you use FUN.VALUE = "integer", "integer" is a character vector of length 1, so the length check passes but the type check fails.
It continues:
(Types may be promoted to a higher type within the ordering logical < integer < double < complex, but not demoted.)
So, if you were vapplying a function that might return a value that is integer or double, you should make sure to specify something like FUN.VALUE = 1.0
The documentation continues to talk about how arrays/matrices are handled. I won't copy/paste it here.

Error in if/while (condition) { : argument is of length zero

I received the error
Error in if (condition) { : argument is of length zero
or
Error in while (condition) { : argument is of length zero
What causes this error message, and what does it mean?
On further inspection it seems that the value is NULL.
condition
## NULL
In order to deal with this error, how do I test for NULL values?
I expected that this would return TRUE, but I got an empty logical value:
condition == NULL
## logical(0)
See ?NULL
You have to use is.null
‘is.null’ returns ‘TRUE’ if its argument is ‘NULL’ and ‘FALSE’
otherwise.
Try this:
if ( is.null(hic.data[[z]]) ) { print("is null")}
From section 2.1.6 of the R Language Definition
There is a special object called NULL. It is used whenever there is a need to indicate or
specify that an object is absent. It should not be confused with a vector or list of zero
length.
The NULL object has no type and no modifiable properties. There is only one NULL object
in R, to which all instances refer. To test for NULL use is.null. You cannot set attributes
on NULL.
What causes this error message, and what does it mean?
if statements take a single logical value (technically a logical vector of length one) as an input for the condition.
The error is thrown when the input condition is of length zero. You can reproduce it with, for example:
if (logical()) {}
## Error: argument is of length zero
if (NULL) {}
## Error: argument is of length zero
Common mistakes that lead to this error
It is easy to accidentally cause this error when using $ indexing. For example:
l <- list(a = TRUE, b = FALSE, c = NA)
if(l$d) {}
## Error in if (l$d) { : argument is of length zero
Also using if-else when you meant ifelse, or overriding T and F.
Note these related errors and warnings for other bad conditions:
Error in if/while (condition) {: missing Value where TRUE/FALSE needed
Error in if/while (condition) : argument is not interpretable as logical
if (NA) {}
## Error: missing value where TRUE/FALSE needed
if ("not logical") {}
## Error: argument is not interpretable as logical
if (c(TRUE, FALSE)) {}
## Warning message:
## the condition has length > 1 and only the first element will be used
How do I test for such values?
NULL values can be tested for using is.null. See GSee's answer for more detail.
To make your calls to if safe, a good code pattern is:
if(!is.null(condition) &&
length(condition) == 1 &&
!is.na(condition) &&
condition) {
# do something
}
You may also want to look at assert_is_if_condition from assertive.code.
When testing for NULL values, you want to use is.null(hic.data[[z]]).

What is the difference between NULL and character(0) in R?

What is the difference between NULL and character(0) | integer(0) etc?
> identical(NULL, character(0))
[1] FALSE
> is.null(integer(0))
[1] FALSE
> str(character(0))
chr(0)
> str(NULL)
NULL
In general it seems you can pass NULL as parameters into functions, and that an empty vector is generally returned as character(0), integer(0), etc.
Why is this the case? Come to think of it, is there a test for zero-ness, a la is.integer0?
The R Language Definition has this on NULL:
There is a special object called NULL. It is used whenever there is a need to indicate or
specify that an object is absent. It should not be confused with a vector or list of zero
length. The NULL object has no type and no modifiable properties. There is only one NULL
object in R, to which all instances refer. To test for NULL use is.null. You cannot set
attributes on NULL.
So by definition NULL is very different to zero length vectors. A zero length vector very much isn't absent. NULL is really a catch-all for something that is absent or not set, but not missing-ness, which is the job of NA. There is an exception, the zero-length pairlist, as mentioned by #Owen. The Language Definition states:
A zero-length pairlist is NULL, as would be expected in Lisp but in contrast to a zero-length list.
which highlights the exception in this case.
To test for a zero-length vector use something like if(length(foo) == 0L) for example. And combine that with a class check (is.character(foo)) if you want a specific type of zero length vector.
The other guys have the right answers, but I want to add a few curiosities.
First, it's not quite true that NULL "is used whenever there is a need to indicate or specify that an object is absent" as it says in the doc. There are actually 2 other "no data" values in R (not counting NA, which is not a complete value).
There's "missing", which is used for missing arguments:
alist(x=)$x
> identical(NULL, alist(x=)$x)
[1] FALSE
> y = alist(x=)$x
> y
Error: argument "y" is missing, with no default
Then there's "unbound", which you can't (AFAIK) access directly, but using C:
SEXP getUnbound(void) {
return R_UnboundValue;
}
> x = .Call("getUnbound")
> x
Error: object 'x' not found
Here's a partial answer, beginning by simply quoting the R Language Definition Guide:
There is a special object called NULL. It is used whenever there is a
need to indicate or specify that an object is absent. It should not be
confused with a vector or list of zero length. The NULL object has no
type and no modifiable properties. There is only one NULL object in R,
to which all instances refer. To test for NULL use is.null. You cannot
set attributes on NULL.
I take that to mean that zero length vectors can have attributes, whereas NULL cannot:
> x <- character(0)
> y <- NULL
> attr(x,"name") <- "nm"
> attr(y,"name") <- "nm"
Error in attr(y, "name") <- "nm" : attempt to set an attribute on NULL

Error with custom aggregate function for a cast() call in R reshape2

I want to use R to summarize numerical data in a table with non-unique rownames to a result table with unique row-names with values summarized using a custom function. The summarization logic is: use the mean of values if the ratio of the maximum to the minimum value is < 1.5, else use median. Because the table is very large, I am trying to use the melt() and cast() functions in the reshape2 package.
# example table with non-unique row-names
tab <- data.frame(gene=rep(letters[1:3], each=3), s1=runif(9), s2=runif(9))
# melt
tab.melt <- melt(tab, id=1)
# function to summarize with logic: mean if max/min < 1.5, else median
summarize <- function(x){ifelse(max(x)/min(x)<1.5, mean(x), median(x))}
# cast with summarized values
dcast(tab.melt, gene~variable, summarize)
The last line of code above results in an error notice.
Error in vapply(indices, fun, .default) :
values must be type 'logical',
but FUN(X[[1]]) result is type 'double'
In addition: Warning messages:
1: In max(x) : no non-missing arguments to max; returning -Inf
2: In min(x) : no non-missing arguments to min; returning Inf
What am I doing wrong? Note that if the summarize function were to just return min(), or max(), there is no error, though there is the warning message about 'no non-missing arguments.' Thank you for any suggestion.
(The actual table I want to work with is a 200x10000 one.)
Short answer: provide a value for fill as follows
acast(tab.melt, gene~variable, summarize, fill=0)
Long answer:
It appears your function gets wrapped as follows, before being passed to vapply in the vaggregate function (dcast calls cast which calls vaggregate which calls vapply):
fun <- function(i) {
if (length(i) == 0)
return(.default)
.fun(.value[i], ...)
}
To find out what .default should be, this code is executed
if (is.null(.default)) {
.default <- .fun(.value[0])
}
i.e. .value[0] is passed to the function. min(x) or max(x) returns Inf or -Inf on when x is numeric(0). However, max(x)/min(x) returns NaN which has class logical. So when vapply is executed
vapply(indices, fun, .default)
with the default value being is of class logical (used as template by vapply), the function fails when starting to return doubles.
dcast() tries to set the value of missing combination by default value.
you can specify this by fill argument, but if fill=NULL,
then the value returned by fun(0-lenght vector) (i.e., summarize(numeric(0)) here) is used as default.
please see ?dcast
then, here is a workaround:
dcast(tab.melt, gene~variable, summarize, fill=NaN)

Resources