Me gustaría llamar a un script R desde Java. He realizado búsquedas en Google sobre el tema, pero casi todos los resultados que he visto me obligarían a agregar una dependencia a una biblioteca de terceros. ¿Alguien puede mostrarme una buena manera de lograr lo mismo sin agregar dependencias a mi código?llamando al script R desde java
Estoy usando una máquina de Windows, así que tal vez podría usar la línea de comando para iniciar R (si no está ya abierta) y ejecutar un script R específico. Pero nunca he escrito el código de línea de comando (o lo llamé desde Java), así que necesitaría ejemplos de código.
Estoy incluyendo el código de muestra de trabajo que escribí para un posible enfoque a continuación, utilizando mi idea de línea de comando. En mis comentarios en línea a continuación, puede ver que Paso tres en AssembleDataFile.java fue dejado en blanco intencionalmente por mí. Si crees que puedes hacer que la idea de línea de comando funcione, entonces muéstrame qué código escribir en el Paso Tres.
Además, siéntase libre de sugerir otro enfoque que, afortunadamente, no implique agregar más dependencias a mi código.
Y, como siempre, agradezco mucho cualquier enlace que pueda publicar en artículos/tutoriales/etc. relacionados con esta pregunta.
Esto es lo que tengo hasta ahora:
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)
EDIT:
Aquí está el mensaje de error que se lanza cuando agrego Runtime.getRuntime(). Exec ("Rscript" + rScriptFileName); para el código anterior:
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
SEGUNDA EDICIÓN: El código anterior funciona ahora porque he seguido las sugerencias de Vincent. Sin embargo, tuve que poner un comando de suspensión para darle al guión R tiempo suficiente para ejecutar. Sin el comando de suspensión, el código de Java anterior arroja un error que dice que el archivo Matches.csv no existe. Me preocupa que un período de sueño de 30 segundos sea demasiado duro para un instrumento. ¿Alguien puede mostrarme el código que hace que el programa java espere hasta que el programa R tenga la oportunidad de crear Matches.csv? Dudo en utilizar las herramientas de subprocesos porque he leído que los subprocesos mal diseñados pueden causar errores que son casi imposibles de localizar y corregir.
cuanto a la espera para el trabajo a fin: Usted puede ver el ID de terminación del proceso. También puede simplemente sondear la existencia (o inexistencia) de algún archivo creado especialmente. – Iterator