Extract names of dataframes passed with dots - r

One can use deparse(substitute()) combination to extract the parameter name inside the function like this function
names_from_dots <- function(...) {
deparse(substitute(...))
}
data(iris)
data(swiss)
names_from_dots(iris)
#[1] "iris"
names_from_dots(swiss)
#[1] "swiss"
extracts the name of a data.frame passed in ... (dots) parameter.
But how can one extract every name of passed multiple data.frames
names_from_dots(swiss, iris)
[1] "swiss"
names_from_dots(iris, swiss)
[1] "iris"
When this only returns the name of the first object.

I wouldn’t use substitute here at all, it works badly with ...1. Instead, you can just capture the unevaluated dots using:
dots = match.call(expand.dots = FALSE)$...
Then you can get the arguments inside the dots:
sapply(dots, deparse)
1 Part of the reason is, I think, that substitute does completely different things when called with (a) an argument (which is a “promise” object) or (b) another object. ... falls somewhere in between these two.

You can try the following:
names_from_dots <- function(...) sapply(substitute(list(...))[-1], deparse)
names_from_dots(swiss, iris)
# [1] "swiss" "iris"

Related

R : how to name String without creating an object [duplicate]

This question already has answers here:
What are the differences between "=" and "<-" assignment operators?
(9 answers)
Closed 6 years ago.
I want to just name these strings "Agra" and "huge" as place and adjective in the simplest way possible.
First I tried this
> args <- list(place <- "Agra", adjective <- "huge")
> args[[1]]
[1] "Agra"
but
> args[["place"]]
NULL
and
> place
[1] "Agra"
here only place object is created but the string is not named
whereas
> args <- list(place = "Agra", adjective = "huge")
here
>args[[1]]
"Agra"
> args[["place"]]
[1] "Agra"
> place
[1] "Agra"
Although the second one works but objects are still created. why there is a difference in the outputs of the two methods? how can I give names without creating objects?
It is because <- and = are not the same. For (just about) every purpose except when used inside a function call, <- and = are the same. If you want to pass a named argument, you have to use = not <-. myFunction(X <- expression) will evaluate expression and save the result into the (global) variable X, and put the result as the first (unnamed) argument to myFunction. Contrast to myFunction(X = expression) which pass the expression as the named X argument to myFunction and will not create a (global) variable X.
My explanation is a little garbled - I highly recommend reading ?'<-' (the helpfile for <- and =) which is clearer.
In the first one:
args <- list(place <- "Agra", adjective <- "huge")
R evaluates place <- "Agra" in the global environment, which returns "Agra". It also evaluates adjective <- "huge" in the global environment similarly, returning "huge". Then it places the results ("Agra" and "huge") into the list() call as unnamed arguments, so essentially what you are doing is
place <- "Agra"
adjective <- "huge"
args <- list("Agra", "huge")
That is why you get global variables, and the args list has no names. If this is what you want, you should use the long form not the short form to write it. Using the first form could lead to unexpected or confusing side-effects.
In the second option
args <- list(place = "Agra", adjective = "huge")
it is simply passing the named argument "place" with value "Agra", and the named argument "adjective" with value "huge". Since list() uses argument names as list names, that's why you get a named list. Also, this will not create global variables place and adjective.

From a list of objects, get a character vector of their names

I have a function that takes as an argument a list of functions.
library(moments)
library(plyr)
tests <- list(mean, varience, skewness, kurtosis)
f <- function(X, tests){
out <- each(... = tests)(X) #each from plyr
names(out) <- GetNames(tests)
out
}
I want GetNames to take the list of objects, in this case functions, and return the names of the objects as text. Ideally, I'd like GetNames to work with any list of named objects:
> GetNames(tests)
[1] "mean" "varience" "skewness" "kurtosis"
as.character(tests) returns the text of the code of each function, not their names.
I tried:
GN <- function(X) deparse(substitute(X))
GetNames <- function(X) lapply(tests, GN)
GetNames(tests)
But this returns:
[[1]]
[1] "X[[i]]"
[[2]]
[1] "X[[i]]"
[[3]]
[1] "X[[i]]"
[[4]]
[1] "X[[i]]"
I have some version of this problem frequently when writing R code. I want a function to evaluate its argument some number of steps, here one step from tests to the names of its objects, and then stop and let me do something to the result, here convert them to strings, rather than going on to get the referents of the names before I can grab them (the names).
Once you run
tests <- list(mean, varience, skewness, kurtosis)
those symbols are evaluated and discarded. If you look at
tests[[2]]
or something, you can see there really isn't an original reference to varience, but rather the funcion that the symbol varience pointed to is now stored in a list. (Things work a bit differently when passing parameters to functions thanks to the promises and the call stack but that's not what you're doing here). There is no lazy-evaluation for list() after you've run it.
If you want to keep the names of the functions, it's probably best to work with a named list. You can make a helper function like
nlist <- function(...) { dots<-substitute(...()); setNames(list(...), sapply(dots, deparse))}
tests <- nlist(mean, var, skewness, kurtosis)
Now the values are preserved as names
names(tests)
# [1] "mean" "var" "skewness" "kurtosis"
I confess to being a bit baffled by this question, which makes me think there's some pieces of information you haven't shared with us.
For instance, you say:
I'd like GetNames to work with any list of named objects
Um...well for a named list of objects, such a function already exists, and it's called names().
The "sane" way to do this sort of thing is just name the list in the first place:
tests <- list("mean" = mean, "variance" = variance,
"skewness" = skewness, "kurtosis" = kurtosis)
or you can set the names programmatically via setNames.

