4.2 Rsession让Java调用R更简单

问题

Java调用R有没有更简单的方法?

引言

Rserve作为R语言的通信接口,已经成为了R语言扩展的重要通道。但Rserve过于底层,用Java调用Rserve的API接口,也有些难于理解。于是就出现了Rsession项目,Rsession是对Rserve的封装,提供了更高层的API接口,包括Rserve服务器控制和多会话机制,并支持Windows环境。Rsession简化了Java调用Rserve的API接口的难度,提供了一种简单的方式,让Java可以访问远程或本地的Rserve实例。另一个R和Java通信的库JRI,并不支持多会话机制,在下一节中会介绍。

4.2.1 Rsession下载

4.2.1 Rsession下载

  • Win7 64bit
  • R: 3.0.1 x86_64-w64-mingw32/x64 b4bit

注:Rsession同时支持Win7环境和Linux环境。

1. 直接下载发行包

Rsession包括3个jar包:REngine.jar、Rserve.jar和Rsession.jar,可以通过链接http://rsession.googlecode.com/files/libRsession.zip下载发行包,下载之后解压缩就可以直接使用了。

2. 下载源代码,自己编译发行包。

也可以通过源代码下载Rsession,Rsession项目的SVN地址是http://rsession.googlecode.com/svn/trunk/Rsession/。从SVN下载Rsession项目的操作如下:

~ cd d:\workspace\java   # 进入本地目录
~ svn checkout http://rsession.googlecode.com/svn/trunk/ rsession-read-only   # 通过svn下载
~ mv rsession-read-only rsession    # 把目录改名
~ cd rsession\Rsession               # 进行Rsession代码目录
Rsession项目是通过Ant构建的,我们可以自己编译、打包。 Ant是一个Java的自动化构建工具。
~ ant                          # 用ant构建项目
Buildfile: d:\workspace\java\rsession\Rsession\build.xml
clean:
clean-dist:
init:
    [mkdir] Created dir: d:\workspace\java\rsession\Rsession\build
    [mkdir] Created dir: d:\workspace\java\rsession\Rsession\dist\lib
resource:
     [copy] Copying 28 files to d:\workspace\java\rsession\Rsession\dist\lib
     [copy] Copied 12 empty directories to 1 empty directory under d:\workspace\java\rsession\Rsession\dist\lib
compile:
    [javac] d:\workspace\java\rsession\Rsession\build.xml:33: warning: 'includeantruntime' was not set, defaulting to bu
ild.sysclasspath=last; set to false for repeatable builds
    [javac] Compiling 10 source files to d:\workspace\java\rsession\Rsession\build
dist:
      [jar] Building jar: d:\workspace\java\rsession\Rsession\dist\lib\Rsession.jar
      [zip] Building zip: d:\workspace\java\rsession\Rsession\dist\libRsession.zip
BUILD SUCCESSFUL
Total time: 2 seconds

运行上面的ant命令,就在目录 d:\workspace\java\rsession\Rsession\dist\ 下面生成了发行包,libRsession.zip 。与直接下载的libRsession.zip文件不同的是,自己手动编译打包的 libRsession.zip 文件中,解压后多了一个文件jmatharray.jar。我觉得这个文件可能是编译过程中需要的依赖包,在运行时是不需要的,有没有都不影响我们的程序运行。

4.2.3 用Eclipse构建Rsession项目

用Eclipse构建Rsession项目,复制Rsession\dist\目录文件到项目,并加载到项目的环境变量,如图4-2所示。

用Eclipse构建Rsession项目

图4-2 用Eclipse构建Rsession项目

4.2.4 Rsession的API介绍

查看类库Rsession.jar,如图4-3所示,可以看到Rsession的各个API,包括接口类、功能类和辅助类,下面分别介绍。

Rsession.jar文件结构

图4-3 Rsession.jar文件结构

(1) 接口类

  • BusyListener: 用于监听R引擎的状态
  • EvalListener: 用于监听R引擎执行R脚本的情况
  • Logger: 用于日志输出
  • UpdateObjectsListener: 用于监听R运行时环境的变化

(2) 功能类

  • Rdaemon: RServe的守护进程
  • RLogPanel: 显示R日志的控件
  • RObjectsPanel: 显示R变量的控件
  • RserverConf: 连接Rserve实例的配置文件
  • Rsession: 连接Rserve实例
  • StartRserve: 启动本地的Rserve

(3) 辅助类

  • RegistryHog: 用于从Windows系统的注册表读取R的安装信息。
  • StreamHog: 用于进程之间的通信。

4.2.5 Rsession使用

接下来,我们用Rsession访问远程的Rserve服务器。

1. Rserve服务器端环境

远程服务器系统环境:

  • Linux: Ubuntu 12.04.2 LTS 64bit
  • R: 3.0.1 x86_64-pc-linux-gnu

远程的Rserve环境:

  • Rserve: Rserve v1.7-1
  • IP: 192.168.1.201,允许远程访问
  • 端口: 6311
  • 登陆认证: 用户名:conan, 密码:conan
  • 字符编码: utf-8

