天天看點

Java調用R與Python

1 為什麼我們要Java調用Python或R

Java是一門面向對象程式設計語言,不僅吸收了C++語言的各種優點,還摒棄了C++裡難以了解的多繼承、指針等概念,是以Java語言具有功能強大和簡單易用兩個特征。Java語言作為靜态面向對象程式設計語言的代表,極好地實作了面向對象理論,允許程式員以優雅的思維方式進行複雜的程式設計 。Java具有簡單性、面向對象、分布式、健壯性、安全性、平台獨立與可移植性、多線程、動态性等特點。Java可以編寫桌面應用程式、Web應用程式、分布式系統和嵌入式系統應用程式等;Python和R在資料科學中有較高的地位,能夠快速的實作特征工程、資料挖掘的模組化。是以在生産中可能需要上線一些資料挖掘模型時,此時軟體工程師(往往不懂資料科學)使用的工具Java和資料分析師的Python或R會有交集。

模型的線上化部署的方式有很多,比如我們可以把訓練的模型轉預測模型标記語言(PMML),這樣Java就可以直接調用PMML;也可以做成REST API,Java通過API接口與模型進行互動,以上這些R與Python都有成熟的解決辦法;最直接的辦法莫過于代碼與代碼的對接(code2code),我們可以通過Java直接調用開發好的R模型或Python模型,完成訓練,評價和預測的目的,下面我們會依次展示一個Java調用Python代碼的例子和Java調用R的例子。

2.Java調用Python舉栗

首先我們知道Python和Java是可以互相調用的,而本節僅舉一個Java調用Python的栗子,Java調用Python的方式有很多,比如Jython(不過我不推薦大家使用,Jython版本更新緩慢,很多Python子產品并沒有包含,在調用的過程中會出現各種問題),我推薦大家使用指令行的方式調用Python代碼或腳本,其核心方法為:

Runtime.getRuntime().exec(args1);
           

注意這種方式隻能接收到python裡print的資料。是以如果你需要傳回值,可以把傳回值列印出來由Java接收就OK了,請後退,我要上代碼了:

首先我們要有一個Python腳本檔案,比如:

import sys
import pandas as pd
import numpy as np
import sklearn
import xgboost
import lightgbm
import tensorflow as tf
import keras

def my_test(str1,str2,str3,str4):
    return "Python函數運作:java調Python測試:"+str1+str2+str3+str4
    

if __name__=="__main__":
    print("腳本名:", sys.argv[0])

    my_arg = []
    for i in range(0, len(sys.argv)):
        my_arg.append(sys.argv[i])
    print("Java傳入的參數長度為:"+str(len(my_arg)))
    
    result = my_test(my_arg[1],my_arg[2],my_arg[3],my_arg[4])
    print(result)
           

其次我們構造一個J2py類用來調用上述Python腳本,并且實作Java資料與Python的互動(動态傳參的過程):

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;

/**
 * @title J2py.java
 * @author 作者:XuJing
 * @date 建立時間:2018年7月13日下午2:39:05
 * @version 1.0.0
 * @parameter 參數及其意義:
 * @return 傳回值:
 */

public class J2py {

