RUtils -- 建立在Rserve之上的Java与R语言通信工具集

  • 注1:RUtils是我偶然发现的一个工具包,它建立在Rserve之上,可以很大程度上简化我们的程序,关于Rserve网络上有很多相关的内容,这里不对其进行介绍,比如这里:http://blog.fens.me/r-rserve-java/
  • 注2:以下内容有很大一部分是“翻译”自官方网站,详情请点开“参考资料”中的链接查看。


简介


        RUtils是一个用于Java连接和使用R语言的工具集,它使用Rserve并在其上添加了”池“功能,简化了多个主机运行多个Rserve进程实例时的配置和使用;另外RUtils还对Rserve的API进行了封装,使我们发送R脚本命令及获取Rserve返回的计算结果等操作可以用非常简洁的代码来完成。

官方主页:http://icb.med.cornell.edu/wiki/index.php/RUtils


依赖


RUtils依赖下面几个软件/项目:

  1.  JDK1.6+
  2.  R语言
  3.  Rserve
  4.  Apache Commons CLI
  5.  Apache Commons Configuration
  6.  Apache Commons I/O
  7.  Apache Commons Lang
  8.  Apache Commons Logging

RUtils的配置文件


        可用的Rserve实例在RUtils中被配置到一个很简洁的XML文件中,XML文件的根元素为RConnectionPool,每个Rserve实例体现为一个RServer节点,每个Rserver节点可以包含以下几个属性:
  1.  host:Rserve正在运行的主机名/IP(必需)
  2.  port:Rserve监听的TCP端口(默认为6311)
  3.  username:建立连接时的用户名(如果需要的话)
  4.  password:建立连接时的密码
  5.  command:远程主机上启动Rserve的命令全路径
  6.  embedded:如果设置为TRUE,RUtils将在连接池初始化时启动Rserve,并在JVM关闭时关闭Rserve服务。这样就不需要手动起停R服务,R服务将在我们应用的Java进程启动之后以守护线程的方式启动。

下面是一个RUtils配置文件的简单示例:

[html]  view plain  copy
  1. <RConnectionPool>  
  2.     <RConfiguration>  
  3.         <RServer host="localhost"/>  
  4.         <RServer host="127.0.0.1" port="6312"/>  
  5.         <RServer host="med.cornell.edu" port="1234" username="me" password="pwd"/>  
  6.     </RConfiguration>  
  7. </RConnectionPool>  

        指定配置文件最好的方式是添加一个key为RConnectionPool.configuration的系统属性,属性值需要指定为classpath下一个合法的资源文件,如果该系统属性没有指定,则默认配置文件为RConnectionPool.xml。


从连接池中获取连接


        连接池类RConnectionPool被设计为单例模式,因此我们不能调用其构造方法对其进行实例化,但我们可以调用该类的静态方法getInstance()来获取RConnectionPool类的实例。从连接池中获取连接可以调用RConnectionPool类的borrowConnection()方法或者borrowConnection(long,java.util.concurrent.TimeUnit)方法,两个方法在连接可用的情况下都会立即返回一个合法的RConnection实例。不带参数的方法在没有连接可用的情况会阻塞;另外一个方法将会等待直到给定时间参数超时,这时方法将返回null。
从连接池中获取的连接在使用完毕后不需要关闭,以保证下次获取时可以重用。如果返回了被关闭的连接将导致下次获取连接时重新建立连接,从而会影响性能。

        当Java进程结束时,为了断开所有的连接连接池应该以尽可能简单的方式关闭。这可以通过调用RConnectionPool类的shutdown方法进行。如果程序没有显式的调用shutdown方法,一个JVM关闭钩子程序将做这些操作。


在Java中调用R脚本


        一旦你拥有了运行中的RServe服务和RConnectionPool.xml配置文件,就可以从Java中调用R了。我们当然可以通过RConnectionPool获取RConnection连接,然后发送R脚本命令从而与Rserve交互,但这样做在R脚本复杂的情况下会很繁琐。更简单的方式就是使用RScript类,如果我们使用RScript来执行R脚本的话不需要自己去获取连接,一切都在RScript中做完了,我们需要做只有下面几项:
  • 1. 指定一个要执行的R脚本
  • 2. 为该脚本指定输入和输出值
  • 3. 执行脚本及获取R返回到Java中的输出值

下面分别来介绍一下这三步的详细情况:


1、 指定要执行的脚本

RScript类提供了两个工厂方法来指定要运行的R脚本,二者都返回一个封装了指定R脚本的RScript对象:
  •  RScript.createFromResource(path to resource) 从CLASSPATH中加载R脚本
  •  RScript.createFromScriptString(script string) 使用字符串构建R脚本

使用字符串构建R脚本示例:

