2012-01-13 114 views
12

我想從Java調用R腳本。我已經完成了關於該主題的谷歌搜索,但幾乎所有我看到的結果都需要我爲某些第三方庫添加依賴關係。任何人都可以告訴我一個很好的方法來完成同樣的事情,而不需要添加任何依賴到我的代碼?從java調用R腳本

我正在使用Windows機器,所以也許我可以使用命令行啓動R(如果它尚未打開)並運行特定的R腳本。但是我從來沒有寫過命令行代碼(或者從Java調用它),所以我需要代碼示例。

我正在使用我的命令行思路包括我爲下面的一種可能方法編寫的工作示例代碼。在下面的我的在線評論中,您可以看到第三步在AssembleDataFile.java中被我故意留空。如果你認爲你可以使命令行的想法起作用,那麼請告訴我在第三步寫什麼代碼。

此外,隨意提出另一種方法,希望不會增加任何更多的依賴關係到我的代碼。

和往常一樣,我非常感謝您可能發佈到與此問題相關的文章/教程/等的任何鏈接。

這是我到目前爲止有:

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  

第二個編輯: 上面的代碼現在的作品,因爲我跟文森特的建議。但是,爲了讓R腳本有足夠的時間運行,我必須輸入睡眠命令。如果沒有sleep命令,上面的java代碼會拋出一個錯誤,指出Matches.csv文件不存在。我擔心30秒的睡眠時間對於樂器來說太粗糙了。 任何人都可以讓我看看java程序等待R程序有機會創建Matches.csv的代碼嗎?我不願意使用線程工具,因爲我已經讀過設計不佳的線程會導致幾乎不可能進行本地化和修復的錯誤。

+2

關於等待作業結束:你可以看的進程ID終止。您也可以輪詢一些特殊創建的文件的存在(或不存在)。 – Iterator 2012-01-13 23:35:53

回答

14

你只是想調用一個外部應用程序:不會有以下工作?

Runtime.getRuntime().exec("Rscript myScript.R"); 
+1

非常感謝您的幫助。 +1給我一個有針對性的想法。我運行了你的代碼,並且它拋出了一個錯誤信息,我在上面發佈的一篇文章中發佈了一條錯誤消息。我還將您的代碼添加到了上面我原始帖子的代碼部分,以便您可以看到我做了什麼。也許我的理解不正確。你能告訴我如何修復我的代碼,以便它在上面工作? – CodeMed 2012-01-13 02:43:03

+1

您可能需要Rscript可執行文件的完整路徑。 – 2012-01-13 02:53:10

+0

我有myScript.R的完整路徑,我在發佈錯誤消息之前檢查確認。你的意思是R的完整路徑嗎? – CodeMed 2012-01-13 03:10:30

1

...需要我的依賴增加了一些第三方庫...

這是爲什麼這麼差?你聽起來像「......要我用棒球棒攻擊蜜蜂......」我沒有看到傷害,尤其是如果它有效的話。

也許RCaller可以幫助你。不需要JNI。

+0

雖然這個鏈接可能回答這個問題,但最好在這裏包含答案的重要部分,並提供供參考的鏈接。如果鏈接頁面更改,則僅鏈接答案可能會失效。 – durron597 2015-08-19 19:26:13

+0

對不起,但下面的一個也包含鏈接。那下面的那個也是。你爲什麼給我發表評論? – duffymo 2015-08-19 19:42:46

+0

我沒有單身你,因爲這個答案出現在LQP審查隊列中。我也沒有讓你失望。 – durron597 2015-08-19 19:46:29

5

您可以輕鬆地適應這個代碼:http://svn.rforge.net/org/trunk/rosuda/REngine/Rserve/test/StartRserve.java

在其他方面找到R和運行R中一個固定的腳本 - 你可以用你的腳本替換該腳本,並忽略最後兩個方法。

+0

感謝您的建議,並對文森特的建議發表評論。上面的建議涉及到爲我的代碼添加另一個依賴項。我更感興趣的是你在文森特的建議中寫的評論。再次感謝你。 – CodeMed 2012-01-13 21:44:43

+1

這不是依賴關係 - 上面的代碼顯示瞭如何在Windows上獲取R的位置以及如何在任何地方運行R - 這只是實際的代碼,正如我在評論中描述的那樣。它與Rserve本身無關,只是它是示例的一部分 - 這就是爲什麼我告訴你忽略與Rserve有關的最後一種方法 - 這不是這個答案的含義。用您自己的R代碼替換「庫(Rserve)」。 – 2012-01-13 23:49:37

+0

謝謝澄清。 +2多嘗試幫助。當我下一步工作時,我會明天更多地檢查你的代碼。 – CodeMed 2012-01-14 05:39:04

4

不要等待的過程與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); 
      } 
2
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(); 
     } 
+0

我目前無法驗證這一點。但是+1需要花時間爲這個老問題增加見解。 – CodeMed 2015-10-08 15:42:16

+0

這並不適用於我,但將'exec'的參數從'String []'的參數更改爲格式爲'C:/ Program Files/path/to/the/Rscript.exe C://something.R'完成了任務。 – Antoine 2016-01-28 10:25:40