Using string as object in R - r

I have variable a as string:
a = "jul_0_baseline,jul_1_baseline,...jul_11_baseline,jul_12_baseline"
When I try to merge the following zoo series to one table using:
temp <- merge(jul_0_baseline,jul_1_baseline,...jul_11_baseline,jul_12_baseline)
it works, however when I try to merge it using
temp <- merge(a)
I get an error as it the variable a is a string (even though the text is correct). I am assuming that it is effectively inputting
temp <- merge("jul_0_baseline,jul_1_baseline,...jul_11_baseline,jul_12_baseline")
Any help would be greatly appreciated
a is a string because it is created using the code:
a <- paste("jul","0","baseline",sep = "_")
for (d in 1:12){ b <- paste("jul",d,"baseline",sep = "_")
a <- paste(a,b, sep=",")
}

Form the entire command string (including merge) and then parse and evaluate it:
eval(parse(text = sprintf("merge(%s)", a)))

Since each jul_i_baseline listed in the string a corresponds to an actual object, you can do this:
temp <- Reduce(function(...) merge(..., all=T), mget(strsplit(a, ",")[[1]]))
The strsplit() function splits a into a vector of strings where each element is "jul_i_baseline". It returns a one-element list, so we can use [[1]] to get the vector of strings.
mget() interprets the list of variables in strings as objects. It returns a list where each element corresponds to the object. So each element is the actual Zoo object jul_i_baseline.
Reduce(function(...) merge(..., all=T), <list>) merges the objects stored in each element of the list. Assuming the objects have a common variable on which you want to merge, you can also add a by variable in merge().
An alternate approach as suggested in the comments is to use do.call() which would work since you're dealing with Zoo objects. (The former approach works with non-Zoo objects as well but this does not.) The command would be structured like so:
temp <- do.call(merge, mget(strsplit(c, ",")[[1]]))
Again we're getting the objects using mget() and strsplit().
#G.Grothendiek's suggestion of using eval(parse(...)) also works in this situation. However, many R users discourage the use of eval(parse(...)) in general. See here.

Related

What does declaring function at the start of a line do?

I encountered this code:
res <- lapply(strsplit(s, "\n")[[1]],
(function (str) paste(rev(strsplit(str, "")[[1]]), collapse = "")))
The secodnd line reverses each of the splitted strings at the first line.
How does it do that? Namely, what does calling 'function' at the start do?
Calling lapply takes and performs some function on each list element. It takes the form lapply(list_data, some_function). So, for instance, if I have a list of integers and want to find out how many integers are in each list element, I would run:
list_data <- list(list1 = 1:5,
list2 = 6:10,
list3 = 11:30)
lapply(list_data, length)
The function here is length, which is a function that is inherent in R. Some functions aren't defined in R, say if I want define my own formula for each value in the list, I could define my own function. Calling a function allows users to define a function that is not already in R or an R library. Like so:
lapply(list_data, function(x) x^2+4-x^3)
The function here is x^2+4-x^3, which is not defined in R programming itself.
So in your example, your data is strsplit(s, "\n")[[1]] and it is taking that data and applying the function paste(rev(strsplit(str, "")[[1]]), collapse = "")) to each element in the data.
Note that in my example, I put function(x) - your example puts function(str) - what's in the parentheses doesn't matter and is user defined. For example lapply(list_data, function(str) str^2+4-str^3) will return the same thing as lapply(list_data, function(x) x^2+4-x^3)
Please note that broad "learning" style questions like this are not exactly what this site is for, and this question will likely get removed and/or receive some negative feedback. Since you are new to this site and to R, I'm providing this answer but I would not be surprised if the question is removed. Just trying to help both you and the SO community!

How do you solve "could not find function "deparse<-" | "as.name<-" | "eval<-"" errors when trying to dynamically name dataframes in R? [duplicate]

