查看原文
其他

JAVA如何与R完美结合起来

2017-05-14 王亨 R语言中文社区

作者:王亨 ,R语言中文社区专栏作者,跟着菜鸟一起一步步学习R语言,争做R语言高手。

个人公众号:跟着菜鸟一起学R语言(微信ID:learn_R) 


为什么要用java调用R?


     Java作为一个非常流行的编程语言,具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。

但是Java缺乏数据分析以及可视化的能力。但是R语言却是专门为统计而生,R语言近年来发展迅速,可以用来进行机器学习,数据挖掘,数据可视化。 为了弥补这种差距, 我们可以将JAVA与R结合起来


今天我们来说两种方法,首先第一个,JAVA通过Rserve调用R语言。


一,环境

系统:win10

JDK:1.8

R:3.3.1

eclipse:luna


二.准备工作

在R软件里面安装Rserve包


install.packages("Rserve")


如果你已经安装了这个包就不需要这一步。如果安装过程没有报错就OK。接下来我们就要通过下面语句启动服务:


Rserve()


如果出现下面语句这表示服务已经启动好了:


Starting Rserve... "D:\PROGRA~1\R\R-33~1.1\library\Rserve\libs\x64\Rserve.exe"


现在我们已经运行Rserve服务器,我们就可以在eclipse中创建一个Java程序,使用Rserve与R进行通信,并在Java代码中调用R的函数。 


我创建里一个RserveProject的java工程,然后右击工程名—properties—Java Build Path—Librares—Add External Jar...加载REngine.jar和Rserve.jar两个jar包,我把R装在了D:\Program Files\下,所以那两个包在D:\Program Files\R\R-3.3.1\library\Rserve\java。大家根据自己的实际情况找找。




三.编写Java程序


在下面程序中,我分别直接调用了R中的函数,也调用自己的R脚本。


