Get a function from a string of the form "package::function" - r

There has been discussion on how to get a variable from a string. Indeed, get works for, say, the data.table function: get("data.table") returns data.table. However,
> get("data.table::data.table")
Error in get("data.table::data.table") :
object 'data.table::data.table' not found
Is there a way to do this that preserves the reference to the package name? I.e., I do NOT want to simply do a split on "::" and get the second half of the string.

You could just use the envir argument to get the function from the namespace.
get("data.table", envir = getNamespace("data.table"))
Or more simply as #joran notes, getFromNamespace() can be used.
getFromNamespace("data.table", "data.table")

Related

Problems obtaining the correct object class. R

I created a small function to process a dataframe to be able to use the function:
preprocessCore::normalize.quantiles()
Since normalize.quintles() can only use a matrixc object, and I need to rearrange my data, I create a small function that takes a specific column (variable) in a especific data frame and do the following:
normal<-function(boco,df){
df_p1<-subset(df,df$Plate==1)
df_p2<-subset(df,df$Plate==2)
mat<-cbind(df_p1$boco,df_p2$boco)
norm<-preprocessCore::normalize.quantiles(mat)
df_1<-data.frame(var_1=c(norm[,1],norm[,2]),well=c(df_p1$well,df_p2$well))
return(df_1)
}
However, "mat" should be a matrix, but it seems the cbind() does not do its job since I'm obtaining the following Error:
normal(antitrombina_FI,Six_Plex_IID)
Error in preprocessCore::normalize.quantiles(mat) :
Matrix expected in normalize.quantiles
So, it is clear that the cbind() is not creating a matrix. I don't understand why this is happening.
Most likely you are binding two NULL objects together, yielding NULL, which is not a matrix. If your df objects are data.frame, then df_p1$boco is interpreted as "extract the variable named boco", not "extract the variable whose name is the value of an object having the symbol boco". I suspect that your data does not contain a variable literally named "boco", so df_p1$boco is evaluated as NULL.
If you want to extract the column that is given as the value to the formal argument boco in function normal() then you should use [[, not $:
normal<-function(boco,df){
df_p1<-subset(df,df$Plate==1)
df_p2<-subset(df,df$Plate==2)
mat<-cbind(df_p1[[boco]],df_p2[[boco]])
norm<-preprocessCore::normalize.quantiles(mat)
df_1<-data.frame(var_1=c(norm[,1],norm[,2]),well=c(df_p1$well,df_p2$well))
return(df_1)
}
Thanks for your help bcarlsen. However I have found some errors:
First, I believe you need to introduce quotes in
mat<-cbind(df_p1[["boco"]],df_p2[["boco"]])
If I run this script outside of a function works erally perfectly:
df_p1<-subset(Six_Plex_IID,Six_Plex_IID$Plate==1)
df_p2<-subset(Six_Plex_IID,Six_Plex_IID$Plate==2)
mat<-cbind(df_p1[["antitrombina_FI"]],df_p2[["antitrombina_FI"]])
norm<-preprocessCore::normalize.quantiles(mat)
However If I introduce this now in a function and try to run it like a function:
normal<-function(boco,df){
df_p1<-subset(df,df$Plate==1)
df_p2<-subset(df,df$Plate==2)
mat<-cbind(df_p1[["boco"]],df_p2[["boco"]])
norm<-preprocessCore::normalize.quantiles(mat)
df_1<-data.frame(var_1=c(norm[,1],norm[,2]),well=c(df_p1$well,df_p2$well))
return(df_1)
}
normal(antitrombina_FI,Six_Plex_IID)
I get the same error mesage:
Error in preprocessCore::normalize.quantiles(mat) :
Matrix expected in normalize.quantiles
I'm completely clueless about why this is happening, why outside the function I'm obtaining a matrix and why inside the function not.
Thanks

Why the code only works with numbers and not letters?

I have to use the code bellow but I don't completely understand how it works. Why it won't work if I change du.4 by du.f and then use the f when calling the function? For some reason it only works with numbers and I do not undarstand why.
This is the error that it is giving in the case of du.f
Error in paste("Meth1=", nr, ".ps", sep = "") : object 'f' not found
du.4 <- function(u,v,a){(exp(a)*(-1+exp(a*v)))/(-exp(a)+exp(a+a*u)-exp(a*(u+v))+exp(a+a*v))}
plotmeth1 <- function(data1,data2,alpha,nr) {
psfile <-paste("Meth1=",nr,".ps",sep="")
diffmethod <-paste("du.",nr,sep="")
title=paste("Family",nr)
alphavalue <-paste("alpha=",round(alpha,digits=3),sep="")
#message=c("no message")
postscript(psfile)
data3<-sort(eval(call(diffmethod,data1,data2,alpha)))
diffdata <-data3[!is.na(data3)]
#if(length(data3)>length(diffdata))
#{message=paste("Family ",nr,"contains NA!")}
tq <-((1:length(diffdata))/(length(diffdata)+1))
plot(diffdata,tq,main=title,xlab="C1[F(x),G(y)]",ylab="U(0,1)",type="l")
legend(0.6,0.3,c(alphavalue))
abline(0,1)
#dev.off()
}
In R, a dot is used as just another character in identifiers. It is often used for clarity but doesn't have a formal function in defining the part after the dot as being in a name-space given by the part of the identifier before the dot. In something like du.f you can't refer to the function by f alone, even if your computation is inside of an environment named du. You can of course define a function named du.4 and then use 4 all by itself, but when you do so you are using the number 4 as just a number and not as a reference to the function. For example, if
du.4 <- function(u,v,a){(exp(a)*(-1+exp(a*v)))/(-exp(a)+exp(a+a*u)-exp(a*(u+v))+exp(a+a*v))}
Then du.4(1,2,3) evaluates to 21.08554 but attempting to use 4(1,2,3) throws the error
Error: attempt to apply non-function
In the case of your code, you are using paste to assemble the function name as a string to be passed to eval. It makes sense to paste the literal number 4 onto the string 'du.' (since the paste will convert 4 to the string '4') but it doesn't make sense to paste an undefined f onto 'du.'. It does, however, make sense to paste the literal string 'f' onto 'du.', so that the function call plotmeth1 (data1, data2, alpha, 'f') will work even though plotmeth1 (data1, data2, alpha, f) will fail.
See this question for more about the use of the dot in R identifiers.

save get'd variable (after assign)

Why can't R find this variable?
assign(paste0('my', '_var'), 2)
get(paste0('my', '_var')) ## isn't this returning an object?
save(get(paste0('my', '_var')), file = paste0('my', '_var.RDATA'))
This throws the error:
Error in save(paste0("my", "_var"), file = paste0("my", "_var.RDATA")) :
object ‘paste0("my", "_var")’ not found
From the help page, the save() function expects "the names of the objects to be saved (as symbols or character strings)." Those values are not evaulated, ie you can't put in functions that will eventually return strings or raw values themselves. Use the list= parameter if you want to call a function to return a string the the name of a variable.
save(list=paste0('my', '_var'), file = paste0('my', '_var.RDATA'))
Though using get/assign is often not a good practice in R. They are usually better ways so you might want to rethink your general approach.
And finally, if you are saving a single object, you might want to consider saveRDS() instead. Often that's the behavior people are expecting when they use the save() function.
The documentation for save says that ... should be
the names of the objects to be saved (as symbols or character strings).
And indeed if you type save into the console you can see that the source has the line
names <- as.character(substitute(list(...)))[-1L]
where substitute captures its argument and doesn't evaluate it. So as the error suggests, it is looking for an object with the name paste0('my', '_var'), not evaluating the expressions supplied.

$ operator for variable object names

I am trying to use the $ operator for selecting and reformating specific columns in a for loop on variably created data.frame objects. I tried 4 different solutions in my commented code, but none of them works. I looked all over SO but i don't seem to find another solution to try.
How can i make use of the $ operator to select specific columns with variable data.frame names?
Thanks
weather_data_files<-c("CMC","ECMWF","ECMWF_VAR_EPS_MONTHLY_FORECAST",
"GFS","ICON_EU","UKMET_EURO4")
for(filename in weather_data_files){
#create data frame environment objects
assign(paste(filename),read.csv(file = paste(filename,".csv",sep = ""),sep = ";"))
#first solution does not work, because filename is here an atomic vector
#rather than a data.frame
#ErrorMessage: $ operator is invalid for atomic vectors
filename$Forecast.Time<- as.POSIXct(filename$Forecast.Time,
format="%d.%m.%Y %H:%M+%S",tz="UTC")
#ok get it, let's try second soltution,but
#it also does not work allthough i try to get the data.frame object
#ErrorMesssage: could not find function "get<-
get(filename)$Forecast.Time<-
as.POSIXct(get(filename)$Forecast.Time,format="%d.%m.%Y %H:%M+%S",tz="UTC")
#Third solution as.name also does not work
#ErrorMessage: object of type 'symbol' is not subsettable
as.name(filename)$Forecast.Time<-
as.POSIXct(as.name(filename)$Forecast.Time,format="%d.%m.%Y %H:%M+%S",tz="UTC")
#Fourth solution comparable to second solution, still not working
#ErrorMessage: could not find function "eval<-"
eval(assign(filename,get(filename)))$Forecast.Time<-
as.POSIXct(eval(assign(filename,get(filename)))$Forecast.Time,
format="%d.%m.%Y %H:%M+%S",tz="UTC")
}
So, the problem is you're passing in character strings, not objects. The get function retrieves the object, just doesn't have a place to store it.
You could always load the character string into a temporary variable as you're looping. Operate on the temporary variable and then assign when you're done.
for(filename in c("a","b")){
tmp <- get(filename)
}
You could also skip most of the for loop and use the apply family.
files = lapply(paste(c("CMC","ECMWF","ECMWF_VAR_EPS_MONTHLY_FORECAST",
"GFS","ICON_EU","UKMET_EURO4"),".csv",sep=""),
read.csv,sep=";")
files = lapply(files,function(x){x$Forecast.Time = as.POSIXct(x$Forecast.Time,
format="%d.%m.%Y %H:%M+%S",tz="UTC");return(x)}
Now you have a list of your files you can work on. You could assign them to global variables if you want.

Pass non-string argument to r function and use it inside this function as is

I am a bit confused with the way arguments are transmitted to r function, and the associated syntax (quoting, substituting, evaluating, calling, expressions, "...", ...) .
Basically, what I need to do is to pass arguments in a function using only their name, but without using the type "character".
This is a (not working) illustration of what I would like to do
require(dplyr)
test <- function(x) select(iris, DesiredFunction(x))
test(Species)
I am also interested in general resources about the possibilities to pass arguments to functions.
Thank you,
François
UPDATE
The following is working
require(dplyr)
test <- function(x) select_(iris, substitute(x))
test(Species)
Is there a way to do this but with "select" instead of "select_" ?
Or in other words, what is the inverse operation for quoting ?

Resources