I'm trying to create a function that subtracts 2 from each element of a vector, and whenever I pass a vector as a parameter to the function, it's outputting an error:
Error in sub(x) : argument "x" is missing, with no default.
so I have a vector that's called x1,
and my function call looks like that: sub(x1)
any help will be appreciated.
sub <- function(x)
{
for(i in 1:length(x))
{
x[i] = x[i]-2
}
return(x)
}
In R a lot of function and operators (just a special form of functions) are vectorised. Vectorisation means that a function/operator works automatically on all elements of an vector (or vector like object).
Therefore, our problem can be solved with much less code. In addition using vectorised functions (especially basic stuff like +, -, ...) is much much much faster than looping over elements.
# define function that does subtraction
sub <- function(x){
x - 2
}
# define vector with numbers ranging from 1 to 20
my_vector <- 1:20
# call function with my_vector as argument
sub(my_vector)
In regard to your error:
Error in sub(x) : argument "x" is missing, with no default.
It is telling you that you called a function sub() without providing an appropriate value for its argument x. Since you did not provide it, and there is no default, and it cannot find it otherwise R does not know what to do and signals (throws) an error.
I can reproduce your error like so:
# call sub without argument
sub()
## Error in sub() : argument "x" is missing, with no default
I can prevent it by providing a value for argument x, like so:
# call sub with value for x
sub(1)
sub(x = 1)
... Or I can provide defaults like this:
# define function with default values
sub <- function(x = NULL){
x - 2
}
# call new 'robust' sub() function without arguments
sub()
## numeric(0)
... Or I can provide defaults like this:
# define function with default values
sub <- function(x){
if ( missing(x) ){
x <- NULL
}
x - 2
}
# call new 'robust' sub() function without arguments
sub()
## numeric(0)
Resources:
https://www.youtube.com/watch?v=M4fMccWy5lU
https://www.stat.berkeley.edu/~statcur/Workshop2/Presentations/functions.pdf
http://adv-r.had.co.nz/Functions.html
?`function`
https://cran.r-project.org/doc/manuals/r-patched/R-intro.html#Writing-your-own-functions
I suppose you forgot to run your function definition:
sub2 <- function(x)
{
for(i in 1:length(x))
{
x[i] = x[i]-2
}
return(x)
}
sub2(1:4) ## works fine
sub(1:4) ## Error calling the function sub(pattern, replacement, x, ...)
Error in sub(1:4) : argument "x" is missing, with no default
or
> x1 <- 1:4
> sub(x1) ## Error
Error in sub(x1) : argument "x" is missing, with no default
If you would have choosen another name for your function (not a name of an existing R-function) the message is clear (to run in a new R-session):
# sub2 <- function(x)
# {
# for(i in 1:length(x))
# {
# x[i] = x[i]-2
# }
# return(x)
# }
sub2(1:4)
# > sub2(1:4)
# Error in sub2(1:4) : could not find function "sub2"
I commented out the function definition to simulate not running of the function definition
Related
I've just read about delayedAssign(), but the way you have to do it is by passing the name of the delayed variable as the first parameter. Is there a way to do it via direct assignment?
e.g.:
x <- delayed_variable("Hello World")
rather than
delayedAssign("x","Hello World")
I want to create a variable that will throw an error if accessed (use-case is obviously more complex), so for example:
f <- function(x){
y <- delayed_variable(stop("don't use y"))
x
}
f(10)
> 10
f <- function(x){
y <- delayed_variable(stop("don't use y"))
y
}
f(10)
> Error in f(10) : don't use y
No, you can't do it that way. Your example would be fine with the current setup, though:
f <- function(x){
delayedAssign("y", stop("don't use y"))
y
}
f(10)
which gives exactly the error you want. The reason for this limitation is that delayed_variable(stop("don't use y")) would create a value which would trigger the error when evaluated, and assigning it to y would evaluate it.
Another version of the same thing would be
f <- function(x, y = stop("don't use y")) {
...
}
Internally it's very similar to the delayedAssign version.
I reached a solution using makeActiveBinding() which works provided it is being called from within a function (so it doesn't work if called directly and will throw an error if it is). The main purpose of my use-case is a smaller part of this, but I generalised the code a bit for others to use.
Importantly for my use-case, this function can allow other functions to use delayed assignment within functions and can also pass R CMD Check with no Notes.
Here is the function and it gives the desired outputs from my question.
delayed_variable <- function(call){
#Get the current call
prev.call <- sys.call()
attribs <- attributes(prev.call)
# If srcref isn't there, then we're not coming from a function
if(is.null(attribs) || !"srcref" %in% names(attribs)){
stop("delayed_variable() can only be used as an assignment within a function.")
}
# Extract the call including the assignment operator
this_call <- parse(text=as.character(attribs$srcref))[[1]]
# Check if this is an assignment `<-` or `=`
if(!(identical(this_call[[1]],quote(`<-`)) ||
identical(this_call[[1]],quote(`=`)))){
stop("delayed_variable() can only be used as an assignment within a function.")
}
# Get the variable being assigned to as a symbol and a string
var_sym <- this_call[[2]]
var_str <- deparse(var_sym)
#Get the parent frame that we will be assigining into
p_frame <- parent.frame()
var_env <- new.env(parent = p_frame)
#Create a random string to be an identifier
var_rand <- paste0(sample(c(letters,LETTERS),50,replace=TRUE),collapse="")
#Put the variables into the environment
var_env[["p_frame"]] <- p_frame
var_env[["var_str"]] <- var_str
var_env[["var_rand"]] <- var_rand
# Create the function that will be bound to the variable.
# Since this is an Active Binding (AB), we have three situations
# i) It is run without input, and thus the AB is
# being called on it's own (missing(input)),
# and thus it should evaluate and return the output of `call`
# ii) It is being run as the lhs of an assignment
# as part of the initial assignment phase, in which case
# we do nothing (i.e. input is the output of this function)
# iii) It is being run as the lhs of a regular assignment,
# in which case, we want to overwrite the AB
fun <- function(input){
if(missing(input)){
# No assignment: variable is being called on its own
# So, we activate the delayed assignment call:
res <- eval(call,p_frame)
rm(list=var_str,envir=p_frame)
assign(var_str,res,p_frame)
res
} else if(!inherits(input,"assign_delay") &&
input != var_rand){
# Attempting to assign to the variable
# and it is not the initial definition
# So we overwrite the active binding
res <- eval(substitute(input),p_frame)
rm(list=var_str,envir=p_frame)
assign(var_str,res,p_frame)
invisible(res)
}
# Else: We are assigning and the assignee is the output
# of this function, in which case, we do nothing!
}
#Fix the call in the above eval to be the exact call
# rather than a variable (useful for debugging)
# This is in the line res <- eval(call,p_frame)
body(fun)[[c(2,3,2,3,2)]] <- substitute(call)
#Put the function inside the environment with all
# all of the variables above
environment(fun) <- var_env
# Check if the variable already exists in the calling
# environment and if so, remove it
if(exists(var_str,envir=p_frame)){
rm(list=var_str,envir=p_frame)
}
# Create the AB
makeActiveBinding(var_sym,fun,p_frame)
# Return a specific object to check for
structure(var_rand,call="assign_delay")
}
I'm trying to program over a function inside a package, but I'm stuck with the function internally using match.call() to parse one of its arguments.
A super-simplified example of the function with the usual utilization could look like this:
f1 = function(x, y=0, z=0, a=0, b=0){ #lots of arguments not needed for the example
mc = match.call()
return(mc$x)
#Returning for testing purpose.
#Normally, the function later uses calls as character:
r1 = as.character(mc$x[1])
r2 = as.character(mc$x[2])
#...
}
x1 = f1(x = foo(bar))
x1
# foo(bar)
class(x1)
# [1] "call"
In my case, I need to get the value of x from a variable (value in the following code). Expected utilisation of f1 is as following :
value = "foo(bar)" #this line could also be anything else
f1(x=some_magic_function(value))
# Expected result = foo(bar)
# Unwanted result = some_magic_function(value)
Unfortunately, match.call() always return the very input value. I'm quite out of my league here so I only tried few functions.
Is there any way I could trick match.call() so it could accept external variable ?
Failed attempts so far:
#I tried to create the exact same call using rlang::sym()
#This may not be the best way...
value = call("foo", rlang::sym("bar"))
value
# foo(bar)
class(value)
# [1] "call"
x1==value
# [1] TRUE
f1(x=value)
# value
f1(x=eval(value))
# eval(value)
f1(x=substitute(value))
# substitute(value)
There's nothing you can include as a parameter to f1 to make this work. Instead, you would dynamically need to build your call to f1. With base R you might do this with do.call.
do.call("f1", list(parse(text=value)[[1]]))
or with rlang
eval_tidy(quo(f1(!!parse_expr(value))))
I'm a bit surprised by R's behaviour in a very specific case. Let's say I define a function square that returns the square of its argument, like this:
square <- function(x) { return(x^2) }
I want to call this function within another function, and I also want to display its name when I do that. I can do that using deparse(substitute()). However, consider the following examples:
ds1 <- function(x) {
print(deparse(substitute(x)))
}
ds1(square)
# [1] "square"
This is the expected output, so all is fine. However, if I pass the function wrapped in a list and process it using a for loop, the following happens:
ds2 <- function(x) {
for (y in x) {
print(deparse(substitute(y)))
}
}
ds2(c(square))
# [1] "function (x) " "{" " return(x^2)" "}"
Can anybody explain to me why this occurs and how I could prevent it from happening?
As soon as you use x inside your function, it is evaluated, so it "stops being an (unevaluated) expression" and "starts being its resulting values (evaluated expression)". To prevent this, you must capture x by substitute before you use it for the first time.
The result of substitute is an object which you can query as if it was a list. So you can use
x <- substitute(x)
and then x[[1]] (the function name) and x[[2]] and following (the arguments of the function)
So this works:
ds2 <- function(x) {
x <- substitute(x)
# you can do `x[[1]]` but you can't use the expression object x in a
# for loop. So you have to turn it into a list first
for (y in as.list(x)[-1]) {
print(deparse(y))
}
}
ds2(c(square,sum))
## [1] "square"
## [1] "sum"
i know might of u think this question and duplicated,but i do really have something kinda freaks me out, i was learning R and i had assignment to do something i do manage to solve it but i wonder why this error appear while the 2 code is very similar, is that something i don't understand in R
the first who has give me an error was :
makeCacheMatrix <- function(x = matrix()) {
#i for invirse
i <- NULL
set <- function(y){
x <<- y
i <<- NULL
}
get <- function(){x}
setinv <- function(solved){i <<- solved}
getinv <- function(){i}
#a list that has the 4 internal methods
list(set = set, get = get,
setinv = setinv,
getinv = getinv)
}
## Write a short comment describing this function
# this method check first if the data already cached,
# if they are it return it with message says "Getting cached data"
# if not it calculated, cache it and then return it
cacheSolve <- function(x, ...) {
## Return a matrix that is the inverse of 'x'
i <- x$getinv()
if(!is.null(i)){
message("Getting cached data")
return(i)
}
#calculate the inverse
x <- x$get()
i <- solve(x)
#print(i)
#print(class(i))
x$setinv(i)
i
}
this is how i call my function and the only result i get is
ps uncomment the print and clas funs will give the correct answers:
> source('~/R/cachematrix[not workng].R')
> x <- makeCacheMatrix(matrix(rnorm(16), 4,4))
> cacheSolve(x)
Error in x$setinv : $ operator is invalid for atomic vectors
after some time i said to myself why using too match variable and i use the methods inside each other for more sample code (one line is better)
but somehow the code works, for me it's the same code the only thing i have did the to pass the methods to each other instead of passing it into variable then pass the variable to method (it's the same really)
the code became like this now :
## Write a short comment describing this function
# this method retuen a matrix that has a list
# this list has 4 method as getters and sitters
makeCacheMatrix <- function(x = matrix()) {
#i for invirse
i <- NULL
set <- function(y){
x <<- y
i <<- NULL
}
get <- function(){x}
setinv <- function(solved){i <<- solved}
getinv <- function(){i}
#a list that has the 4 internal methods
list(set = set, get = get,
setinv = setinv,
getinv = getinv)
}
## Write a short comment describing this function
# this method check first if the data alredy cached,
# if they are it return it with messege sys "Getting cached data"
# if not it calculated, cache it and then return it
cacheSolve <- function(x, ...) {
## Return a matrix that is the inverse of 'x'
i <- x$getinv()
if(!is.null(i)){
message("Getting cached data")
return(i)
}
#calculate the invirse
i <- solve(x$get())
#cache the invirse for later
x$setinv(i)
i
}
and this's how i call my function:
> source('~/R/ProgrammingAssignment2/cachematrix.R')
> x <- makeCacheMatrix(matrix(rnorm(16), 4,4))
> cacheSolve(x)
[,1] [,2] [,3] [,4]
[1,] 0.09904578 -0.4586855 -0.2487849 -0.3421875
[2,] -1.84896897 0.8476203 0.7990204 0.5919526
[3,] 0.70645287 -0.1508695 -0.7141914 -0.2729974
[4,] 1.37441746 -0.9853108 -0.5607929 0.6553295
works good, i just wanna know what happen there, and why the first code give me an error and the second one didn't while both suppose to have the same logic, Thanks in advance mates
ps. i'm using : R version 3.3.2 on linux mint 18.1 with the latest version of rstudio
I have some code below. Now I would want to manipulate my initial top level x variable when an error occurs in the tryCatch statement. I read the documentation, but I can't really figure out how it's supposed to be used.
Some questions I can't get my head around.
What is the workflow for these type of issues? (Should I define a new enviroment for the x variable and reference that enrivoment when I want x in my local function?
How to use the get() function? I suppose for my task I need the get() function, coupled with the superassignment operator <<- or assign.
Something like. x <<- x[! x %in% get(x, envir = "no idea")] is what I need.
You can try out the code by specifying any vector with valid yahoo tickers, such as LoadData(c('YHOO', 'GOOG')). The tryCatch statement is meant to catch any tickers that do not exist, and in that case I want to modify my initial ticker list (the x variable) to not include this ticker name. Thus the need for an get() operation.
LoadData <- function(x) {
if(is.atomic(x) != TRUE & is.data.frame(x) != TRUE) stop('x must be either a data.frame or an atomic object')
if(is.data.frame(x) == TRUE) x <- as.character(x[,1])
df.list <- lapply(x, function(x) {
poss.error <- tryCatch(
{
quantmod::getSymbols(x, env = NULL, return.class = 'data.frame')
},
error = function(e) {
message(cat(x, "could not be retrieved"))
# Get the x variable that was passed to LoadData() and manipulate it.
return(e)
})
}
In the function call LoadData(c('YHOO', 'GOOG')) mentioned in your question, the argument x is not a variable but simply a value. If the value is first stored in a variable, e.g. v, then the value of this variable can be altered by the function. (v is the "global" name outside the function, x is the name inside the function.)
Now consider the function call LoadData(x=v) or simply LoadData(v). To get the variable v from inside the function, two things are needed:
The environment env in which the variable v is stored,
The name under which the variable v is stored in the environment env.
The environment env should be another argument of the function LoadData, perhaps with the global environment as default value:
LoadData <- function(x,env=.GlobalEnv) { ... }
The trick to get the name of the variable passed to the argument x is to use the function match.call. as.list(match.call()) is a named list and as.list(match.call())$x is the "symbol" that is passed to the argument x, i.e. "v" in our case. Then
x.name <- as.character(as.list(match.call())$x`)
is the desired name of the variable passed to the argument x.
Now you can use env[[x.name]] to alter the value of v. The value of v is get(x.name,env), but this is the same as the value of x. So get is not really needed.
Here is a small example:
f <- function( x, v, env=.GlobalEnv )
{
x.name <- as.character(as.list(match.call())$x)
if ( !is.numeric(x) ) { stop(paste0(x.name," must be numeric")) }
env[[x.name]] <- x-v
return(NULL)
}
.
> x <- 5
> y <- 3
> z <- "abc"
> f(x,1)
NULL
> x
[1] 4
> f(y,2)
NULL
> y
[1] 1
> f(z,3)
Error in f(z, 3) : z must be numeric
>
If f is called from another function g to alter the value of a local variable a, the argument env has to be used:
g <- function()
{
a <- 10
print("global environment:")
print(ls(.GlobalEnv))
print("local environment:")
print(ls(environment()))
print("value of `a` before calling `f`:")
print(a)
f(a,1,environment())
print("value of `a` after calling `f`:")
print(a)
return(NULL)
}
.
> g()
[1] "global environment:"
[1] "f" "g" "x" "y" "z"
[1] "local environment:"
[1] "a"
[1] "value of `a` before calling `f`:"
[1] 10
[1] "value of `a` after calling `f`:"
[1] 9
NULL
If the variable passed to LoadData is always the same variable and stored in the global environment, LoadData doesn't need any argument. Then you can simply use <<-.