I am using R to parse a list of strings in the form:
original_string <- "variable_name=variable_value"
First, I extract the variable name and value from the original string and convert the value to numeric class.
parameter_value <- as.numeric("variable_value")
parameter_name <- "variable_name"
Then, I would like to assign the value to a variable with the same name as the parameter_name string.
variable_name <- parameter_value
What is/are the function(s) for doing this?
assign is what you are looking for.
assign("x", 5)
x
[1] 5
but buyer beware.
See R FAQ 7.21
http://cran.r-project.org/doc/FAQ/R-FAQ.html#How-can-I-turn-a-string-into-a-variable_003f
You can use do.call:
do.call("<-",list(parameter_name, parameter_value))
There is another simple solution found there:
http://www.r-bloggers.com/converting-a-string-to-a-variable-name-on-the-fly-and-vice-versa-in-r/
To convert a string to a variable:
x <- 42
eval(parse(text = "x"))
[1] 42
And the opposite:
x <- 42
deparse(substitute(x))
[1] "x"
The function you are looking for is get():
assign ("abc",5)
get("abc")
Confirming that the memory address is identical:
getabc <- get("abc")
pryr::address(abc) == pryr::address(getabc)
# [1] TRUE
Reference: R FAQ 7.21 How can I turn a string into a variable?
Use x=as.name("string"). You can use then use x to refer to the variable with name string.
I don't know, if it answers your question correctly.
strsplit to parse your input and, as Greg mentioned, assign to assign the variables.
original_string <- c("x=123", "y=456")
pairs <- strsplit(original_string, "=")
lapply(pairs, function(x) assign(x[1], as.numeric(x[2]), envir = globalenv()))
ls()
assign is good, but I have not found a function for referring back to the variable you've created in an automated script. (as.name seems to work the opposite way). More experienced coders will doubtless have a better solution, but this solution works and is slightly humorous perhaps, in that it gets R to write code for itself to execute.
Say I have just assigned value 5 to x (var.name <- "x"; assign(var.name, 5)) and I want to change the value to 6. If I am writing a script and don't know in advance what the variable name (var.name) will be (which seems to be the point of the assign function), I can't simply put x <- 6 because var.name might have been "y". So I do:
var.name <- "x"
#some other code...
assign(var.name, 5)
#some more code...
#write a script file (1 line in this case) that works with whatever variable name
write(paste0(var.name, " <- 6"), "tmp.R")
#source that script file
source("tmp.R")
#remove the script file for tidiness
file.remove("tmp.R")
x will be changed to 6, and if the variable name was anything other than "x", that variable will similarly have been changed to 6.
I was working with this a few days ago, and noticed that sometimes you will need to use the get() function to print the results of your variable.
ie :
varnames = c('jan', 'feb', 'march')
file_names = list_files('path to multiple csv files saved on drive')
assign(varnames[1], read.csv(file_names[1]) # This will assign the variable
From there, if you try to print the variable varnames[1], it returns 'jan'.
To work around this, you need to do
print(get(varnames[1]))
If you want to convert string to variable inside body of function, but you want to have variable global:
test <- function() {
do.call("<<-",list("vartest","xxx"))
}
test()
vartest
[1] "xxx"
Maybe I didn't understand your problem right, because of the simplicity of your example. To my understanding, you have a series of instructions stored in character vectors, and those instructions are very close to being properly formatted, except that you'd like to cast the right member to numeric.
If my understanding is right, I would like to propose a slightly different approach, that does not rely on splitting your original string, but directly evaluates your instruction (with a little improvement).
original_string <- "variable_name=\"10\"" # Your original instruction, but with an actual numeric on the right, stored as character.
library(magrittr) # Or library(tidyverse), but it seems a bit overkilled if the point is just to import pipe-stream operator
eval(parse(text=paste(eval(original_string), "%>% as.numeric")))
print(variable_name)
#[1] 10
Basically, what we are doing is that we 'improve' your instruction variable_name="10" so that it becomes variable_name="10" %>% as.numeric, which is an equivalent of variable_name=as.numeric("10") with magrittr pipe-stream syntax. Then we evaluate this expression within current environment.
Hope that helps someone who'd wander around here 8 years later ;-)
Other than assign, one other way to assign value to string named object is to access .GlobalEnv directly.
# Equivalent
assign('abc',3)
.GlobalEnv$'abc' = 3
Accessing .GlobalEnv gives some flexibility, and my use case was assigning values to a string-named list. For example,
.GlobalEnv$'x' = list()
.GlobalEnv$'x'[[2]] = 5 # works
var = 'x'
.GlobalEnv[[glue::glue('{var}')]][[2]] = 5 # programmatic names from glue()

How to name an object out of a string in R [duplicate]

I am using R to parse a list of strings in the form:
original_string <- "variable_name=variable_value"
First, I extract the variable name and value from the original string and convert the value to numeric class.
parameter_value <- as.numeric("variable_value")
parameter_name <- "variable_name"
Then, I would like to assign the value to a variable with the same name as the parameter_name string.
variable_name <- parameter_value
What is/are the function(s) for doing this?
assign is what you are looking for.
assign("x", 5)
x
[1] 5
but buyer beware.
See R FAQ 7.21
http://cran.r-project.org/doc/FAQ/R-FAQ.html#How-can-I-turn-a-string-into-a-variable_003f
You can use do.call:
do.call("<-",list(parameter_name, parameter_value))
There is another simple solution found there:
http://www.r-bloggers.com/converting-a-string-to-a-variable-name-on-the-fly-and-vice-versa-in-r/
To convert a string to a variable:
x <- 42
eval(parse(text = "x"))
[1] 42
And the opposite:
x <- 42
deparse(substitute(x))
[1] "x"
The function you are looking for is get():
assign ("abc",5)
get("abc")
Confirming that the memory address is identical:
getabc <- get("abc")
pryr::address(abc) == pryr::address(getabc)
# [1] TRUE
Reference: R FAQ 7.21 How can I turn a string into a variable?
Use x=as.name("string"). You can use then use x to refer to the variable with name string.
I don't know, if it answers your question correctly.
strsplit to parse your input and, as Greg mentioned, assign to assign the variables.
original_string <- c("x=123", "y=456")
pairs <- strsplit(original_string, "=")
lapply(pairs, function(x) assign(x[1], as.numeric(x[2]), envir = globalenv()))
ls()
assign is good, but I have not found a function for referring back to the variable you've created in an automated script. (as.name seems to work the opposite way). More experienced coders will doubtless have a better solution, but this solution works and is slightly humorous perhaps, in that it gets R to write code for itself to execute.
Say I have just assigned value 5 to x (var.name <- "x"; assign(var.name, 5)) and I want to change the value to 6. If I am writing a script and don't know in advance what the variable name (var.name) will be (which seems to be the point of the assign function), I can't simply put x <- 6 because var.name might have been "y". So I do:
var.name <- "x"
#some other code...
assign(var.name, 5)
#some more code...
#write a script file (1 line in this case) that works with whatever variable name
write(paste0(var.name, " <- 6"), "tmp.R")
#source that script file
source("tmp.R")
#remove the script file for tidiness
file.remove("tmp.R")
x will be changed to 6, and if the variable name was anything other than "x", that variable will similarly have been changed to 6.
I was working with this a few days ago, and noticed that sometimes you will need to use the get() function to print the results of your variable.
ie :
varnames = c('jan', 'feb', 'march')
file_names = list_files('path to multiple csv files saved on drive')
assign(varnames[1], read.csv(file_names[1]) # This will assign the variable
From there, if you try to print the variable varnames[1], it returns 'jan'.
To work around this, you need to do
print(get(varnames[1]))
If you want to convert string to variable inside body of function, but you want to have variable global:
test <- function() {
do.call("<<-",list("vartest","xxx"))
}
test()
vartest
[1] "xxx"
Maybe I didn't understand your problem right, because of the simplicity of your example. To my understanding, you have a series of instructions stored in character vectors, and those instructions are very close to being properly formatted, except that you'd like to cast the right member to numeric.
If my understanding is right, I would like to propose a slightly different approach, that does not rely on splitting your original string, but directly evaluates your instruction (with a little improvement).
original_string <- "variable_name=\"10\"" # Your original instruction, but with an actual numeric on the right, stored as character.
library(magrittr) # Or library(tidyverse), but it seems a bit overkilled if the point is just to import pipe-stream operator
eval(parse(text=paste(eval(original_string), "%>% as.numeric")))
print(variable_name)
#[1] 10
Basically, what we are doing is that we 'improve' your instruction variable_name="10" so that it becomes variable_name="10" %>% as.numeric, which is an equivalent of variable_name=as.numeric("10") with magrittr pipe-stream syntax. Then we evaluate this expression within current environment.
Hope that helps someone who'd wander around here 8 years later ;-)
Other than assign, one other way to assign value to string named object is to access .GlobalEnv directly.
# Equivalent
assign('abc',3)
.GlobalEnv$'abc' = 3
Accessing .GlobalEnv gives some flexibility, and my use case was assigning values to a string-named list. For example,
.GlobalEnv$'x' = list()
.GlobalEnv$'x'[[2]] = 5 # works
var = 'x'
.GlobalEnv[[glue::glue('{var}')]][[2]] = 5 # programmatic names from glue()

Different beheavior of get and mget in aggregation (R)

I have an character array (chr [1:5] named keynn) of column names on which I would like to perform an aggregation.
All elements of the array is a valid column name of the data frame (mydata), but it is a string and not the variable ("YEAR" instead of mydata$YEAR).
I tried using get() to return the column from the name and it works, for the first element, like so:
attach(mydata)
aggregate(mydata, by=list(get(keynn, .GlobalEnv)), FUN=length)
I tried using mget() since my array as more than one element, like this:
attach(mydata)
aggregate(mydata, by=list(mget(keynn, .GlobalEnv)), FUN=length)
but I get an error:
value for 'YEAR' not found.
How can I get the equivalent of get for multiple columns to aggregate by?
Thank you!
I would suggest not using attach in general
If you are just trying to get columns from mydata you can use [ to index the list
aggregate(mydata, by = mydata[keynn], FUN = length)
should work -- and is very clear that you want to get keynn from mydata
The problem with using attach is that it adds mydata to the search path (not copying to the global environment)
try
attach(mydata)
mget(keynn, .GlobalEnv)
so if you were to use mget and attach, you need
mget(keynn, .GlobalEnv, inherits = TRUE)
so that it will not just search in the global environment.
But that is more effort than it is worth (IMHO)
The reason get works is that inherits = TRUE by default. You could thus use lapply(keynn, get) if mydata were attached, but again this ugly and unclear about what it is doing.
another approach would be to use data.table, which will evaluate the by argument within the data.table in question
library(data.table)
DT <- data.table(mydata)
DT[, {what you want to aggregate} , by =keynn]
Note that keynn doesn't need to be a character vector of names, it can be a list of names or a named list of functions of names etc

Use ls() or objects() to get objects of class data.frame

Is there anyway I can loop through some set of objects and apply a function to each?
When I type ls() or objects(), it returns a list of object names. I could like to iterate through this list, identify those which are data.frame, and then run a function against each object.
How do I pass an entry from ls or objects through a function?
The answer given by #jverzani about figuring out which objects are data frames is good. So let's start with that. But we want to select only the items that are data.frames. So we could do that this way:
#test data
df <- data.frame(a=1:10, b=11:20)
df2 <- data.frame(a=2:4, b=4:6)
notDf <- 1
dfs <- ls()[sapply(mget(ls(), .GlobalEnv), is.data.frame)]
the names of the data frames are now strings in the dfs object so you can pass them to other functions like so:
sapply( dfs, function(x) str( get( x ) ) )
I used the get() command to actually get the object by name (see the R FAQ for more about that)
I've answered your qeustion above, but I have a suspicion that if you would organize your data frames into list items your code would be MUCH more readable and easy to maintain. Obviously I can't say this with certainty, but I can't come up with a use case where iterating through all objects looking for the data frames is superior to keeping your data frames in a list and then calling each item in that list.
You can get an object from its name with get or mget and iterate with one of the apply type functions. For example,
sapply(mget(ls(), .GlobalEnv), is.data.frame)
will tell you which items in the global environment are data frames. To use within a function, you can specify an environment to the ls call.
You can loop through objects in environment using "eapply".
Throwing in another solution to the mix using inherits. It basically (a) gets all objects from the current environment and (b) checks if they inherit from a data frame.
sapply(sapply(ls(), get), inherits, 'data.frame')
You can use the function get() to refer to an object by name
# Create some objects
df <- data.frame(a=1:10)
dl <- list(a=1, b=2, c=3)
# Use `ls()` to return a list of object names
lso <- ls()
# Use `get()` to refer to specific objects
class(get(lso[1]))
[1] "data.frame"
# Using an apply function to evaluate the class
lapply(lso, function(x) class(get(x)))
[[1]]
[1] "data.frame"
[[2]]
[1] "list"
You can use Filter with is.data.frame and ls in mget to get a named list of in this case of data.frame objects.
This list can then be used e.g. in lapply to apply each element of the list to a function.
L <- Filter(is.data.frame, mget(ls()))
lapply(L, nrow)

Resources