I am a bit of an R novice, and I am stuck with what seems like a simple problem, yet touches pretty deep questions about how and when things get evaluated in R.
I am using Rserve quite a bit; the typical syntax to get things evaluated remotely is a bit of a pain to type repeatedly:
RSeval(connection, quote(try(command)))
So I would like a function r which does the same thing with just the call:
r(command)
My first, naive, bound to fail attempt involved:
r <- function(command) {
RSeval(c, quote(try(command)))
}
You've guessed it: this sends, literally, try(command) to my confused Rserve daemon. I want command to be partially evaluated, if that makes any sense -- i.e. replaced by what I typed as an argument, but without evaluating it locally.
I looked for solutions to this, browsed throught the documentation for quote, substitute, eval, call, etc.. but I was not able to find something that worked. Either command gets evaluated locally, or not at all.
This is not a big problem, I can type the whole damn quote(try()) thing all the time; but at this point I am mostly curious as to how to get this to work!
EDIT:
More explanations as to what I want to do.
In the text above, command is meant to be a call do a function, ideally -- i.e., not a character string. Something like a <- 3 or assign("a", 3) rather than "a<-3" or quote(a<-3).
I believe that this is part of what makes this tricky. It seems really hard to tell R not to evaluate this locally, but only send it literally. Basically I would like my function to be a bit like quote(), which does not evaluate its argument.
Some explanation about my intentions. I wish to use Rserve frequently to pass commands to a remote R daemon. The commands would be my own (or my colleagues) and the daemon protected by firewall and authentication (and would not be run as root) -- so there is no worry of malicious commands being passed.
To be perfectly honest, this is not a big issue, and I would be pretty happy to always use the RSeval(c, quote(try())). At this point I see this more like an interesting inquiry into the subleties of R :-)
You probably want to use the substitute command, it can give you the argument unevaluated that you can build into the call.
I'm not sure if I understood you correctly - would eval(parse(text = command)) do the trick? Notice that command is a character, so you can easily pass it as a function argument. If I'm getting the point...
Anyway, evaluating user-specified commands is potentially malicious, therefore not recommended. You should either install AppArmor and tweak it (which is not an easy one), or drop the whole evaluation thing...
Related
I have a command with six lines that I want to use several times. Therfore, I want to assign a name to this command and use it as a procedure instead of writing the whole command lines over and over.
In this case it is a <-rbind() command, but the issue is also more general.
modelcoeff<-rbind(modelcoeff,c(as.character((summary(mymodel)$terms[[2]])[[3]]),
as.character((((((summary(mymodel)$terms[[2]])[[2]])[[3]])[[3]])[[2]])[[3]]),
summary(mymodel)$coefficients[2,1],
summary(mymodel)$coefficients[2,4],
summary(mymodel)$coefficients[2,2],
summary(mymodel)$r.squared*100))
I would like to call something like rbindmodelcoeff and execute these command lines. How can I achieve this?
I tried to write a function, but it didn't seem to be the right approach.
A literal wrapping of your code into a function:
rbindmodelcoeff <- function(modelcoeff, mymodel) {
rbind(modelcoeff,
c(as.character((summary(mymodel)$terms[[2]])[[3]]),
as.character((((((summary(mymodel)$terms[[2]])[[2]])[[3]])[[3]])[[2]])[[3]]),
summary(mymodel)$coefficients[2,1],
summary(mymodel)$coefficients[2,4],
summary(mymodel)$coefficients[2,2],
summary(mymodel)$r.squared*100))
}
However, there are a couple changes I recommend:
call summary(mymodel) once, then re-use the results
you are using as.character on some of the objects but not all within the enclosing c(.), so everything is being converted to a character; to see what I mean, try c(as.character(1), 2); we can use a list instead to preserve string-vs-number
rbindmodelcoeff <- function(modelcoeff, mymodel) {
summ <- summary(mymodel)
rbind(modelcoeff,
list(as.character((summ$terms[[2]])[[3]]),
as.character((((((summ$terms[[2]])[[2]])[[3]])[[3]])[[2]])[[3]]),
summ$coefficients[2,1],
summ$coefficients[2,4],
summ$coefficients[2,2],
summ$r.squared*100))
}
But there are still some problems with this. I can't get it to work at the moment since I don't know the model parameters you're using, so as.character((summ$terms[[2]])[[3]]) for me will fail. With that, I'm always hesitant to hard-code so many brackets without a firm understanding of what is being used. It's out of scope for this question (which is being converting your basic code into a function), but you might want to find out how to generalize that portion a bit.
I was going through swirl() again as a refresher, and I've noticed that the author of swirl says the command ?matrix is the correct form to calling for a help screen. But, when I run ?matrix(), it still works? Is there a difference between having and not having a pair of parenthesis?
It's not specific to the swirl environment (about which I was entirely unaware until 5 minutes ago) That is standard for R. The help page for the ? shortcut says:
Arguments
topic
Usually, a name or character string specifying the topic for which help is sought.
Alternatively, a function call to ask for documentation on a corresponding S4 method: see the section on S4 method documentation. The calls pkg::topic and pkg:::topic are treated specially, and look for help on topic in package pkg.
It something like the second option that is being invoked with the command:
?matrix()
Since ?? is actually a different shortcut one needs to use this code to bring up that page, just as one needs to use quoted strings for help with for, if, next or any of the other reserved words in R:
?'?' # See ?Reserved
This is not based on a "fuzzy logic" search in hte help system. Using help instead of ? gets a different response:
> help("str()")
No documentation for ‘str()’ in specified packages and libraries:
you could try ‘??str()’
You can see the full code for the ? function by typing ? at the command line, but I am just showing how it starts the language level processing of the expressions given to it:
`?`
function (e1, e2)
{
if (missing(e2)) {
type <- NULL
topicExpr <- substitute(e1)
}
#further output omitted
By running matrix and in general any_function you get the source code of it.
I am using Emacs with SLIME for my development environment. When I type (write-to and then C-M-i I get the following autocompletions:
Click on a completion to select it.
In this buffer, type RET to select the completion near point.
Possible completions are:
write-to-sting
write-to-string
I know Common Lisp is powerful, but I guess write-to-sting is not in the ANSI standard. Google didn't offer a single hit for this function. Then I tried to find it in the SBCL code, but alas
(documentation 'write-to-sting 'function) returns nil so it doesn't have a documentation string.
When I try to execute the function (write-to-sting) I get The function COMMON-LISP-USER::WRITE-TO-STING is undefined.
Apropos also finds an unbound function:
(apropos 'write-to)
WRITE-TO
WRITE-TO-STING
WRITE-TO-STRING (fbound)
My question is: What is going on? Does anyone knows the story behind this function?
At some point during your interaction with the Lisp environment, you wrote write-to-sting and it was read by the Lisp reader. The symbol was interned in the COMMON-LISP-USER package. After all, maybe you intended to implement a function that sends an email to Sting, who knows?
Auto-completion works by filtering the currently known symbols in the environment.
You can safely (unintern 'write-to-sting) (or implement it).
I'm trying to package some code I use for data analysis so that other workers can use it. Currently, I'm stuck trying to write a simple function that imports data from a specific file type generated by a datalogger and trims it for use by other functions. Here's the code:
import<-function(filename,type="campbell",nprobes){
if (filename==TRUE){
if (type=="campbell"){
message("File import type is from Campbell CR1000")
flux.data<<-read.table(filename,sep=",",header=T,skip=1)
flux.data<<-flux.data[,-c(1,2)];flux.data<<-flux.data[-c(1,2),]
if (nprobes=="missing"){
nprobes<-32
}
flux.data<<-flux.data[,c(1:nprobes)]
flux.data.names<<-colnames(flux.data) #Saves column names
}
}
}
Ideally, the result would be a dataframe/matrix flux.data and a concomittant vector/list of the preserved column headers flux.data.names. The code runs and the function executes without errors, but the outputs aren't preserved. I usually use <<- to get around the function enclosure but its not working in this case - any suggestions?
I think the real problem is that I don't quite understand how enclosures work, despite a lot of reading... should I be using environment to assign environments within the function?
User joran answered my question in the comments above:
The critical issue was just in how the function was written: the conditional at the start (if filename==TRUE) was intended to see if filename was specified, and instead was checking to see if it literally equaled TRUE. The result was the conditional never being met, and no function output. Here's what fixed it:
import<-function(filename,type="campbell",nprobes){
if (exists(filename){
if (type=="campbell"){
#etc....
Another cool thing he pointed out was that I didn't need the <<- operator to utilize the function output and instead could write return(flux.data). This is a much more flexible approach, and helped me understand function enclosures a lot better.
Using rscript inside a bash script
I am passing the content of text files has arguments. to rscript
"$SCRIPTS/myscript.R" "$filecontent"
I get the following when file have +- over 4000 row
/usr/bin/Rscript: Argument list too long
Any way I can increase the length of accepted argument so I can pass large files?
What #MrFlick said is correct - you should change the way the arguments are passed to your script. However, if you still want to try to do it your way, then I recommend reading the following article:
"Argument list too long": Beyond Arguments and Limitations
The "Argument list too long" error, which occurs anytime a user feeds
too many arguments to a single command, leaves the user to fend for
oneself, since all regular system commands (ls *, cp *, rm *, etc...)
are subject to the same limitation. This article will focus on
identifying four different workaround solutions to this problem, each
method using varying degrees of complexity to solve different
potential problems.
Also, this Unix&Linux thread can help:
“Argument list too long”: How do I deal with it, without changing my command?