web-dev-qa-db-ja.com

javaからRスクリプトを呼び出す

JavaからRスクリプトを呼び出したいのですが。私はトピックについてグーグル検索をしました、しかし私が見たほとんどすべての結果は私がいくつかのサードパーティのライブラリに依存関係を追加することを要求するでしょう。コードに依存関係を追加せずに同じことを達成するための良い方法を誰かに教えてもらえますか?

私はWindowsマシンを使用しているため、コマンドラインを使用してRを起動し(まだ開いていない場合)、特定のRスクリプトを実行する可能性があります。しかし、コマンドラインコードを記述したことがない(またはJavaから呼び出した)ため、コード例が必要になります。

コマンドラインのアイデアを使用して、以下の1つの可能なアプローチのために作成した実用的なサンプルコードを含めています。以下の私のインラインコメントでは、AssembleDataFile.JavaのStep Threeが意図的に空白になっていることがわかります。コマンドラインのアイデアを機能させることができると思われる場合は、ステップ3でどのコードを記述するかを教えてください。

また、うまくいけば、私のコードにこれ以上の依存関係を追加することを含まない別のアプローチを提案してください。

そして、いつものように、この質問に関連する記事/チュートリアル/その他にあなたが投稿するかもしれないリンクを非常に感謝しています。

ここに私がこれまでに持っているものがあります:

AssembleDataFile.Java

import Java.io.BufferedReader;
import Java.io.FileNotFoundException;
import Java.io.FileReader;
import Java.io.IOException;
import Java.io.PrintWriter;

public class AssembleDataFile {
static String delimiter;
static String localPath = "C:\\test\\cr\\";
static String[][] myDataArray;

public static void main(String[] args) {
    String inputPath = localPath+"pd\\";
    String fileName = "MSData.txt";
    delimiter = "\\t";

    // Step One: Import data in two parts
    try {
        // 1A: get length of data file
        BufferedReader br1 = new BufferedReader(new FileReader(inputPath+fileName));
        int numRows = 0;
        int numCols = 0;
        String currentRow;
        while ((currentRow = br1.readLine()) != null) {
            numRows += 1;
            numCols = currentRow.split(delimiter).length;}
        br1.close();
        //1B: populate data into array
        myDataArray = new String[numRows][numCols+1];
        BufferedReader br2 = new BufferedReader(new FileReader(inputPath+fileName));
        String eachRow;
        int rowIdx = 0;
        while ((eachRow = br2.readLine()) != null) {
            String[] splitRow = eachRow.split(delimiter);
            for(int z = 0;z < splitRow.length;z++){myDataArray[rowIdx][z] = splitRow[z];}
            rowIdx += 1;}
        br2.close();

        // Step Two: Write data to csv
        String rPath = localPath+"r\\";
        String sFileName = rPath+"2colData.csv";
        PrintWriter outputWriter = new PrintWriter(sFileName);
        for(int q = 0;q < myDataArray.length; q++){
            outputWriter.println(myDataArray[q][8]+", "+myDataArray[q][9]);
        }
        outputWriter.close();

        //Step Three: Call R script named My_R_Script.R that uses 2ColData.csv as input
        // not sure how to write this code.  Can anyone help me write this part?
        // For what it is worth, one of the R scripts that I intend to call is included below
        //
        //added the following lines here, per Vincent's suggestion:
            String rScriptFileName = rPath+"My_R_Script.R";
        Runtime.getRuntime().exec("mypathto\\R\\bin\\Rscript "+rScriptFileName);
        //
        //

        //Step Four: Import data from R and put it into myDataArray's empty last column
        try {Thread.sleep(30000);}//make this thread sleep for 30 seconds while R creates the needed file
        catch (InterruptedException e) {e.printStackTrace();}
        String matchFileName = rPath+"Matches.csv";
        BufferedReader br3 = new BufferedReader(new FileReader(matchFileName));
        String thisRow;
        int rowIndex = 0;
        while ((thisRow = br3.readLine()) != null) {
            String[] splitRow = thisRow.split(delimiter);
            myDataArray[rowIndex][numCols] = splitRow[0];
            rowIndex += 1;}
        br3.close();

        //Step Five: Check work by printing out one row from myDataArray
        //Note that the printout has one more column than the input file had.
        for(int u = 0;u<=numCols;u++){System.out.println(String.valueOf(myDataArray[1][u]));}
    }
    catch (FileNotFoundException e) {e.printStackTrace();}
    catch (IOException ie){ie.printStackTrace();}
}
}