Rserve服务器环境与5.2节 Rserve的R语言客户端RSclient 环境配置相同。

2. Java程序代码

下面我们来写一个Java的类,实现Java对远程Rserve服务器的调用。 新建Java程序文件 RsessionDemo.java。

package org.conan.r.rsession;

import java.io.File;
import java.util.Properties;
import org.math.R.RserverConf;
import org.math.R.Rsession;
import org.rosuda.REngine.REXPMismatchException;

public class RsessionDemo {
   /**
    * Main方法用于启动Java应用
    */
    public static void main(String args[]) throws REXPMismatchException {        
        RserverConf rconf = new RserverConf("192.168.1.201", 6311, "conan", "conan", new Properties());  //建立远程连接
        Rsession s = Rsession.newInstanceTry(System.out, rconf);        
        double[] rand = s.eval("rnorm(5)").asDoubles();  // 执行R脚本
        System.out.println(rand);        
        s.set("demo", Math.random());  // 创建一个R对象
        s.eval("ls()");      
        s.save(new File("./output/save.Rdata"), "demo");    // 保存R运行时状态到文件       
        s.rm("demo");   // 删除R对象demo
        s.eval("ls()");     
        s.load(new File("./output/save.Rdata"));     // 从文件加载R环境
        s.eval("ls()");
        s.eval("print(demo)");       
        s.set("df", new double[][] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 }, { 10, 11, 12 } }, "x1", "x2", "x3");   // 创建一个data.frame对象
        double df$x1_3 = s.eval("df$x1[3]").asDouble();
        System.out.println(df$x1_3);
        s.rm("df");     
        s.eval("getwd()");     // 生成一个图形文件
        s.toJPEG(new File("./output/plot.png"), 400, 400, "plot(rnorm(10))");
        String html = s.asHTML("summary(rnorm(100))");          // 以HTML格式输出
        System.out.println(html);
        String txt = s.asString("summary(rnorm(100))");    // 以文本格式输出
        System.out.println(txt);
        System.out.println(s.installPackage("sensitivity", true));   // 安装新类库
        s.end();
    }
}

3 运行日志输出

为了方便阅读,我把对应的Java程序与日志放在一起显示。首先执行R脚本。

double[] rand = s.eval("rnorm(5)").asDoubles();  // 执行R脚本
for(double ran:rand){
    System.out.print(ran+",");
}
 [eval] rnorm(5)  // 日志输出

org.rosuda.REngine.REXPDouble@5f934ad[5]{0.08779203903807914,0.039929482749452114,-0.8788534039223883,-0.8875740206608903,-0.8493446334021442}
0.08779203903807914,0.039929482749452114,-0.8788534039223883,-0.8875740206608903,-0.8493446334021442

然后创建R对象并保存R环境

s.set("demo", Math.random());  // 创建一个R对象
s.eval("ls()");
s.save(new File("./output/save.Rdata"), "demo");  // 保存R环境到本地到文件
s.rm("demo");  // 删除R对象demo
s.eval("ls()");
s.load(new File("./output/save.Rdata"));  // 从文件加载R环境
s.eval("ls()");
s.eval("print(demo)");
 [set] demo  //日志输出

再创建一个data.frame对象。

s.set("df", new double[][] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 }, { 10, 11, 12 } }, "x1", "x2", "x3");
double df$x1_3 = s.eval("df$x1[3]").asDouble();
System.out.println(df$x1_3);
s.rm("df");
 [set] df  //日志输出

在本地生成一个图形文件,如图4-4所示。

s.toJPEG(new File("./output/plot.png"), 400, 400, "plot(rnorm(10))");
[set] plotfile_1100539400  //日志输出

 toJPEG图片

图4-4 toJPEG图片

以HTML格式输出

String html = s.asHTML("summary(rnorm(100))");
System.out.println(html);
<html>     Min.   1st Qu.    Median      Mean   3rd Qu.      Max. <br/>-2.332000 -0.659900  0.036920  0.004485  0.665800  2.517000 </html>  //日志输出

以文本格式输出

String txt = s.asString("summary(rnorm(100))"); // format in text
System.out.println(txt);
    Min.  1st Qu.   Median     Mean  3rd Qu.     Max.  //日志输出
-3.19700 -0.65330 -0.09893 -0.07190  0.53300  2.29000

安装新类库

System.out.println(s.installPackage("sensitivity", true)); // 安装新类库 trying to load package sensitivity //日志输出 package sensitivity is not installed. package sensitivity not yet installed. [eval] install.packages('sensitivity',repos='http://cran.cict.fr/',dependencies=TRUE) org.rosuda.REngine.REXPNull@4d47c5fc request package sensitivity install... package sensitivity is not installed. ! package sensitivity installation failed. Impossible to install package sensitivity ! ```

对比5.1节 Rserve的JavaAPI,是不是感觉Rsession更友好呢!Rsession封装了Java调用R的过程,对于有Java基础的同学可以快速上手,让Java应用也能玩转统计计算。动起手来,创造就在自己手中。

results matching ""

    No results matching ""