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

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.

Related

How to pass a list whose names is not NULL to the arguments of do.call in r

When I try to pass a list whose names is not NULL, I get the following error from evaluating do.call: Error: argument "x" is missing, with no default. Is there another way to bypass the names of the list and access instead the actual elements within the list without setting the names to NULL?
# with NULL names, do.call runs
num_list <- list(1:10)
do.call(mean,num_list)
# without names being NULL, do.call fails
names(num_list) <- 'a'
do.call(mean,num_list)
Specifically, I'd like to pass the list to a function's ellipsis such as for raster::merge, https://www.rdocumentation.org/packages/raster/versions/3.3-7/topics/merge.
library(rgdal)
library(sf)
library(raster)
cities <- sf::st_read(system.file("vectors/cities.shp", package = "rgdal"))
birds <- sf::st_read(system.file("vectors/trin_inca_pl03.shp", package = "rgdal"))
sf_shapes <- list(cities, birds)
# without names works
sf_shape_extents = lapply(sf_shapes, raster::extent)
sf_max <- do.call(what = raster::merge, args = sf_shape_extents)
# with names does not
names(sf_shapes) <- c('cities', 'birds')
sf_shape_extents_names = lapply(sf_shapes, raster::extent)
sf_max_names <- do.call(what = raster::merge, args = sf_shape_extents)
You either ensure that the names of the list being passed in corresponds to the parameters of the function, or that the list is unnamed and the position of the list elements corresponds to the position of the parameter in question.
names(num_list) <- 'x'
do.call(mean,num_list)
[1] 5.5
names(num_list) <- 'a'
do.call(mean,unname(num_list))
[1] 5.5
EDIT:
I do not see any structural change in your edited version. The error is because of the names since they do not correspond to the named parameters of the function. You are passing in named arguments and that will throw an error.
The question you need to ask yourself is what are the parameter names of the function you intend to use?
If the ellipsis of a function takes in unnamed parameters, then whether the passed in arguments are named or not, it does not matter. eg, the paste function in R:
a <- list(a="a",b=3,c="d");
do.call(paste,a)
[1] "a 3 d"

'=' vs. '<-' as a function argument in R

I am a beginner so I'd appreciate any thoughts, and I understand that this question might be too basic for some of you.
Also, this question is not about the difference between <- and =, but about the way they get evaluated when they are part of the function argument. I read this thread, Assignment operators in R: '=' and '<-' and several others, but I couldn't understand the difference.
Here's the first line of code:
My objective is to get rid of variables in the environment. From reading the above thread, I would believe that <- would exist in the user workspace, so there shouldn't be any issue with deleting all variables.
Here is my code and two questions:
Question 1
First off, this code doesn't work.
rm(ls()) #throws an error
I believe this happens because ls() returns a character vector, and rm() expects an object name. Am I correct? If so, I would appreciate if someone could guide me how to get object names from character array.
Question 2
I googled this topic and found that this code below deletes all variables.
rm(list = ls())
While this does help me, I am unsure why = is used instead of <-. If I run the following code, I get an error Error in rm(list <- ls()) : ... must contain names or character strings
rm(list <- ls())
Why is this? Can someone please guide me? I'd appreciate any help/guidance.
I read this thread, Assignment operators in R: '=' and '<-' and several others, but I couldn't understand the difference.
No wonder, since the answers there are actually quite confusing, and some are outright wrong. Since that’s the case, let’s first establish the difference between them before diving into your actual question (which, it turns out, is mostly unrelated):
<- is an assignment operator
In R, <- is an operator that performs assignment from right to left, in the current scope. That’s it.
= is either an assignment operator or a distinct syntactic token
=, by contrast, has several meanings: its semantics change depending on the syntactic context it is used in:
If = is used inside a parameter list, immediately to the right of a parameter name, then its meaning is: “associate the value on the right with the parameter name on the left”.
Otherwise (i.e. in all other situations), = is also an operator, and by default has the same meaning as <-: i.e. it performs assignment in the current scope.
As a consequence of this, the operators <- and = can be used interchangeably1. However, = has an additional syntactic role in an argument list of a function definition or a function call. In this context it’s not an operator and cannot be replaced by <-.
So all these statements are equivalent:
x <- 1
x = 1
x[5] <- 1
x[5] = 1
(x <- 1)
(x = 1)
f((x <- 5))
f((x = 5))
Note the extra parentheses in the last example: if we omitted these, then f(x = 5) would be interpreted as a parameter association rather than an assignment.
With that out of the way, let’s turn to your first question:
When calling rm(ls()), you are passing ls() to rm as the ... parameter. Ronak’s answer explains this in more detail.
Your second question should be answered by my explanation above: <- and = behave differently in this context because the syntactic usage dictates that rm(list = ls()) associates ls() with the named parameter list, whereas <- is (as always) an assignment operator. The result of that assignment is then once again passed as the ... parameter.
1 Unless somebody changed their meaning: operators, like all other functions in R, can be overwritten with new definitions.
To expand on my comment slightly, consider this example:
> foo <- function(a,b) b+1
> foo(1,b <- 2) # Works
[1] 3
> ls()
[1] "b" "foo"
> foo(b <- 3) # Doesn't work
Error in foo(b <- 3) : argument "b" is missing, with no default
The ... argument has some special stuff going on that restricts things a little further in the OP's case, but this illustrates the issue with how R is parsing the function arguments.
Specifically, when R looks for named arguments, it looks specifically for arg = val, with an equals sign. Otherwise, it is parsing the arguments positionally. So when you omit the first argument, a, and just do b <- 1, it thinks the expression b <- 1 is what you are passing for the argument a.
If you check ?rm
rm(..., list = character(),pos = -1,envir = as.environment(pos), inherits = FALSE)
where ,
... - the objects to be removed, as names (unquoted) or character strings (quoted).
and
list - a character vector naming objects to be removed.
So, if you do
a <- 5
and then
rm(a)
it will remove the a from the global environment.
Further , if there are multiple objects you want to remove,
a <- 5
b <- 10
rm(a, b)
This can also be written as
rm(... = a, b)
where we are specifying that the ... part in syntax takes the arguments a and b
Similarly, when we want to specify the list part of the syntax, it has to be given by
rm(list = ls())
doing list <- ls() will store all the variables from ls() in the variable named list
list <- ls()
list
#[1] "a" "b" "list"
I hope this is helpful.

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.