My_R_Script.R

myCSV <- read.csv(file="2colData.csv",head=TRUE,sep=",")  
pts = SpatialPoints(myCSV)
Codes = readShapeSpatial("mypath/myshapefile.shp")  
write.csv(ZipCodes$F[overlay(pts,Codes)], "Matches.csv", quote=FALSE, row.names=FALSE)

編集:
Runtime.getRuntime()。exec( "Rscript" + rScriptFileName);を追加したときにスローされるエラーメッセージを次に示します。上記のコードに:

Java.io.IOException: Cannot run program "Rscript": CreateProcess error=2, The system cannot find the file specified
at Java.lang.ProcessBuilder.start(Unknown Source)
at Java.lang.Runtime.exec(Unknown Source)
at Java.lang.Runtime.exec(Unknown Source)
at Java.lang.Runtime.exec(Unknown Source)
at AssembleDataFile.main(AssembleDataFile.Java:52)
Caused by: Java.io.IOException: CreateProcess error=2, The system cannot find the file specified
at Java.lang.ProcessImpl.create(Native Method)
at Java.lang.ProcessImpl.<init>(Unknown Source)
at Java.lang.ProcessImpl.start(Unknown Source)
... 5 more    

2番目の編集:上記のコードは、Vincentの提案に従っているため機能します。ただし、Rスクリプトを実行するのに十分な時間を与えるために、sleepコマンドを入力する必要がありました。スリープコマンドがないと、上記のJavaコードは、Matches.csvファイルが存在しないことを示すエラーをスローします。30秒のスリープ期間では、測定器が粗すぎることが心配です。- JavaプログラムがMatches.csvを作成する機会を得るまで待つプログラムを取得するコードを誰かに見せてもらえますか?スレッドツールの使用をためらっています。設計が不十分なスレッドは、ローカライズと修正がほぼ不可能であるバグを引き起こす可能性があることを読んだためです。

18
CodeMed

外部アプリケーションを呼び出したいだけです。次の作業はうまくいきませんか?

Runtime.getRuntime().exec("Rscript myScript.R"); 
18

このコードは簡単に適応できます: http://svn.rforge.net/org/trunk/rosuda/REngine/Rserve/test/StartRserve.Java

とりわけ、Rを見つけてRで固定スクリプトを実行します。そのスクリプトを自分のスクリプトに置き換えて、最後の2つの方法を無視できます。

5
Simon Urbanek

プロセスがThread.sleep()...で完了するのを待たないでください。

代わりにwaitFor()メソッドを使用してください。

Process child = Runtime.getRuntime().exec(command, environments, dataDir);

int code = child.waitFor();

switch (code) {
    case 0:
        //normal termination, everything is fine
        break;
    case 1:
        //Read the error stream then
        String message = IOUtils.toString(child.getErrorStream());
        throw new RExecutionException(message);
}
5
Vasily
BufferedReader reader = null;
        Process Shell = null;
        try {
            Shell = Runtime.getRuntime().exec(new String[] { "/usr/bin/Rscript", "/media/subin/works/subzworks/RLanguage/config/predict.R" });

            reader = new BufferedReader(new InputStreamReader(Shell.getInputStream()));
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);

            }

        } catch (IOException e) {
            e.printStackTrace();
        }
2
amicos

...サードパーティのライブラリに依存関係を追加する必要があります...

なぜそんなに悪いのですか? 「...野球バットでハニーバジャーを攻撃する必要があります...」のように聞こえますが、特にそれが機能する場合、害はありません。

たぶん RCaller が役に立ちます。 JNIは必要ありません。

1
duffymo