    public static void main(String[] args) {
        // 需傳入的參數
        String a = "你好", b = "123", c = "徐靜", d = "qingdao";
        System.out.println("Java中動态參數已經初始化,準備傳參");
        // 設定指令行傳入參數
        String[] args1 = new String[] { "python","java\\03_project\\J2py\\src\\my_model.py", a,b, c, d }; 
        //Java資料a,b,c,d傳入Python
        Process pr;
        try {
            pr = Runtime.getRuntime().exec(args1); //最核心的函數

            BufferedReader in = new BufferedReader(new InputStreamReader(pr.getInputStream(), "gbk"));
            String line;
            List<String> lines = new ArrayList<String>();

            System.out.println("-----------------------------------------------");

            while ((line = in.readLine()) != null) {
                System.out.println(line);
                lines.add(line); //把Python的print值儲存了下來

            }
            System.out.println("-------------------------------------------------");

            in.close();

            pr.waitFor();
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("Java調Python結束");

    }

}
           

在Eclipse下運作的結果如下:

Java中動态參數已經初始化,準備傳參
-----------------------------------------------
腳本名: java\03_project\J2py\src\my_model.py
Java傳入的參數長度為:5
Python函數運作:java調Python測試:你好123徐靜qingdao
-------------------------------------------------
Java調Python結束
           

OK,成功了,虛線中間的部分就是我Python腳本實作的功能,并且我們實作了Java資料與Python代碼的參數傳遞。注意一點我在Python腳本中導入了部分我們常用到的子產品,這種方式Java并沒有報錯,也就意味着我們均可以通過Java調用這些子產品構造的模型,簡直是太棒了。

附:我的測試環境是Win7,Python3.6.4,JDK10.0.1,這裡需要說明的是我們也可以調用Python的虛拟環境,隻是把Python的代碼稍作修改就可以實作。

3.Java調用R舉栗

R與Java同樣可以進行互相調用,實際中很多R包都是由Java完成的,本節重點依然放在Java調用R代碼或腳本中,要注意的是Java調用R的方式也有很多,我們本節主要舉一個Java通過Rserve調用R代碼或腳本的例子,同時實作Python資料與R腳本的互動。翠花,上代碼:

首先我們要有一段R腳本,在現實中可能是你用R開發好的模型,等待上線:

library(tidyverse)
library(ggplot2)
library(mlr)
library(xgboost)
library(tensorflow)
library(keras)

getSum <- function(x,y){
  m <- x + y
  print("成功執行了該R函數")  
  return(m)
}
           

其次,我們構造一個J2r的Java類,用來調用上面的R腳本,并且實作資料互動和在Java中自動開啟Rserve:

import org.rosuda.REngine.REXP;
import org.rosuda.REngine.REXPMismatchException;
import org.rosuda.REngine.Rserve.RConnection;
import org.rosuda.REngine.Rserve.RserveException;

/**
 * @title J2r2.java
 * @author 作者:XuJing
 * @date 建立時間:2018年7月13日下午5:31:12
 * @version 1.0.0
 * @parameter 參數及其意義:
 * @return 傳回值:
 */

public class J2r2 {

    public static void main(String[] args) {

        System.out.println(StartRserve.checkLocalRserve());

        System.out.println("準備開始Java調用R");
        System.out.println("-----------------------------------------------");
         RConnection rConnection = null;

         try {
         rConnection = new RConnection();
         rConnection.eval("source('C:/test.R')");

         } catch (RserveException e) {
         e.printStackTrace();
         } // 檔案名不能帶中文,否則報錯:eval failed, request status: error code: 127
         int a = 2;
         int b = 3;
         int c = 4;
         int sum = 0;

         try {
         sum = rConnection.eval("getSum(" + a + "," + b + ")").asInteger();
         } catch (Exception e) {
         e.printStackTrace();
         }

         System.out.println("the sum = " + sum);
         rConnection.close();

        // 調用R代碼
         System.out.println("調用R代碼");

        RConnection rc = null;
        try {
            rc = new RConnection();
        } catch (RserveException e) {
            e.printStackTrace();
        }
        REXP x = null;
        try {
            x = rc.eval("library(xgboost);R.version.string");
        } catch (RserveException e) {
            e.printStackTrace();
        }
        try {
            System.out.println(x.asString());
        } catch (REXPMismatchException e) {
            e.printStackTrace();
        }
        rc.close();
        System.out.println("-----------------------------------------------");
        System.out.println("回到Java");

    }
}
           
準備開始Java調用R
-----------------------------------------------
the sum = 5
調用R代碼
R version 3.4.0 (2017-04-21)
-----------------------------------------------
回到Java
           

OK成功。java同時可以調用第三方的R包,執行R腳本傳參,并把資料傳回給Java,這裡要注意的是需要導入Rengine.jar和Rserve.jar兩個壓縮包,并且如果要實作Java中自動開啟Rserve需要在Rserve包中找到Rserve.java源檔案進行調用。

附:我的測試環境是Win7,R3.4.0,JDK10.0.1, 特别注意:不建議在Windows系統使用Rserve.

4.小結

通過以上兩種簡單方式我們就可以非常容易的通過Java調用R和Python封裝的資料挖掘模型。實際上這是一種最簡單直接的模型線上化部署的辦法,在生産中我們要基于硬體和系統要求選擇合理的模型線上化部署的辦法。同時也可以直接使用Java或C等底層的語言開發自己的模型,減少不同代碼間互相調用,提高模型的生産效率和運作速度。

原文釋出時間為:2018-07-17

本文作者: 徐靜

本文來自雲栖社群合作夥伴“

Python愛好者社群

”,了解相關資訊可以關注“