Extract names of dataframes passed with dots

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"

Convert character vector to numeric vector in R for value assignment?

I have:
z = data.frame(x1=a, x2=b, x3=c, etc)
I am trying to do:
for (i in 1:10)
{
paste(c('N'),i,sep="") -> paste(c('z$x'),i,sep="")
}
Problems:
paste(c('z$x'),i,sep="") yields "z$x1", "z$x1" instead of calling the actual values. I need the expression to be evaluated. I tried as.numeric, eval. Neither seemed to work.
paste(c('N'),i,sep="") yields "N1", "N2". I need the expression to be merely used as name. If I try to assign it a value such as paste(c('N'),5,sep="") -> 5, ie "N5" -> 5 instead of N5 -> 5, I get target of assignment expands to non-language object.
This task is pretty trivial since I can simply do:
N1 = x1...
N2 = x2...
etc, but I want to learn something new
I'd suggest using something like for( i in 1:10 ) z[,i] <- N[,i]...
BUT, since you said you want to learn something new, you can play around with parse and substitute.
NOTE: these little tools are funny, but experienced users (not me) avoid them.
This is called "computing on the language". It's very interesting, and it helps understanding the way R works. Let me try to give an intro:
The basic language construct is a constant, like a numeric or character vector. It is trivial because it is not different from its "unevaluated" version, but it is one of the building blocks for more complicated expressions.
The (officially) basic language object is the symbol, also known as a name. It's nothing but a pointer to another object, i.e., a token that identifies another object which may or may not exist. For instance, if you run x <- 10, then x is a symbol that refers to the value 10. In other words, evaluating the symbol x yields the numeric vector 10. Evaluating a non-existant symbol yields an error.
A symbol looks like a character string, but it is not. You can turn a string into a symbol with as.symbol("x").
The next language object is the call. This is a recursive object, implemented as a list whose elements are either constants, symbols, or another calls. The first element must not be a constant, because it must evaluate to the real function that will be called. The other elements are the arguments to this function.
If the first argument does not evaluate to an existing function, R will throw either Error: attempt to apply non-function or Error: could not find function "x" (if the first argument is a symbol that is undefined or points to something other than a function).
Example: the code line f(x, y+z, 2) will be parsed as a list of 4 elements, the first being f (as a symbol), the second being x (another symbol), the third another call, and the fourth a numeric constant. The third element y+z, is just a function with two arguments, so it parses as a list of three names: '+', y and z.
Finally, there is also the expression object, that is a list of calls/symbols/constants, that are meant to be evaluated one by one.
You'll find lots of information here:
https://github.com/hadley/devtools/wiki/Computing-on-the-language
OK, now let's get back to your question :-)
What you have tried does not work because the output of paste is a character string, and the assignment function expects as its first argument something that evaluates to a symbol, to be either created or modified. Alternativelly, the first argument can also evaluate to a call associated with a replacement function. These are a little trickier, but they are handled by the assignment function itself, not by the parser.
The error message you see, target of assignment expands to non-language object, is triggered by the assignment function, precisely because your target evaluates to a string.
We can fix that building up a call that has the symbols you want in the right places. The most "brute force" method is to put everything inside a string and use parse:
parse(text=paste('N',i," -> ",'z$x',i,sep=""))
Another way to get there is to use substitute:
substitute(x -> y, list(x=as.symbol(paste("N",i,sep="")), y=substitute(z$w, list(w=paste("x",i,sep="")))))
the inner substitute creates the calls z$x1, z$x2 etc. The outer substitute puts this call as the taget of the assignment, and the symbols N1, N2 etc as the values.
parse results in an expression, and substitute in a call. Both can be passed to eval to get the same result.
Just one final note: I repeat that all this is intended as a didactic example, to help understanding the inner workings of the language, but it is far from good programming practice to use parse and substitute, except when there is really no alternative.
A data.frame is a named list. It usually good practice, and idiomatically R-ish not to have lots of objects in the global environment, but to have related (or similar) objects in lists and to use lapply etc.
You could use list2env to multiassign the named elements of your list (the columns in your data.frame) to the global environment
DD <- data.frame(x = 1:3, y = letters[1:3], z = 3:1)
list2env(DD, envir = parent.frame())
## <environment: R_GlobalEnv>
## ta da, x, y and z now exist within the global environment
x
## [1] 1 2 3
y
## [1] a b c
## Levels: a b c
z
## [1] 3 2 1
I am not exactly sure what you are trying to accomplish. But here is a guess:
### Create a data.frame using the alphabet
data <- data.frame(x = 'a', y = 'b', z = 'c')
### Create a numerical index corresponding to the letter position in the alphabet
index <- which(tolower(letters[1:26]) == data[1, ])
### Use an 'lapply' to apply a function to every element in 'index'; creates a list
val <- lapply(index, function(x) {
paste('N', x, sep = '')
})
### Assign names to our list
names(val) <- names(data)
### Observe the result
val$x

Resources