Creating (and saving to) an object with a random name - r

I have a function which I use repeatedly. One of the things it returns is a plot visualising effects of a model. I want the function to save the plot to an object, but I want the name of the object to have a random component to it. I use the function multiple times and don't want the plots to overwrite. But I could use the unique identifier in its name to reference it later for the writeup.
So I tried a few things, trying to save a simple object under a partially-random name. All of them fail because I put a function left from the "<-" sign. I'm not going to give examples, because they are just very very wrong.
So I'd like to have something like:
NAME(randomNumber) <- "some plot"
Which, after running multiple times in a function (with the actual input on the right of course) would result in objects named randomly like
NAME104, NAME314, NAME235, etc.
Is this at all doable?

Yes its doable.
Don't do it.
Make a LIST of objects. You can use the name as the key in the list. Example:
plots = list()
plots[["NAME104"]] = "some plot"
plots[["NAMEXXX"]] = "some other plot"
Why? Because now it's easy to loop over the plots stored in the list. Its also easy to create the list in a loop in the first place, something like:
for(i in 1:100){
data = read.table(paste("data",i,".csv"))
name = data$name[1] # get name from column in file
plots[[name]] = plotthing(data)
}
If you really really want to create a thing with a random name, use assign:
> assign(paste0("NAME",round(runif(1,1,1000))), "hello")
> ls(pattern="NAME*")
[1] "NAME11" "NAME333" "NAME717" "NAME719"
But really DONT do that.

Related

Referencing recently used objects in R

My question refers to redundant code and a problem that I've been having with a lot of my R-Code.
Consider the following:
list_names<-c("putnam","einstein","newton","kant","hume","locke","leibniz")
combined_df_putnam$fu_time<-combined_df_putnam$age*365.25
combined_df_einstein$fu_time<-combined_einstein$age*365.25
combined_df_newton$fu_time<-combined_newton$age*365.25
...
combined_leibniz$fu_time<-combined_leibniz$age*365.25
I am trying to slim-down my code to do something like this:
list_names<-c("putnam","einstein","newton","kant","hume","locke","leibniz")
paste0("combined_df_",list_names[0:7]) <- data.frame("age"=1)
paste0("combined_df_",list_names[0:7]) <- paste0("combined_df_",list_names[0:7])$age*365.25
When I try to do that, I get "target of assignment expands to non-language object".
Basically, I want to create a list that contains descriptors, use that list to create a list of dataframes/lists and use these shortcuts again to do calculations. Right now, I am copy-pasting these assignments and this has led to various mistakes because I failed to replace the "name" from the previous line in some cases.
Any ideas for a solution to my problem would be greatly appreciated!
The central problem is that you are trying to assign a value (or data.frame) to the result of a function.
In paste0("combined_df_",list_names[0:7]) <- data.frame("age"=1), the left-hand-side returns a character vector:
> paste0("combined_df_",list_names[0:7])
[1] "combined_df_putnam" "combined_df_einstein" "combined_df_newton"
[4] "combined_df_kant" "combined_df_hume" "combined_df_locke"
[7] "combined_df_leibniz"
R will not just interpret these strings as variables that should be created and be referenced to. For that, you should look at the function assign.
Similarily, in the code paste0("combined_df_",list_names[0:7])$age*365.25, the paste0 function does not refer to variables, but simply returns a character vector -- for which the $ operator is not accepted.
There are many ways to solve your problem, but I will recommend that you create a function that performs the necessary operations of each data frame. The function should then return the data frame. You can then re-use the function for all 7 philosophers/scientists.

Combining many vectors into one larger vector (in an automated way)

