我正在尝试使用rjava的 Rengine.eval()
方法从Java中调用R。我已经成功地运行了一个简单的"hello world"脚本,并运行了简单的分析,只要我保持单行语句。
当我尝试执行一个多行语句(例如分配一个函数定义),然而,我没能找到一个一致的方法来让它工作。
根据这个Devoxx视频:youtube视频中的演示者,(在36:52标记处)可以通过单独评估每一行来执行多个脚本。除非我误解了他刚才在幻灯片中展示的代码示例。
由于该方法失败了,我编写了一个单元测试,它没有显示工作方法…
有经验的人能解释一下吗?每个测试用例的行为都包含在注释中。(下面的代码块)
任何帮助都是非常感谢的
KR
西蒙import org.junit.Test;
import org.rosuda.JRI.RMainLoopCallbacks;
import org.rosuda.JRI.Rengine;
public class RJavaSanityCheck {
private static Rengine engine;
@Test
public void singleStatementMultiLinesMultiEval(){
Rengine engine = getEngine();
engine.eval("myfunc <- function(x){");
engine.eval("z <- x");
engine.eval("return (x)");
engine.eval("}");
engine.eval("print(myfunc(1))");
//FAIL: Throws two errors:
// Error: object 'x' not found
// Error in print(myfunc(1)) : could not find function "myfunc"
}
@Test
public void singleStatementMultiLinesSingleEvalWindows(){
Rengine engine = getEngine();
engine.eval("myfunc <- function(x){rnz <- xrnreturn(x)rn}rn");
engine.eval("print(myfunc(1))");
engine.end();
//FAIL: Prints nothing and throws an error:
// Error in print(myfunc(1)) : could not find function "myfunc"
}
@Test
public void singleStatementMultiLinesSingleEvalLinux(){
Rengine engine = getEngine();
engine.eval("myfunc <- function(x){nz <- xnreturn(x)n}");
engine.eval("print(myfunc(1))");
engine.end();
//SUCCESS: Prints 1
}
@Test
public void multiStatementsMultiLineSingleEvalLinux(){
Rengine engine = getEngine();
engine.eval("print("Hello")nprint("World!")");
engine.end();
//FAIL: Prints "hello" but not "world!"
}
@Test
public void multiStatementsMultiLineSingleEvalWindows(){
Rengine engine = getEngine();
engine.eval("print("Hello")rnprint("World!")");
engine.end();
//FAIL: Prints nothing
}
@Test
public void MultiStatementsMultiEval(){
Rengine engine = getEngine();
engine.eval("print("Hello")");
engine.eval("print("World!")");
engine.end();
//SUCCESS: Prints Hello World!
}
private static Rengine getEngine(){
if (engine == null){
if (!Rengine.versionCheck()){
throw new RuntimeException("Version mismatch!");
}
engine = new Rengine(new String[]{"--vanilla"}, false, new RMainLoopCallbacks() {
@Override
public void rWriteConsole(Rengine rengine, String s, int i) {
System.out.println(s);
}
@Override
public void rBusy(Rengine rengine, int i) {
//Not implemented
}
@Override
public String rReadConsole(Rengine rengine, String s, int i) {
//Not implemented
return null;
}
@Override
public void rShowMessage(Rengine rengine, String s) {
System.out.println(s);
}
@Override
public String rChooseFile(Rengine rengine, int i) {
//Not implemented
return null;
}
@Override
public void rFlushConsole(Rengine rengine) {
//Not implemented
}
@Override
public void rSaveHistory(Rengine rengine, String s) {
//Not implemented
}
@Override
public void rLoadHistory(Rengine rengine, String s) {
//Not implemented
}
});
if (!engine.waitForR()){
throw new RuntimeException("Loading error!");
}
}
return engine;
}
}
我建议用Rserve代替rJava。
我在我的工作中实现了这两个,并使用rServe解决了我的问题。
更多的实现是在附加的链接。
将R与Java集成
目前我所做的(但不是最优雅的解决方案)是:
public REXP executeFromFile(Rengine engine, File file) throws Exception {
String fileName = file.getCanonicalPath().replace("\", "\\");
return execute(engine, "source(""+fileName+"")");
}