How do I access function names in R?

I am writing a function that receives two parameters: a data frame, and a function, and, after processing the data frame, summarizes it using the function parameter (e.g. mean, sd,...). My question is, how can I get the name of the function received as a parameter?
How about:
f <- function(x) deparse(substitute(x))
f(mean)
# [1] "mean"
f(sd)
# [1] "sd"
do.call may be what you want here. You can get a function name as character value, and then pass that and a list of arguments to do.call for evaluation. For example:
X<-"mean"
do.call(X,args=list(c(1:5)) )
[1] 3
Perhaps I'm misunderstanding the question, but it seems like you could simply have the function name as a parameter, and evaluate the function like normal within your function. This approach works fine for me. The ellipsis is for added parameters to your function of interest.
myFunc=function(data,func,...){return(func(data,...))}
myFunc(runif(100), sd)
And if you'd want to apply it to every column or row of a data.frame, you could simply use an apply statement in myFunc.
Here's my try, perhaps, you want to return both the result and the function name:
y <- 1:10
myFunction <- function(x, param) {
return(paste(param(x), substitute(param)))
}
myFunction(y, mean)
# [1] "5.5 mean"

how to access the name of a dataframe in R

my question is how can I get the name of a dataframe not the colnames
for example d is my dataframe I want to use a function to get the exact name "d" rather than the results from names(d)
Thank you so much!
Update:
The reason why I am asking this is because I want to write a function to generate several plots at one time. I need to change the main of the plots in order to distinguish them. My function looks like
fct=function(data){
cor_Max = cor(data)
solution=fa(r = cor_Max, nfactors = 1, fm = "ml")
return(fa.diagram(solution,main=names(data))
}
How can I change the main in the function correspondingly to the data's name?
You can use the fact that R allows you to obtain the text representation of an expression:
getName <- function(x) deparse(substitute(x))
print(getName(d))
# [1] "d"
objects() will list all of the objects in your environment. Note that names(), as used in your question, provides the column names of the data frame.
I read your question to say that you are looking for the name of the data frame, not the column names. So you're looking for the name passed to the data argument of fct. If so, perhaps something like the following would help
fct <- function(data){
cor_Max <- cor(data)
# as.character(sys.call()) returns the function name followed by the argument values
# so the value of the "data" argument is the second element in the char vector
main <- as.character(sys.call())[2]
print(main)
}
This is a bit ad hoc but maybe it would work for your case.
The most accepted way to do this is as Robert showed, with deparse(substitute(x)).
But you could try something with match.call()
f <- function(x){
m <- match.call()
list(x, as.character(m))
}
> y <- 25
> f(y)
# [[1]]
# [1] 25
#
# [[2]]
# [1] "f" "y"
Now you've got both the value of y and its name, "y" inside the function environment. You can use as.character(m)[-1] to retrieve the object name passed to the argument x
So, your function can use this as a name, for example, like this:
fct <- function(data){
m <- match.call()
plot(cyl ~ mpg, data, main = as.character(m)[-1])
}
> fct(mtcars)

Pass object name into do.call() function

Is there a way to pass object name into do.call() function?
For example:
#First make a function that will return the name of object itself.
PrintObjectName <- function(obj){
print(deparse(substitute(obj)))
}
data(iris)
PrintObjectName(iris)
[1] "iris" #This is what I want
do.call(what="PrintObjectName", args=list(obj=iris))
#The output is a messy stuff
You want to use alist within your call to do.call.
alist handles its arguments as if they described function arguments. So the values are not evaluated
do.call(what="PrintObjectName", args=alist(obj=iris))
# [1] "iris"
or you could use quote
do.call(what="PrintObjectName", args=list(obj=quote(iris)))

Resources