R function-- the default value does not work? - r

I am really new to R. Allow me to ask a beginner's question.
When I type p.adjust, for example, I can see the following. It seems that the argument method is p.adjust.methods by default. I tried to trace the code but when I typed something like:
match.arg(p.adjust.methods)
It says:
Error in match.arg(p.adjust.methods) : 'arg' must be of length 1
Why?
> p.adjust
function (p, method = p.adjust.methods, n = length(p))
{
method <- match.arg(method)
...
}

The match.arg function does not work in interactive mode in its one argument form, since there is nothing to match to. That first argument is expected to be a length 1 character vector, and it is tested against the known methods _inside_the_function_:
> ?p.adjust
> p.adjust.methods
[1] "holm" "hochberg" "hommel" "bonferroni" "BH" "BY" "fdr"
[8] "none"
(The first argument to p.adjust if you are using positional matching needs to be a vector of p-values.)

Related

subvert external function's `deparse(substitute())` without `eval`

I'd like to wrap around the checkmate library's qassert to check multiple variable's specification at a time. Importantly, I'd like assertion errors to still report the variable name that's out of spec.
So I create checkargs to loop through input arguments. But to get the variable passed on to qassert, I use the same code for each loop -- that ambigious code string gets used for for the error message instead of the problematic variable name.
qassert() (via vname()) is getting what to display in the assertion error like deparse(eval.parent(substitute(substitute(x))). Is there any way to box up get(var) such that that R will see e.g. 'x' on deparse instead?
At least one work around is eval(parse()). But something like checkargs(x="n', system('echo malicious',intern=T),'") has me hoping for an alternative.
checkargs <- function(...) {
args<-list(...)
for(var in names(args))
checkmate::qassert(get(var,envir=parent.frame()),args[[var]])
# scary string interpolation alternative
#eval(parse(text=paste0("qassert(",var,",'",args[[var]], "')")),parent.frame())
}
test_checkargs <- function(x, y) {checkargs(x='b',y='n'); print(y)}
# checkargs is working!
test_checkargs(T, 1)
# [1] 1
# but the error message isn't helpful.
test_checkargs(1, 1)
# Error in checkargs(x = "b", y = "n") :
# Assertion on 'get(var, envir = parent.frame())' failed. Must be of class 'logical', not 'double'.
#
# want:
# Assertion on 'x' failed. ...
substitute() with as.name seems to do the trick. This still uses eval but without string interpolation.
eval(substitute(
qassert(x,spec),
list(x=as.name(var),
spec=args[[var]])),
envir=parent.frame())

Error in match.fun(f) : argument "term1" is missing, with no default

Having trouble setting up these integral terms in R. I created "term1" to more easily insert it into the integral code, but I keep getting various error messages after trying different codes. any help or spotting the issue would be appreciated.
##
S<-readline(prompt="Enter underlying instrument price:")
X<-readline(prompt="Enter strike price:")
V<-readline(prompt="Enter absolute volatility in dollars:")
r<-readline(prompt="Enter risk-free rate (%):")
q<-readline(prompt="Enter dividend yield (%):")
T<-readline(prompt="Enter time to maturity, in fraction of years:")
t=0
##
S<-as.numeric(S)
X<-as.numeric(X)
V<-as.numeric(V)
r<-as.numeric(r)/100
q<-as.numeric(q)/100
T<-as.numeric(T)
##Bond Price
B<-exp(r*(T-t))
##Volatility
vol<-function(start,end,rate,yield,B) {
if(r==q){
V*(sqrt((B-1)/(2*(r-q))))
}
else{
V*(sqrt(T-t))
}
}
##d
d<-(S*B-X)/vol()
##N(d)
term1<-(exp(-(r^2)/2)/sqrt(2*pi))
#Call
Nc<-function(term1){
Nc<-((integrate(term1,-Inf,d)))}
#Put
Np<-function(term1){
Np<-(-(integrate(term1,-Inf,d)))}
These are the errors i am getting
> Nc(term1)
Error in get(as.character(FUN), mode = "function", envir = envir) :
object 'term1' of mode 'function' was not found
> Nc()
Error in match.fun(f) : argument "term1" is missing, with no default
Well, the big question is: Have you read the documentation for function integrate ?
The first argument you assign to that function has to be a function.
The second problem is, that function Nc, which you have defined, does not return any output (you can fix that by not assigning the result of integrate to an object and instead just returning it. Same goes for the Np. One more problem with Np is, that it actually returns an error "unexpected argument to unary operator"
Anyway, here is the code with some changes:
## Assign some "random" numbers to the variables, so that I can run the script
S<-100
X<-110
V<-3
r<-10
q<-15
# Is it a good idea to have variable called T? T stands also for TRUE
T <- 10
t=0
##
S<-as.numeric(S)
X<-as.numeric(X)
V<-as.numeric(V)
r<-as.numeric(r)/100
q<-as.numeric(q)/100
T<-as.numeric(T)
##Bond Price
B<-exp(r*(T-t))
##Volatility
vol<-function(start,end,rate,yield,B) {
if(r==q){
V*(sqrt((B-1)/(2*(r-q))))
}
else{
V*(sqrt(T-t))
}
}
##d
d<-(S*B-X)/vol()
# make term1 a function of r, so that there is actually something to integrate...
term1<-function(r) {(exp(-(r^2)/2)/sqrt(2*pi))}
# Do not assign the result of integration to an object, otherwise there will be no output from the function
Nc<-function(term1){
((integrate(term1,-Inf,d)))}
# In order to use the minus sign, you have to extract the value from the result of function "integrate"
Np<-function(term1){
(-(integrate(term1,-Inf,d)$value))}

Why subset doesn't mind missing subset argument for dataframes?

Normally I wonder where mysterious errors come from but now my question is where a mysterious lack of error comes from.
Let
numbers <- c(1, 2, 3)
frame <- as.data.frame(numbers)
If I type
subset(numbers, )
(so I want to take some subset but forget to specify the subset-argument of the subset function) then R reminds me (as it should):
Error in subset.default(numbers, ) :
argument "subset" is missing, with no default
However when I type
subset(frame,)
(so the same thing with a data.frame instead of a vector), it doesn't give an error but instead just returns the (full) dataframe.
What is going on here? Why don't I get my well deserved error message?
tl;dr: The subset function calls different functions (has different methods) depending on the type of object it is fed. In the example above, subset(numbers, ) uses subset.default while subset(frame, ) uses subset.data.frame.
R has a couple of object-oriented systems built-in. The simplest and most common is called S3. This OO programming style implements what Wickham calls a "generic-function OO." Under this style of OO, an object called a generic function looks at the class of an object and then applies the proper method to the object. If no direct method exists, then there is always a default method available.
To get a better idea of how S3 works and the other OO systems work, you might check out the relevant portion of the Advanced R site. The procedure of finding the proper method for an object is referred to as method dispatch. You can read more about this in the help file ?UseMethod.
As noted in the Details section of ?subset, the subset function "is a generic function." This means that subset examines the class of the object in the first argument and then uses method dispatch to apply the appropriate method to the object.
The methods of a generic function are encoded as
< generic function name >.< class name >
and can be found using methods(<generic function name>). For subset, we get
methods(subset)
[1] subset.data.frame subset.default subset.matrix
see '?methods' for accessing help and source code
which indicates that if the object has a data.frame class, then subset calls the subset.data.frame the method (function). It is defined as below:
subset.data.frame
function (x, subset, select, drop = FALSE, ...)
{
r <- if (missing(subset))
rep_len(TRUE, nrow(x))
else {
e <- substitute(subset)
r <- eval(e, x, parent.frame())
if (!is.logical(r))
stop("'subset' must be logical")
r & !is.na(r)
}
vars <- if (missing(select))
TRUE
else {
nl <- as.list(seq_along(x))
names(nl) <- names(x)
eval(substitute(select), nl, parent.frame())
}
x[r, vars, drop = drop]
}
Note that if the subset argument is missing, the first lines
r <- if (missing(subset))
rep_len(TRUE, nrow(x))
produce a vector of TRUES of the same length as the data.frame, and the last line
x[r, vars, drop = drop]
feeds this vector into the row argument which means that if you did not include a subset argument, then the subset function will return all of the rows of the data.frame.
As we can see from the output of the methods call, subset does not have methods for atomic vectors. This means, as your error
Error in subset.default(numbers, )
that when you apply subset to a vector, R calls the subset.default method which is defined as
subset.default
function (x, subset, ...)
{
if (!is.logical(subset))
stop("'subset' must be logical")
x[subset & !is.na(subset)]
}
The subset.default function throws an error with stop when the subset argument is missing.

R: Testing function in interactive session

I am not sure if it is possible, but I would like to be able to grab the default argument values of a function and test them and the code within my functions without having to remove the commas (this is especially useful in the case when there are many arguments).
In effect, I want to be able to have commas when sending arguments into the function but not have those commas if I copy and paste the arguments and run them by themselves.
For example:
foo=function(
x=1,
y=2,
z=3
) {
bar(x,y,z)
}
Now to test pieces of the function outside of the code block, copy and paste
x=1,
y=2,
z=3
bar(x,y,z)
But this gives an error because there is a comma after x=1
Perhaps I am not asking the right question. If this is strange, what is the preferred method for debugging functions?
Please note, just posted nearly identical question in Julia.
If you want to programmatically get at the arguments of a function and their default values, you can use formals:
fxn = function(a, b, d = 2) {}
formals(fxn)
# $a
#
#
# $b
#
#
# $d
# [1] 2
I suppose if you wanted to store the default value of every argument to your function into a variable of that name (which is what you're asking about in the OP), then you could do this with a for loop:
info <- formals(fxn)
for (varname in names(info)) {
assign(varname, info[[varname]])
}
a
# Error: argument "a" is missing, with no default
b
# Error: argument "b" is missing, with no default
d
# [1] 2
So for arguments without default values, you'll need to provide a value after running this code (as you would expect). For arguments with defaults, they'll now be set.

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

Resources