以下代码在win7,jdk 1.7,eclipse 4.4.2,R 3.1.2下运行通过。
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)
}
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文件,调用函数
*/
@SuppressWarnings("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>
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]
---------------2
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。示例代码有相关提示。