I have a list of identifiers as follows:
url_num <- c('85054655', '85023543', '85001177', '84988480', '84978776', '84952756', '84940316', '84916976', '84901819', '84884081', '84862066', '84848942', '84820189', '84814935', '84808144')
And from each of these I'm creating a unique variable:
for (id in url_num){
assign(paste('test_', id, sep = ""), FUNCTION GOES HERE)
}
This leaves me with my variables which are:
test_8505465, test_85023543, etc, etc
Each of them hold the correct output from the function (I've checked), however my next step is to combine them into one big vector which holds all of these created variables as a seperate element in the vector. This is easy enough via:
c(test_85054655,test_85023543,test_85001177,test_84988480,test_84978776,test_84952756,test_84940316,test_84916976,test_84901819,test_84884081,test_84862066,test_84848942,test_84820189,test_84814935,test_84808144)
However, as I update the original 'url_num' vector with new identifiers, I'd also have to come down to the above chunk and update this too!
Surely there's a more automated way I can setup the above chunk?
Maybe some sort of concat() function in the original for-loop which just adds each created variable straight into an empty vector right then and there?
So far I've just been trying to list all the variable names and somehow get the output to be in an acceptable format to get thrown straight into the c() function.
for (id in url_num){
cat(as.name(paste('test_', id, ",", sep = "")))
}
...which results in:
test_85054655,test_85023543,test_85001177,test_84988480,test_84978776,test_84952756,test_84940316,test_84916976,test_84901819,test_84884081,test_84862066,test_84848942,test_84820189,test_84814935,test_84808144,
This is close to the output I'm looking for but because it's using the cat() function it's essentially a print statement and its output can't really get put anywhere. Not to mention I feel like this method I've attempted is wrong to begin with and there must be something simpler I'm missing.
Thanks in advance for any help you guys can give me!
Troy

Preserve a promise in R

I want to, essentially, pass a value untouched through a function. So in the following example (in Rstudio):
example_function <- function(datain){
as.environment("package:utils")$View(datain)
}
I want the inner function to act as if I'm passing it the original object, in particular so the name which appears in the View window will have the name of the original object (X, say) rather than datain which is what currently occurs.
With deparse(substitute(datain)) you can get the original name of the argument passed.
Then, to accomplish what you asked for, you can simply do
example_function <- function(datain){
as.environment("package:utils")$View(datain, deparse(substitute(datain)))
}
Now the View window will be titled appropriately as you wanted.
However note that "I want the inner function to act as if I'm passing it the original object" request of yours is not possible in R. R does not support pass-by-reference. There are some workarounds, but if you only needed if for naming the View, the above fix should be fine.
You can also use get for this.
example_function <- function(datain){
as.environment("package:utils")$View(get(datain),datain)
}
in this case you don't pass the variable but rather the name of the variable as a string.
example_function("X")

How to save results into a various data.frames with various names

I have the following vector:
USTickers=c("BAC","C","JPM","HBS","WFC","GS","MS","USB","BK","PNC")
Actually this vector of mine is much longer, but I just cut it short. This vector has ticker names of stocks.
I use quantmod to download data of the stocks from yahoo.
Since I do not intend to write function for every specific ticker I want to do a loop.
First I want to use a function getSymbols which is not a problem. An object of a specific stock is downloaded.
However I want to make some adjustments of it and save it. Then I have a problem (second line in the for in loop). I want to have a variable name. The name of an object in which it will be saved has to be changing. But I am unable to do that.
for (i in 1:(length(USTickers))) {
getSymbols.yahoo(paste(USTickers[i]),.GlobalEnv,from=StrtDt,to=EndDt)
as.symbol(USTickers[i]=data.frame(time(get(USTickers[1])),get(USTickers[1])[,4],row.names=NULL)
}
In addiction:
in every object of a stock that I download, a column name is in this form "AAL.Open" and i want to change it to "AAL". How am I supposed to change column name?
I know it can be done with colnames function, but i don't know how to automate the operation.
Cause the first part "AAL" will be constantly changing, i just want to get rid of the ".Open" part.
Basically I could just be rewriting it with a ticker name, but I do not know how to apply it when the column name will be changing and I am planning to use as a reference my vector USTickers.
It is a better idea to turn off auto assignment with the getSymbols function and store the results in a list. The elements can be easily accessed later. See the below for some ideas.
require(quantmod)
# Not going to loop through all
USTickers = c("BAC","C")#,"JPM","HBS","WFC","GS","MS","USB","BK","PNC")
# Initialise empty list
mysymbols <- vector("list", length(USTickers))
# Loop through symbols
for (i in 1:length(USTickers)) {
# Store in list
mysymbols[[i]] <- getSymbols.yahoo(paste(USTickers[i]),auto.assign = F)
# Isolate column of interest and date
mysymbols[[i]] <- data.frame(time(mysymbols[[i]]),
mysymbols[[i]][,4],
row.names = NULL)
# Change list elements name to symbol
names(mysymbols)[i] <- USTickers[i]
}
Regarding substituting names, this can be done easily with gsub which can be applied to the colnames. For example:
gsub(".Open", "", "AAL.Open")
However if you just want to make that column name the ticker you can just do that directly in the loop as well colnames(mysymbols[[i]])[2] <- USTickers[i]

In R, I am trying to make a for loop that will cycle through variable names and perform functions on them

I have variables that are named team.1, team.2, team.3, and so forth.
First of all, I would like to know how to go through each of these and assign a data frame to each one. So team.1 would have data from one team, then team.2 would have data from a second team. I am trying to do this for about 30 teams, so instead of typing the code out 30 times, is there a way to cycle through each with a counter or something similar?
I have tried things like
vars = list(sprintf("team.x%s", 1:33)))
to create my variables, but then I have no luck assigning anything to them.
Along those same lines, I would like to be able to run a function I made for cleaning and sorting the individual data sets on all of them at once.
For this, I have tried a for loop
for (j in 1:33) {
assign(paste("team.",j, sep = ""), cleaning1(paste("team.",j, sep =""), j))
}
where cleaning1 is my function, with two calls.
cleaning1(team.1, 1)
This produces the error message
Error in who[, -1] : incorrect number of dimensions
So obviously I am hoping the loop would count through my data sets, and also input my function calls and reassign my datasets with the newly cleaned data.
Is something like this possible? I am a complete newbie, so the more basic, the better.
Edit:
cleaning1:
cleaning1 = function (who, year) {
who[,-1]
who$SeasonEnd = rep(year, nrow(who))
who = (who[-nrow(who),])
who = tbl_df(who)
for (i in 1:nrow(who)) {
if ((str_sub(who$Team[i], -1)) == "*") {
who$Playoffs[i] = 1
} else {
who$Playoffs[i] = 0
}
}
who$Team = gsub("[[:punct:]]",'',who$Team)
who = who[c(27:28,2:26)]
return(who)
}
This works just fine when I run it on the data sets I have compiled myself.
To run it though, I have to go through and reassign each data set, like this:
team.1 = cleaning1(team.1, 1)
team.2 = cleaning1(team.2, 2)
So, I'm trying to find a way to automate that part of it.
I think your problem would be better solved by using a list of data frames instead of many variables containing one data frame each.
You do not say where you get your data from, so I am not sure how you would create the list. But assuming you have your data frames already stored in the variables team.1 etc., you could generate the list with
team.list <- list(team.1, team.2, ...,team.33)
where the dots stand for the variables that I did not write explicitly (you will have to do that). This is tedious, of course, and could be simplified as follows
team.list <- do.call(list,mget(paste0("team.",1:33)))
The paste0 command creates the variable names as strings, mget converts them to the actual objects, and do.call applies the list command to these objects.
Now that you have all your data in a list, it is much easier to apply a function on all of them. I am not quite sure how the year argument should be used, but from your example, I assume that it just runs from 1 to 33 (let me know, if this is not true and I'll change the code). So the following should work:
team.list.cleaned <- mapply(cleaning1,team.list,1:33)
It will go through all elements of team.list and 1:33 and apply the function cleaning1 with the elements as its arguments. The result will again be a list containing the output of each call, i.e.,
list( cleaning1(team.list[[1]],1), cleaning1(team.list[[2]],2), ...)
Since you are now to R I strongly recommend that you read the help on the apply commands (apply, lapply, tapply, mapply). There are very useful and once you got used to them, you will use them all the time...
There is probably also a simple way to directly generate the list of data frames using lapply. As an example: if the data frames are read in from files and you have the file names stored in a character vector file.names, then something along the lines of
team.list <- lapply(file.names,read.table)
might work.

Resources