How can I write a function that takes an argument which is passed to the data function in R.
As a simple example
load_data <- function(mydata) {
x <- data(mydata)
x
}
If I tried to use this to load iris
load_data(mydata = "iris")
The function just returns "data set mydata not found"
My end goal here is to have a function that attaches a dataset to the function's environment, and then the function would do some arbitrary calculations.
If you want data() to evaualte that character string, it needs to be passed via list=
load_data <- function(mydata) {
x <- data(list=mydata)
x
}
I'm not sure what you were expecting to be returned but the ?data help page tells you it just returns the name of the data sets loaded, not the data itself.
If you only want it to load into the function scope, then also set the environment= parameter
load_data <- function(mydata) {
data(list=mydata, environment=environment())
}
If you want iris to be stored in x then you don't need to call data at all.
load_data <- function(mydata) {
x <- mydata
x
}
load_data(iris)
Related
I am currently writing a function that will take an equation as an argument. The function will expect variables to be apart of the column names of data.
mydata <- data.frame(x=c(1,2,3,4),y=c(5,6,7,8), z=c(9,10,11,12))
my_function <- function(data, equ) {
EQU.sub <- deparse(substitute(equ))
#Check if colnames are used
for(i in 1:length(colnames(data)) {
if(str_detect(string = EQU.sub, pattern = colnames(data)[i])) {
#if used, create variable with its name.
assign(x = colnames(data)[i],
value = eval(parse(text = paste("data$",
colnames(data),
sep = ""))))
} else {
warning(paste(colnames[i], "was not used in EQU"))
}
}
df$new.value <- eval(equ)
output <- function(new.equ = equ)
return(df)
}
my_function(data = mydata, equ = x+(y^2))
I know what you may be thinking, this is a big workaround for just doing
mydata$x+(mydata$y^2)
THE ISSUE
The issue is that I want to pass my input of equ into an new function.
new_function <- function(new.equ) {
string <- deparse(substitute(new.equ))
#does some stuff....
return(output) }
however, when changing from execution environment of my_function to new_function, calling deparse(substitute(equ)) returns "equ" instead of "x+(y^2)"
I know that the function substitute returns what was explicitly assigned to the variable. (equ) but I am wondering if there is a way for new_function() to be able to see into the execution environment of my_function() so I can get the desired output of "x+(y^2)"
UPDATE
After thinking about it, I could change what I pass to new.equ to the deparsed version of equ as follows...
output <- function(new.equ = EQU.sub)
new_function <- function(new.equ) {
#given that these variables are available
value <- parse(text = new.equ)
#does some stuff....
return(output) }
but my original question still stands because I'm still new to R environments. Is there a more elegant way to go through execution environments?
Using non-standard evaulation like this can be pretty messy. Rather than trying to capture expressions from promises passed to functions, it's much safer just to pass a formula. For example
mydata <- data.frame(x=c(1,2,3,4),y=c(5,6,7,8), z=c(9,10,11,12))
my_function <- function(data, equ) {
stopifnot(inherits(equ, "formula"))
eval(equ[[2]], data)
}
new_function <- function(newequ) {
my_function(mydata, newequ)
}
my_function(mydata, ~x+(y^2))
new_function(~x+(y^2))
Or give your function an extra parameter where you can pass an expression instead so you don't have to rely on a promise. This makes it much easier to write other functions that can call your function.
my_function <- function(data, equ, .equ=substitute(equ)) {
eval(.equ, data)
}
new_function <- function(newequ) {
equ <- substitute(newequ)
my_function(mydata, .equ=equ)
}
my_function(mydata, x+(y^2))
new_function(x+(y^2))
my_function(mydata, .equ=quote(x+(y^2)))
I've got some code that creates an object from a formula and saves the call for future use, as so:
create_obj <- function(formula, data) {
obj <- list()
# Populate obj with whatever we're interested in
# ...
# Save call for future use
obj$call <- match.call()
obj
}
obj <- create_obj(time ~ sex, data)
If I then bootstrap data I can easily build the model on the new dataset:
data <- data[sample(1:nrow(data), replace=T), ]
new_obj <- eval(obj$call)
However, if I have the formula saved in a variable and I pass the object into a new environment this won't work:
do_stuff <- function(object, newdata) {
data <- newdata[sample(1:nrow(newdata), replace=T), ]
new_object <- eval(object$call)
}
main <- function() {
my_form <- time ~ sex
obj2 <- create_obj(my_form, data)
# obj2$call: 'create_obj(formula = my_form, data = data)'
do_stuff(obj2, data)
}
Error: object my_form not found.
How can I have it so that obj$call saves time~sex rather than myform? Otherwise I need to pass the formula itself around rather than just the object, limiting the practicality.
The above example isn't reproducible but you can see the same thing with a standard lm call.
EDIT: I've solved the problem, see the accepted answer.
I've solved it by having the constructor function modify the call by evaluating the constant argument in the local environment:
create_obj <- function(formula, data) {
obj <- list()
# Populate obj with whatever we're interested in
# ...
# Save call for future use
func_call <- match.call()
func_call$formula <- eval(formula)
# obj_call is now: create_obj(formula=time~sex, data=data)
obj$call <- func_call
obj
}
I want to build a function that calls another object that name is related to the main object name.
For example, Main object is 'VCU_Players' and the other object is 'VCU_Players_opp'
in my function i need to use both objects in my calculations.
So i am trying to do
my_function<- function(x) {
y<-deparse(substitute(x))
z<-"_opp"
y<- paste(y,z,sep = "")
#My Calculations
x$newfield<- x$pts+ y$pts
Return(x)
}
Now i want to pass the object VCU_Players to the function
my_function(VCU_Players)
But the function doesn't figure the VCU_Players_opp object
Consider passing string literals and using get() to retrieve corresponding object:
teams <- c("Team1", "Team2", "Team3", "Team4", "Team5", "Team6",
"Team7", "Team8", "Team9", "Team10", "Team11", "Team12")
my_function <- function(i) {
x <- get(paste0(i, "_players"))
y <- get(paste0(i, "_opp"))
# My Calculations
x$newfield <- x$pts + y$pts
return(x)
}
dfList <- lapply(teams, my_function)
Ideally, however is working with a few lists of many objects, and not separate multiple objects in your global environment. Try importing from your data source (i.e., Excel) multiple objects into single lists:
teamdfs <- c(Team1_players, Team2_players, Team3_players, Team4_players, Team5_players, Team6_players,
Team7_players, Team8_players, Team9_players, Team10_players, Team11_players, Team12_players)
team_oppdfs <- c(Team1_opp, Team2_opp, Team3_opp, Team4_opp, Team5_opp, Team6_opp,
Team7_opp, Team8_opp, Team9_opp, Team10_opp, Team11_opp, Team12_opp)
my_function <- function(x, y) {
# My Calculations
x$newfield <- x$pts + y$pts
return(x)
}
dfList <- mapply(my_function, teamdfs, team_oppdfs, SIMPLIFY = FALSE)
# EQUIVALENT TO Map(my_function, teamdfs, team_oppdfs)
I want to build a function in such a way that once i supplied data='name of data frame' there is no need to write variable=data$variable as just writing variable name from the supplied data frame will serve the purpose
myfunction<-function(variable,data)
{
result=sum(data)/sum(variable)
return(result)
}
for example i have a data frame df
df<-data.frame(x=1:5,y=2:6,z=3:7,u=4:8)
I want to provide following input
myfunction(variable=x,data=df)
instead of below input to serve the purpose
myfunction(variable=df$x,data=df)
We can use non-standard evaluation:
myfunction <- function(variable, data) {
var <- eval(substitute(variable), data)
result = sum(data)/sum(var)
return(result)
}
# Test
myfunction(variable = x, data = df)
#[1] 6
The with or attach functions can help you here, see the ?with and ?attach documentation. Alternatively, you can supply the variable name as a character and use this in the function body. I.e. you can do something like this:
myfunction2 <- function(variable, data) {
result <- sum(data)/sum(data[[variable]])
return(result)
}
df <- data.frame(x=1:5,y=2:6,z=3:7,u=4:8)
myfunction2("x", df)
#[1] 6
Yet another resort is to use non-standard evaluation. A small example of this is something like:
myfunction3 <- function(variable, data) {
var.name <- deparse(substitute(variable))
result <- sum(data)/sum(data[[var.name]])
return(result)
}
myfunction3(variable = x, data = df)
#[1] 6
Is there any way to "check" or "verify" a source code file in R when sourcing it ?
For example, I have this function in a file "source.R"
MyFunction <- function(x)
{
print(x+y)
}
When sourcing "source.R", I would like to see some sort of warning : MyFunctions refers to an undefined object Y.
Any hints on how to check / verifiy R code ?
Cheers!
I use a function like this one for scanning all the functions in a file:
critic <- function(file) {
require(codetools)
tmp.env <- new.env()
sys.source(file, envir = tmp.env)
checkUsageEnv(tmp.env, all = TRUE)
}
Assuming source.R contains the definitions of two rather poorly written functions:
MyFunction <- function(x) {
print(x+y)
}
MyFunction2 <- function(x, z) {
a <- 10
x <- x + 1
print(x)
}
Here is the output:
critic("source.R")
# MyFunction: no visible binding for global variable ‘y’
# MyFunction2: local variable ‘a’ assigned but may not be used
# MyFunction2: parameter ‘x’ changed by assignment
# MyFunction2: parameter ‘z’ may not be used
You can use the codetools package in base R for that. And if you had your code in a package, it would tell you about this: