1 搭建R环境
在使用Java代码调用R代码之前,需要先保证本机环境已搭建R环境,可以正常执行R代码。否则,在R开发工具中尚不能执行R代码,在java中调用R很有可能会失败。 下载R windows安装包,https://cran.r-project.org/bin/windows/base/ 选择一个版本,解压,执行\R-3.1.2\bin\x64\Rgui.exe,打开R界面窗口,会显示命令行。执行以下命令,验证R已正确安装;
sessionInfo() 会显示R版本、本机操作系统等信息 x <- c(1,2,3) x * 10 会显示[1] 10 20 30
2 编写R测试代码
点击左上角菜单,新建R文件,保存到某一个目录下,路径中最好没有空格和括号等特殊字符,命名为1.R 将下面内容复制到里面保存。
test_no_param <- function (){ return(100) } # 入参为一个list和一个整数,出参为一个list test_param_list <- function (x, y) { x[,2] <- x[,2] * y return(x) }1234567891012345678910
3 执行R代码
全选代码,点击工具栏运行代码图标,加载两个函数,R Console窗口命令行会输出相关信息。在命令行输入下面代码,结果如下:
test_no_param() [1] 100 在命令行输入下面代码,结果如下: c1 <- c(“a”,”b”,”c”) c2 <- c(1, 2, 3) x <- data.frame(c1,c2) x c1 c2 1 a 1 2 b 2 3 c 3 y <- test_param_list(x, 10) y c1 c2 1 a 10 2 b 20 3 c 30
4 安装rJava包
如果上面两个函数执行无问题,表示本地已搭建好R环境。在命令行执行: install.packages(“rJava”) 选择国内的一个源,R会安装一个包,rJava。接下来通过这个包,实现在java代码中调用上面的函数。
5 在系统环境变量中添加R路径
新建R_HOME的变量,值为R的根路径,如E:\R\R-3.1.2; 在PATH中添加 %R_HOME%;%R_HOME%/bin/x64;%R_HOME%/library/rJava/jri/x64; 保存; 打开cmd窗口,输入R,正常会显示R版本信息,并进入R代码执行模式,输入quit()退出。表示R已配置到系统环境变量中。
6 编译路径添加相关jar
在R的安装目录(\R-3.1.2\library\rJava\jri)下,找到三个jar包:JRI.jar,JRIEngine.jar,REngine.jar。在eclipse中新建一个java工程,将三个jar包添加到工程编译路径下。 新建Test2.java,代码如下:
package com; import java.util.Arrays; import org.rosuda.JRI.REXP; import org.rosuda.JRI.RList; import org.rosuda.JRI.RVector; import org.rosuda.JRI.Rengine; /** * 使用rJava包,调用R代码中的函数 * * @author frank * @since 2016-11-14 * */ public class Test2 { public static void main(String[] args) { Test2 test2 = new Test2(); test2.method2(); } /** * 加载R文件,调用函数 */ "deprecation") ( public void method2(){ // R文件全路径 String filePath = "D:\\1.R"; // 初始化R解析类 Rengine engine = new Rengine(null, false, null); System.out.println("Rengine created, waiting for R"); // 等待解析类初始化完毕 if (!engine.waitForR()) { System.out.println("Cannot load R"); return; } // 将文件全路径复制给R中的一个变量 engine.assign("fileName", filePath); // 在R中执行文件。执行后,文件中的两个函数加载到R环境中,后续可以直接调用 engine.eval("source(fileName)"); System.err.println("R文件执行完毕"); { // 直接调用无参的函数,将结果保存到一个对象中 REXP rexp = engine.eval("test_no_param()"); System.err.println(rexp); // 已知返回值的类型,故将其转换为double,供其他代码使用 double d = rexp.asDouble(); System.err.println(d); System.err.println("---------------1"); } { // 定义一个数组,与R中c1集合对应 String[] arr1 = new String[]{"a", "b", "c"}; // 将数组复制给R中的变量c1。R中变量无需预先定义 engine.assign("c1", arr1); // 定义一个数组,与R中c2集合对应 double[] arr2 = new double[]{1, 2, 3}; // 将数组复制给R中的变量c2 engine.assign("c2", arr2); // 将c1 c2连接为一个集合(R中的数据集,类似java的list),赋值给一个变量 engine.eval("x <- data.frame(c1, c2)"); // 将一个数值保存到一个变量中 engine.eval("y <- 10"); // 入参为list,出参为list。调用R中函数,将结果保存到一个对象中。 REXP rexp = engine.eval("test_param_list(x, y)"); System.err.println(rexp); // 解析rexp对象,转换数据格式 // list的标题 RList list = rexp.asList(); String[] key = list.keys(); System.err.println(Arrays.toString(key)); if(key != null){ int i = 0; while (i < key.length){ i++; } } // list的数据 RVector v = rexp.asVector(); for(int i=0; i<v.size(); i++){ REXP rexpTemp = (REXP) v.get(i); if(REXP.INTSXP == rexpTemp.rtype){ int[] arr = rexpTemp.asIntArray(); System.err.println(Arrays.toString(arr)); } else if(REXP.STRSXP == rexpTemp.rtype){ String[] arr = rexpTemp.asStringArray(); System.err.println(Arrays.toString(arr)); } else if(REXP.REALSXP == rexpTemp.rtype){ double[] arr = rexpTemp.asDoubleArray(); System.err.println(Arrays.toString(arr)); } } System.err.println("---------------2"); } engine.stop(); } }
jar包maven配置:
<properties> <rjava.version>0.9-7</rjava.version> </properties> <!-- rjava --> <!-- https://mvnrepository.com/artifact/com.github.lucarosellini.rJava/JRIEngine --> <dependency> <groupId>com.github.lucarosellini.rJava</groupId> <artifactId>JRIEngine</artifactId> <version>${rjava.version}</version> </dependency> <dependency> <groupId>com.github.lucarosellini.rJava</groupId> <artifactId>REngine</artifactId> <version>${rjava.version}</version> </dependency> <dependency> <groupId>com.github.lucarosellini.rJava</groupId> <artifactId>JRI</artifactId> <version>${rjava.version}</version> </dependency>1234567891011121314151617181920212212345678910111213141516171819202122
7 运行java代码
正常输出如下结果:
Rengine created, waiting for R R文件执行完毕 [REAL* (100.0)] 100.0 ---------------1 [VECTOR ([FACTOR {levels=("a","b","c"),ids=(0,1,2)}], [REAL* (10.0, 20.0, 30.0)])] [c1, c2] null [10.0, 20.0, 30.0] ---------------21234567891012345678910
8 备注1
至此,已实现在java中调用R函数、执行R代码。test_param_list入参、出参均为list,复杂的参数都可以使用list进行传输,基本能满足常见的java调用R函数的业务场景。执行过程中,若报错,可google上搜索结果。
9 备注2
R安装目录\R\R-3.1.2\library\rJava\jri\examples下有官方示例代码,可参考。需要注意的是:编写业务代码时不要调用rni开头的函数,此类函数为低级别api。示例代码有相关提示。