Insert a Function Name into a Call - r

I have a long script wherein I have a section at the top which is dedicated to assumptions and other hardcodes. By means of context, it's an asset allocation script wherein one of the hardcodes that is chosen is the method by which momentum is calculated, for which I have various functions. I realize that one way in which I could change the code is simply to change the function used in the body of the code; however, my preference would be to leave the body untouched and only change the name of the function to be used within the assumptions section.
By means of an extremely simple toy example, let's say I have the following two lines of code:
selected_function = "sum"
temp_data = c(2,3,4)
How would I allow whichever function is saved in the variable selected_function to be the calling function on the temp_data data set (i.e., if I want to change it to "mean", etc.) and allow that function to be applied to the data.

If you have a function name as a string, you get can get the function itself with getFunction(). That will return a function and you can then pass your values to that returned function. For example.
selected_function = "sum"
temp_data = c(2,3,4)
getFunction(selected_function)(temp_data)

Related

Is there a way to create a function that uses multiple argument, and run the same function independently for each one of them?

I'm pretty new in programming, but I'm trying to learn through practice. I'm coding a function which accepts a variable number of arguments, with the ... function. Here's an example of what I've done:
decyph_test = function(...) {
decript = letters[...]
return(decript)
}
If I enter only one argument (in this case, the required argument is a number, 'cause its used to locate that position in the letter constant) there's no big problem. But, what I want to do is to enter multiple numbers, so each one of them is located to its respective letter, and then is compiled into a vector, which would be the return of the function. Is there any specific way in which I can make any individual argument run the same process of locating its letter counterpart?

R: Not to look for variables outside a function if they do not exist within it

This function is OK in R:
f <- function(x) {
x + y
}
Because if the variable y is not defined inside the function f(), R will look for it outside the environment of the function, in its parent environment.
Apart from the fact that this behavior can be a bug generator, what is the point of functions having input parameters? Anyway, all the variables inside a function can be searched outside of it.
Is there any way not to look for variables outside a function if they do not exist within the function?
Some reasons for using parameters that came to my mind:
Without parameters, users have to define variables before using the function, and these variable names need to match the variable names used within the function -- this is impractical.
How is anyone supposed to know/remember the names of the variables within a function? How do I know which variables within a function are purely local, and which variables have to exist outside of the function?
Input parameters can be passed directly as values or as a variable (and the variable name does not matter).
Input parameters communicate the intended usage of the function; it is clear what data is needed to operate it (or at the very least: how many values need to be inserted by the user of the function)
Input parameters can be documented properly using Rd files (or roxygen syntax)
I am sure there are many other reasons to use input parameters.
M. Papenberg provides a very good explanation.
Here's a quick addendum how to make a function not look for objects in parental environments:
Just provide them in the parameter list! This might sound stupid, but that's what you should always do unless you have good reason to do otherwise. In your example only x is passed to the function. So, if the idea here is that x should be returned if y doesn't exist, you can go for default parameters. In this case this could be done as
f <- function(x, y = 0) {
x + y
}

What is the best way to write a function in R where the output depends on an argument?

I want to write a function that calculates income tax in the UK, potentially inside a package. The precise formula changes regularly, every year say, but instead of writing a new function every time it changes, I want to use an argument, 'year', that controls the behavior of the function. So for example:
income_tax(x = '25000', year = '2019/20')
where x is a vector of incomes and year specifies the tax rules to apply.
What is the best way to organize and manage this function, considering that the formula for each year can be quite complex, and new updates will be added each year?
Is there an object orientated solution? Or write internal functions inside for each year and some if/else logic inside the main function?
It's a bit of a meta-question, as it's not specific to R, but... I imagine that even though the years are different, there are some parts that are common (in form, even if not in all the details) to several years. I'd be tempted to have a list of functions (one per year) that gets called by income_tax, and these in turn are bespoke, but can call common functionality:
year_fns <- list(
`2019/20` = function(x, ...) {
taxable <- post_allowance(x, 11000)
# now some bespoke stuff for this year
if (taxable > 100e3 ){
...
}
....
final_value
},
`2020/21` = #another function
...
)
post_allowance <- function(x, allowance) {
# some common functionality
}
and then you'd just calculate income tax via
income_tax <- function(x, year, ...) {
year_fns[[year]](x, ...)
}
This may take a bit of getting used to, but it's a beauty of R that functions are as easy to handle as numbers, strings etc. So we're looking-up the correct function to call in the year_fns[[year]] part, and then calling that function with the (x,...) part
In R you can pass around expressions (or parts of it), just like numbers and strings, meaning that they can be deployed as arguments in function calls. Most likely, the function expression() may suit your needs.

How do I remove an object from within a function environment in R?

How do I remove an object from the current function environment?
I'm trying to achieve this:
foo <- function(bar){
x <- bar
rm(bar, envir = environment())
print(c(x, is.null(bar)))
}
Because I want the function to be able to handle multiple inputs.
Specifically I'm trying to pass either a dataframe or a vector to the function, and if I'm passing a dataframe I want to set the vector to NULL for later error handling.
If you want, you can watch my DepthPlotter script, where I want to let the second function check if depth is a dataframe, and if so, assign it to df in stead and remove depth from the environment.
Here is a very brief sketch of how to set this up using S3 method dispatch.
First, you define your generic:
DepthPlotter <- function(depth,...){
UseMethod("DepthPlotter", depth)
}
Then you define methods for specific classes of the argument depth. As a very basic example in your case, you might create only two, a data.frame method and a default method to handle the vector case:
DepthPlotter.default <- function(depth, variable, ...){
#Here you write a function assuming that depth is
# anything but a data frame
}
DepthPlotter.data.frame <- function(depth,...){
#Here you'd write a function that assumes
# that depth is a data frame
}
And then you can call DepthPlotter() using either type of argument and the correct function will be run based upon the result of class(depth).
The example I've sketched out here is a little crude, since I've used a default method to handle the vector case. You could write .numeric and .integer methods to handle numeric or integer vectors more specifically. In my example, the .default method will be called for any case other than data.frame, so if you go this route you'd want to write some code in there that checks for strange cases like depth being a complicated list, or other odd object, if you think there's a chance something like that might be passed to the function.

How to use a value that is specified in a function call as a "variable"

I am wondering if it is possible in R to use a value that is declared in a function call as a "variable" part of the function itself, similar to the functionality that is available in SAS IML.
Given something like this:
put.together <- function(suffix, numbers) {
new.suffix <<- as.data.frame(numbers)
return(new.suffix)
}
x <- c(seq(1000,1012, 1))
put.together(part.a, x)
new.part.a ##### does not exist!!
new.suffix ##### does exist
As it is written, the function returns a dataframe called new.suffix, as it should because that is what I'm asking it to do.
I would like to get a dataframe returned that is called new.part.a.
EDIT: Additional information was requested regarding the purpose of the analysis
The purpose of the question is to produce dataframes that will be sent to another function for analysis.
There exists a data bank where elements are organized into groups by number, and other people organize the groups
into a meaningful set.
Each group has an id number. I use the information supplied by others to put the groups together as they are specified.
For example, I would be given a set of id numbers like: part-1 = 102263, 102338, 202236, 302342, 902273, 102337, 402233.
So, part-1 has seven groups, each group having several elements.
I use the id numbers in a merge so that only the groups of interest are extracted from the large data bank.
The following is what I have for one set:
### all.possible.elements.bank <- .csv file from large database ###
id.part.1 <- as.data.frame(c(102263, 102338, 202236, 302342, 902273, 102337, 402233))
bank.names <- c("bank.id")
colnames(id.part.1) <- bank.names
part.sort <- matrix(seq(1,nrow(id.part.1),1))
sort.part.1 <- cbind(id.part.1, part.sort)
final.part.1 <- as.data.frame(merge(sort.part.1, all.possible.elements.bank,
by="bank.id", all.x=TRUE))
The process above is repeated many, many times.
I know that I could do this for all of the collections that I would pull together, but I thought I would be able to wrap the selection process into a function. The only things that would change would be the part numbers (part-1, part-2, etc..) and the groups that are selected out.
It is possible using the assign function (and possibly deparse and substitute), but it is strongly discouraged to do things like this. Why can't you just return the data frame and call the function like:
new.part.a <- put.together(x)
Which is the generally better approach.
If you really want to change things in the global environment then you may want a macro, see the defmacro function in the gtools package and most importantly read the document in the refrences section on the help page.
This is rarely something you should want to do... assigning to things out of the function environment can get you into all sorts of trouble.
However, you can do it using assign:
put.together <- function(suffix, numbers) {
assign(paste('new',
deparse(substitute(suffix)),
sep='.'),
as.data.frame(numbers),
envir=parent.env(environment()))
}
put.together(part.a, 1:20)
But like Greg said, its usually not necessary, and always dangerous if used incorrectly.

Resources