import org.rosuda.REngine.Rserve.RConnection; import org.rosuda.REngine.Rserve.RserveException; import org.rosuda.REngine.REXPMismatchException;; public class Temp { public static void main(String[] args) throws REXPMismatchException { // TODO Auto-generated method stub RConnection connection = null; System.out.println("平均值"); try { //创建对象 connection = new RConnection(); String vetor="c(1,2,3,4)"; connection.eval("meanVal<-mean("+vetor+")"); //System.out.println("the mean of given vector is="+mean); double mean=connection.eval("meanVal").asDouble(); System.out.println("the mean of given vector is="+mean); //connection.eval(arg0) } catch (RserveException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("执行脚本"); try { connection.eval("source('D:/myAdd.R')");
//此处路径也可以这样写D:\\\\myAdd.R int num1=20; int num2=10; int sum=connection.eval("myAdd("+num1+","+num2+")").asInteger(); System.out.println("the sum="+sum); } catch (RserveException e) { // TODO Auto-generated catch block e.printStackTrace(); } connection.close(); } }


结果为:

平均值
the mean of given vector is=2.5
执行脚本
the sum=30


其中myAdd.R代码如下:


myAdd<-function(x,y){ sum=x+y return(sum) }


四.Reserve的多线程


由于Rserve是以服务器的形式运行,那么它可以同时处理多个请求。 这也就意味着当我们使用命令启动Rserve的实例。

我们从R控制台启动Rserve实例,如下有三个实例。


Rserve(port=5011) Rserve(port=5012) Rserve(port=5013)


现在有了这3个独立的实例,这3个线程可以很容易地连接到这3个实例:

//线程1连接到在端口5011上运行的实例 RConnection connection = new RConnection("hostIP_or_hostName",5011); //线程2连接到在端口5012上运行的实例 RConnection connection = new RConnection("hostIP_or_hostName",5012); //线程3连接到在端口5013上运行的实例 RConnection connection = new RConnection("hostIP_or_hostName",5013);


第二种方法:

      

这是一种比较简单方便的方法,这次我们需要写一个简单的R语言脚本,然后通过运行这个R脚本,来打开Rserve服务。这样的话,我们每次运行Java程序之前就不用先打开R,再输入程序打开Rserve服务。这样是不是很简单方便。今天我们要用这种方法,和R语言,画一个简单的词云出来。


首先,我们建一个R脚本:


library(Rserve) Rserve()</span>


我将它保存成Rserve.R文件,放在了这个目录下(MyScript这是我自己新建的文件夹):    D:\Program Files\R\R-3.3.1\MyScript

提示:路径最后不要有中文字符,就是有的时候可能不识别,或包其他错误


首先我们要导入  包,大家可以查看我的另一篇博文。我们新建一个类,用来初始化Rserve服务。代码如下:


package rserve; import javax.xml.transform.Source; import org.rosuda.REngine.Rserve.RConnection; import org.rosuda.REngine.Rserve.RserveException; /** * 启动Rserve服务 * @author henry wang * */ public class Rservel { private static String R_EXE_PATH="D:\\Program Files\\R\\R-3.3.1\\bin\\Rscript.exe"; private static String R_SCRIPT_PATH="D:\\Program Files\\R\\R-3.3.1\\MyScript\\Rserve.R"; public static RConnection getRConnection(){ try { RConnection rConnection=new RConnection(); return rConnection; } catch (RserveException e) { // TODO: handle exception System.out.println("正在启动Rserve服务......"); try { Runtime rn=Runtime.getRuntime(); /* * 不建议写成直接写成rn.exec("R_EXE_PATH R_SCRIPT_PATH"),
*如果这样学的画前面定义的R_EXE_PATH,R_SCRIPT_PATH会提示 * 这两个变量没有用到 * 运行也许会出错,提示错误如下: * java.io.IOException: Cannot run program "D:\Program": CreateProcess error=2,
*系统找不到指定的文件。 */ String[] commandArgs={R_EXE_PATH,R_SCRIPT_PATH}; rn.exec(commandArgs); Thread.sleep(5000); } catch (Exception e2) { // TODO: handle exception e2.printStackTrace(); } return getRConnection(); } } }


说明:R_EXE_PATH 是Rscript.exe或者R.exe的路径,这两个都可以。R_SCRIPT_PATH是R脚本的路径。


package rserve; import java.awt.Graphics; import java.awt.Image; import java.awt.MediaTracker; import java.awt.Toolkit; import javax.swing.JFrame; import org.rosuda.REngine.REXP; import org.rosuda.REngine.Rserve.RConnection; public class WordCloud extends JFrame{ private static final long serialVersionUID=1L; static Image img; public static void main(String[] args) throws Exception{ // TODO Auto-generated method stub WordCloud wc=new WordCloud(); REXP xp=wc.getRobj();//获得R对象 wc.PlotDemo(xp,wc);//错误 } private REXP getRobj() throws Exception{ RConnection c=Rserve.getRConnection(); c.setStringEncoding("utf8");//设置字符编码 //返回R的版本 REXP Rservesion=c.eval("R.version.string"); System.out.println(Rservesion.asString()); System.out.println("\n----------绘图演示--------"); System.out.println(""); REXP xp=c.parseAndEval("jpeg('test.jpg',quality=90)"); c.eval("library(wordcloud)"); c.voidEval("colors=c('red','blue','green','yellow','purple')"); c.parseAndEval(" data(SOTU);wordcloud(SOTU,min.freq=10,colors=colors);dev.off()"); xp=c.parseAndEval("r=readBin('test.jpg','raw',3000*3000);unlink('test.jpg');r"); return xp; } public void PlotDemo(REXP xp, JFrame f)throws Exception{ img=Toolkit.getDefaultToolkit().createImage(xp.asBytes()); MediaTracker mediaTracker=new MediaTracker(this); mediaTracker.addImage(img, 0); mediaTracker.waitForID(0); f.setTitle("Test Image"); f.setSize(img.getWidth(null),img.getHeight(null)); f.setDefaultCloseOperation(EXIT_ON_CLOSE); f.setVisible(true); } public void paint(Graphics g){ g.drawImage(img, 0, 0, null); } }


c.parseAndEval(" data(SOTU);wordcloud(SOTU,min.freq=10,colors=colors);dev.off()");

这个句子的冒号里面都是一些R语句,只不过每句话后面都有一个分号。


运行结果如下:




这样就好了,我们使用java调用R语言就绘制出了一个简单的词云。如果大家还有什么问题可以在留言区留言讨论。

号外:

5月23日张丹老师在Hellobi Live直播授课,只要19.99喔。数据老手教你如何用R语言开始量化投资

参加方式:扫码参团 | 阅读原文


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存