[java]  view plain  copy
  1. final String ksTest = "q <- ks.test(x,y)\n"  
  2.             + "p_value <- q$p.value\n"  
  3.             + "test_statistic <- q$statistic[[1]]";  
  4. final RScript rscript = RScript.createFromScriptString(ksTest);  

如果要使用预先定义的R脚本文件构建RScript的话,只需要将脚本文件放在CLASSPATH下,RScript会自动寻找并加载。


2、 为脚本绑定输入输出参数

        很多情况下我们在调用R脚本需要传入一些参数,同时也可能需要接收R脚本运行得到的结果,RScript为我们提供了setInput方法和setOutput方法分别来绑定输入和输出变量;其中setInput方法有多个重载方法以支持不同的数据类型,而setOutput则使用RDataObjectType枚举类来定义输出变量的类型(见第4点)。在上面的示例中,x和y都是输入参数(double数组类型),而我们要取得变量p_value和test_statistic的值也需要绑定输出变量,所以我们需要为RScript绑定输入输出参数,如下所示:

[java]  view plain  copy
  1. final double[] xValues = new double[] {0.10.20.30.40.5};  
  2. final double[] yValues = new double[] {0.60.70.80.91.0};  
  3. // 为脚本指定输入变量的名字和值  
  4. rscript.setInput("x", xValues);  
  5. rscript.setInput("y", yValues);  
  6. // 为脚本输出指定变量名和类型, 输出必须在脚本执行前指定  
  7. rscript.setOutput("p_value", RDataObjectType.Double);  
  8. rscript.setOutput("test_statistic", RDataObjectType.Double);  


3、 执行脚本并获取返回值

        经过上面两步后,所剩下的也就只有执行R脚本以及获取脚本运行的返回值了。运行脚本通过调用RScript类的execute方法进行;而针对获取不同类型的返回值RScript则提供了一系列的getOutputXXX()方法,其中XXX代表数据类型。如下所示:

[java]  view plain  copy
  1. rscript.execute();  
  2. final double pvalue = rscript.getOutputDouble("p_value");  
  3. final double testStat = rscript.getOutputDouble("test_statistic");  


4、 RDataObjectType 枚举

RUtils使用RDataObjectType枚举类定义了R和Java之间通信支持的数据类型(主要用在绑定输出变量上,以获取R脚本的计算结果),其定义的数据类型有:
  •  RDataObjectType.String 在Java和R中都代表String;获取返回值时用rscript.getOutputString(R script variable name)
  •  RDataObjectType.StringArray 在Java中代表String[],在R中则是c(string vals);获取返回值时调用rscript.getOutputStringArray(R script variable name)
  •  RDataObjectType.Double 在Java和R中都代表Double;获取返回值时调用rscript.getOutputDouble(R script variable name)
  •  RDataObjectType.DoubleArray 在Java中代表Double[],在R中则代表c(double vals);获取数据时调用rscript.getOutputDoubleArray(R script variable name)
  •  RDataObjectType.Double2DArray 在Java中代表double[][],在R中则是matrix;获取返回值时调用rscript.getOutputDouble2DArray(R script variable name)

总结


        RUtils构建于REngine.jar之上,只是简化了其使用,原理也很简单。但如果不使用RUtils我们在调用R脚本文件或者获取各种类型的返回数据时会很麻烦,RUtils正是解决了这些问题,使我们调用Rserve的操作得以简化。

        其实RUtils执行脚本文件时是将脚本文件内容读到内存,构建成一个大的字符串(去掉空行和注释),在调用execute方法时将其发送到Rserve进行执行,这可以从RScript的createFromResource方法的源码看出来;

        RUtils绑定输入参数的原理也十分简单,在我们调用execute方法执行脚本时,如果我们设置了输入变量,那么RUtils会迭代这些变量,根据变量类型组成不同的R变量定义脚本语句,发送到Rserve执行(变量定义);然后才去执行真正的R脚本内容,因此在R解释器执行这些脚本内容时已经可以找到要使用的变量了,脚本因此得以顺利执行。这些可以从RScript源码中的execute方法中看到,execute方法在执行过程中调用了setInputs方法,该方法便做了如上所述的操作。

        RUtils绑定输出参数的原理类似于输入参数的原理,在execute方法执行之后,如果我们绑定了输出参数,那么RUtils会遍历所有绑定的输出参数,直接将参数名作为命令发送到Rserve;在R中如果直接将变量名传递给解释器,解释器会将这个变量的值输出,这时RUtils再获取Rserve的返回值,根据我们绑定输出参数时指定的数据类型封装成相应的Java对象。然后我们向RUtils要求获取输出时它们已经存在了,而且RUtils还会根据我们指定的数据类型进行转换。


参考资料

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值