In my code I have to create an object assigning some values, something like this:
assign(paste("a","bis",sep="."),rep(NA,5))
then I have to replace some of them, like this:
get(paste("a","bis",sep="."))[1:2] <- 7:8
But I get the following error: "Error in get(paste("a", "bis", sep = "."))[1:2] <- 7:8 : target of assignment expands to non-language object".
Of course the code above is a simplified version of the real one. What I'm trying to do is to build a loop which allows me to replace in a data frame the results of some calculations. Something like this
assign(paste(country[j],"ext",sep="."),
data.frame(Year=rep(unique(get(country[j])$Year),each=24),
Age=rep(c(0,1,seq(5,110,5)),length(unique(get(country[j])$Year))),
mx=NA,qx=NA,lx=NA,Lx=NA,Tx=NA,ex=NA))
get(paste(country[j],".ext",sep=""))$mx[(24*i-24+1):(24*i)] <-
c(subset(get(country[j]),Age<=70 & Year==year)$mx,mx.ext)
in this case, the error indicates that: *Error in get(paste(country[j], ".ext", sep = ""))$mx[(24 * i - 24 + 1):(24 * : could not find function "get<-"*
Thanks in advance.
You would be better off saving these items in a list.
myList <- list()
myList[[paste("a","bis",sep=".")]] <- rep(NA,5))
or
myList[[paste(country[j],"ext",sep=".")]] <- data.frame(Year=rep(unique(get(country[j])$Year),each=24),
Age=rep(c(0,1,seq(5,110,5)),length(unique(get(country[j])$Year))),
mx=NA,qx=NA,lx=NA,Lx=NA,Tx=NA,ex=NA))
This relieves you from the pains of get() and assign() and also puts your data in nice structure for looping / applying.
Related
Let me start by saying I'm sure this has been answered before but I am unsure of what terms to search.
I have a few data frames that are named like df_A , df_B , and df_C and wish to send them all to ggplot. I tried to loop through them all but have been unsuccessful. Here is what I have now:
for (Param in c("A","B","C"){
chosen_df <- paste0("df_",Param)
ggplot(data=chosen_df...)
}
I receive back an error saying "data must be a data frame". This error makes sense to me since chosen_df is character vector rather than the actual data frame.
I have tried using noquote but to no avail.
My questions are:
1) What kind of search terms can I look up to solve this problem
2) How close am I to solving this problem?
We can use get to return the value of the object names as a string
for (Param in c("A","B","C"){
chosen_df <- get(paste0("df_",Param))
ggplot(data=chosen_df, ...)
}
Or with mget, return the values in a list
lst1 <- mget(ls(pattern = '^df_[A-Z]$'))
Low level R user here.
I have 3 population data frames (low.proj, med.proj, high.proj) with the exact same number of rows and columns I'm trying to clean and reshape.
I want to eliminate some extra commas in the country column all three of the frames so I'm trying this loop with gsub:
for(i in c("low.proj", "med.proj", "high.proj")){
i$Country <- gsub(",","",i[,"Country"])
}
When I run this I get the error "Error in i[, "Country"] : incorrect number of dimensions"
When I run the code without the loop:
low.proj$Country <- gsub(",","",low.proj[,"Country"])
It works. What causes this error and how do I fix it?
In order to retrieve the contents of the object with the string contained in i use get() to put new data in that object use assign
for(i in c("low.proj", "med.proj", "high.proj")){
tmp <- get(i)
tmp$Country <- gsub(",","",tmp[,"Country"])
assign(i, tmp)
}
You're indexing the wrong variable:
i$Country <- gsub(",","",i[,"Country"])
i is a string, so i$Country doesn't have any meaning.
I have matlab files with an integer in each name of my variables inside (except the first one). I want to loop to concatenate the name of the integers.
There is my code:
library('R.matlab')
mat <- readMat('SeriesContPJM.mat')
#str(mat)
#typeof(mat)
#mat[[1]]
write.csv(mat$vol.PJM$data[[4]][[1]], "PJM.csv")
i = 2
while (i < 7)
{
write.csv(get(paste("mat$vol.PJM", as.character(i), "$data[[4]][[1]]", sep = "")), paste(paste("PJM", as.character(i), sep="_"), "csv", sep ="."))
i = i + 1
}
I have write.csv(mat$vol.PJM$data[[4]][[1]], "PJM.csv") which gives me the good ouput. I would like the same for the other variable names in the loop but I get the following ouput:
+ Error in get(paste("mat$vol.PJM", as.character(i), "$data[[4]][[1]]", (from importpjm.R#10) :
objet 'mat$vol.PJM2$data[[4]][[1]]' introuvable
"introuvable" means "not found" in French.
Here you're mixing where you need to use get and where you need to use eval(parse()).
You can use get with a string variable game, e.g., get("mtcars"), but [ is a function that needs to be evaluated.
get("mtcars[2, 2]") won't work because you don't have a variable named "mtcars[2, 2]", you have a variable named "mtcars" and a function named "[" that can take arguments 2, 2.
eval(parse(text = "mtcars[2, 2]")) will work because it doesn't just look for a variable, it actually evaluates the text string as if you typed it into the command line.
So, you could rewrite your loop, replacing the get(...) with eval(parse(text = ...)) and it would probably work, assuming the strings you've pasted together have the right syntax. But this can be difficult to read and debug. In 6 months, if you look back at this code and need to understand it or modify it, it will be confusing.
Another way to do it would be to use [[ with strings to extract sublists. Rather than mess with eval(parse()) I would do this:
vols = paste0("vol.PJM", 2:7)
for (vol in vols) {
write.csv(mat[[vol]][["data"]][[4]][[1]],
paste0(vol, ".csv"))
}
I think it's more readable, and it's easy to debug the vols vector beforehand to make sure all your names are correct. Similarly, if you want to loop over all elements, you could initialize the vols as something like names(mat), or use some sort of regex criteria to extract the appropriate sublists from names(mat).
In R, I am using readHTMLTable to read in a tables from the web. The tables I want occur at indexes 16 & 17, [[16]] & [[17]].
Here is a small sample of the data for you to work with:
These are some of the urls that contain the HTML tables.
url1 = "http://www.basketball-reference.com/leagues/NBA_1980.html"
url2 = "http://www.basketball-reference.com/leagues/NBA_1981.html"
url3 = "http://www.basketball-reference.com/leagues/NBA_1982.html"
And here, I read in the tables to variables named x1, x2, and x3.
x1 = readHTMLTable(url1)
x2 = readHTMLTable(url2)
x3 = readHTMLTable(url3)
If you look at the summary of each of these summary(x1), summary(x2), summary(x3) and count down through the indexes, the tables I want are the ones named "team" and "opponent", which occur on line 16 and line 17.
I have been trying to write a loop that would cycle through these and name the "team" table from each to a variables named team.1980, team.1981, and team.1982, respectively. The "opponent" tables would follow the same trend, opp.1980, and so forth.
This is the code for the loop I have been trying:
for(i in 1:3) {
for (j in 1980:1982) {
nam1 = paste0("team.", j)
nam2 = paste0("opp.", j)
assign(nam1, paste0("x.", i)[[16]])
assign(nam2, paste0("x.", i)[[17]])
}
}
I think the theory behind this loop works, however the problem occurs with the two assign functions:
assign(nam1, paste0("x.", i)[[16]])
assign(nam2, paste0("x.", i)[[17]])
When I run the loop, I get the error message
Error in paste0("x.", i)[[16]] : subscript out of bounds
which is the same error I get if I just run:
paste0("x", 1)[[16]]
> paste0("x", 1)[[16]]
Error in paste0("x", 1)[[16]] : subscript out of bounds
So I am pretty sure this is where my problem is. Does anyone know how I could cycle through variables and pull out indexes from each?
Please keep in mind that I am rather new to R, so simplicity would be much appreciated! Thanks in advance!
The output from readHTMLTable() is a list and the elements can be referenced by name; index isn't necessary. (Though you can use it.)
Suppose x1, x2, and x3 are defined as in your post. Then you can just do this:
for (i in 1:3) {
year <- 1980 + i - 1
eval(parse(text=paste0("team.", year, " <- x", i, '[["team"]]')))
eval(parse(text=paste0("opp.", year, " <- x", i, '[["opponent"]]')))
}
This evaluates the parsed text that's constructed dynamically in the loop. It creates 6 data frames: team.1980 and opp.1980 for years 1980-1982.
Let's take a closer look at what it's doing...
First a string is constructed using paste0() to concatenate the values into a string with no separator. The first call to paste0() in the first iteration yields this string:
'team.1980 <- x1[["team"]]'
Calling parse() on this tells R to turn that string into an object called an expression. Expressions can be evaluated using eval(). So this string gets turned into an R statement and executed, thereby assigning team.1980.
This process continues for each of the 3 iterations.
This may not be the best approach, but it should work in your situation. I assume you have more than just these 6, otherwise you might as well just write them as individual assignments.
I am trying to rename the columns of a time series using assign function as follows -
assign(colnames(paste0(<logic_to_get_dataset>)),
c(<logic_to_get_column_names>))
I am getting a warning : In assign(colnames(get(paste0("xvars_", TopVars[j, 1], "_lag", :
only the first element is used as variable name
also, the column name assignment does not happen. I think this is happening because of colnames() function. Is there a workaround ?
The issue is that assign only looks at the first element of the vector.
You can try this, for example:
df = data.frame(x = 1:3, y = 4:2)
within(df, assign(colnames(df),c('a','b'))
You'll notice that R only looks at the first variable, and it tries to reassign the values that are described by those column names to the second value. This behavior is obviously not what you're looking for.
Unfortunately, it's kind of hackey, but you can always use something like this
data.frame.name = get_df()#some function that returns text
data.frame.columns = get_cols()#some function that returns text
eval(parse(text = paste0('colnames(',data.frame.name,') = c(',
paste(data.frame.columns,collapse = ','),')')))
I prefer to avoid doing these kinds of expressions, but it should work as intended.
Here it goes -
temp_var <- paste0('colnames(var_',TopLines[j,1],'_lag',get(paste0('uniqLg_',TopLines[j,1]))[k,],'_',get(paste0('uniqLg_',TopLines[j,1]))[k,]+12 ,
') <- c(gsub( "xt',get(paste0('uniqLg_',TopLines[j,1]))[k,],'" , "xt',get(paste0('uniqLg_',TopLines[j,1]))[k,],'__',get(paste0('uniqLg_',TopLines[j,1]))[k,]+12,
'", colnames(var_',TopLines[j,1],'_xt',get(paste0('uniqLg_',TopLines[j,1]))[k,],')))')
print(temp_var )
eval(parse( text=temp_var ))
where TopLines is a data frame with one column and contains a list of lines. The only problem with this method is, I can't test the output of eval unless I actually open the dataset and see if the changes have been affected.