Extract items in a list using variable names in R - r

I'm parsing a JSON using the RJSONIO package.
The parsed item contains nested lists.
Each item in the list can be extracted using something like this:
dat_raw$`12`[[31]]
which correctly returns the string stored at this location (in this example, the '12' refers to the month and [[31]] to day).
"31-12-2021"
I now want to run a for loop to sequentially extract the date for every month. Something like this:
for (m in 1:12) {
print(dat_raw$m[[31]])
}
This, naturally, returns a NULL because there is no $m[[31]] in the list.
Instead, I'd like to extract the objects stored at $`1`[[31]], $`2`[[31]], ... $`12`[[31]].
There must be a relatively easy solution here but I haven't managed to crack it. I'd value some help. Thanks.
EDIT: I've added a screenshot of the list structure I'm trying to extract. The actual JSON object is quite large for a dput() output. Hope this helps
So, to get the date in this list, I'd use something like dat_raw$data$`1`[[1]]$date$gregorian$date.
What I'm trying to do is run a loop to extract multiple items of the list by cycling through $data$`1`[[1]]$..., $data$`2`[[1]]$... ... $data$`12`[[1]]$... using $data$m[[1]]$... in a for loop where m is the month.

Instead of dat_raw$`12`[[31]], you can have dat_raw[[12]][[31]] if 12 is the 12th element of the JSON. So your for loop would be:
for (m in 1:12) {
print(dat_raw[[m]][[31]])
}

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.

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.

Subsetting a List in R where not a value

I'm having trouble "filtering" a list in R because I don't have specific parameters. The function i've created will evaluate 4000 html strings and "decide" if it is a valid or not address:
Tree<-lapply(TreeList,ValURL)
#Returns a list with "Error" or a html string in each element (about 4000 elements total).
I want to create a subset of the Tree list with only the elements that are NOT "Error".I'm used to SQL, so it would be something like:
SELECT * FROM Tree WHERE Column1!="Error"
Obviously it's different in R but I can't seem to get it. I've been trying (to no avail):
Tree$"Error"
Help!
Assuming your Tree looks kind of like this
Tree<-list(
"Error",
"<p>Hello</p>",
"<h1>Heading</h1>",
"Error",
"<strong>Bold</strong"
)
then this should work:
Tree[Tree != "Error"]

In R, package xts, how would one iterate period subsetting over a list without throwing errors?

Assume:
list of n xts objects in .GlobalEnv with the suffix ".raw" (e.g: ABC.raw)
have created a list of .raw names in a list (ie, rawfiles <- ls(pattern="*.raw",envir=.GlobalEnv))
Would like to:
loop or lapply through rawfiles and subset a particular timeperiod in each iteration
for example, to write this as a single line would be: new <- ABC.raw["T09:00/T10:00"] if I wanted to subset ABC.raw from 9am to 10am each day.
The problem is:
Doesn't seem to be an easy way of passing["Thh:mm/Thh:mm"] to a loop, apply or assign without causing errors.
Any ideas how to pass this?
In pidgeon code, I guess I'm looking for a working equivalent of:
for(i in 1:length(raw)){
raw[i]["T09:00/T10:00"]
}
Many thanks in advance for any assistance on this.
Try get.
get(x) retrieves the variable whose name is stored in x, so foo<-1; get('foo') would return 1.
for ( rawname in rawfiles ) {
get(rawname)["T09:00/T10:00"]
}

Resources