Intégration Java-R

1. Vue d'ensemble

R est un langage de programmation populaire utilisé pour les statistiques. Comme il dispose d'une grande variété de fonctions et de packages disponibles, il n'est pas rare d'incorporer du code R dans d'autres langues.

Dans cet article, nous examinerons certaines des méthodes les plus courantes d'intégration de code R dans Java.

2. Script R

Pour notre projet, nous allons commencer par implémenter une fonction R très simple qui prend un vecteur en entrée et renvoie la moyenne de ses valeurs. Nous définirons cela dans un fichier dédié:

customMean <- function(vector) { mean(vector) }

Tout au long de ce didacticiel, nous utiliserons une méthode d'assistance Java pour lire ce fichier et renvoyer son contenu sous forme de chaîne :

String getMeanScriptContent() throws IOException, URISyntaxException { URI rScriptUri = RUtils.class.getClassLoader().getResource("script.R").toURI(); Path inputScript = Paths.get(rScriptUri); return Files.lines(inputScript).collect(Collectors.joining()); }

Voyons maintenant les différentes options dont nous disposons pour appeler cette fonction depuis Java.

3. RCaller

La première bibliothèque que nous allons considérer est RCaller qui peut exécuter du code en engendrant un processus R dédié sur la machine locale.

Puisque RCaller est disponible depuis Maven Central, nous pouvons simplement l'inclure dans notre pom.xml :

 com.github.jbytecode RCaller 3.0 

Ensuite, écrivons une méthode personnalisée qui renvoie la moyenne de nos valeurs en utilisant notre script R original:

public double mean(int[] values) throws IOException, URISyntaxException { String fileContent = RUtils.getMeanScriptContent(); RCode code = RCode.create(); code.addRCode(fileContent); code.addIntArray("input", values); code.addRCode("result <- customMean(input)"); RCaller caller = RCaller.create(code, RCallerOptions.create()); caller.runAndReturnResult("result"); return caller.getParser().getAsDoubleArray("result")[0]; }

Dans cette méthode, nous utilisons principalement deux objets:

  • RCode , qui représente notre contexte de code, y compris notre fonction, son entrée et une instruction d'appel
  • RCaller , qui nous permet d'exécuter notre code et de récupérer le résultat

Il est important de noter que RCaller n'est pas adapté aux calculs petits et fréquents en raison du temps nécessaire pour démarrer le processus R. Ceci est un inconvénient notable.

En outre, RCaller fonctionne uniquement avec R installé sur la machine locale .

4. Renjin

Renjin est une autre solution populaire disponible sur le paysage d'intégration R. Il est plus largement adopté et offre également une assistance aux entreprises .

Ajouter Renjin à notre projet est un peu moins trivial puisque nous devons ajouter le référentiel bedatadriven avec la dépendance Maven:

  bedatadriven bedatadriven public repo //nexus.bedatadriven.com/content/groups/public/     org.renjin renjin-script-engine RELEASE  

Encore une fois, construisons un wrapper Java pour notre fonction R:

public double mean(int[] values) throws IOException, URISyntaxException, ScriptException { RenjinScriptEngine engine = new RenjinScriptEngine(); String meanScriptContent = RUtils.getMeanScriptContent(); engine.put("input", values); engine.eval(meanScriptContent); DoubleArrayVector result = (DoubleArrayVector) engine.eval("customMean(input)"); return result.asReal(); }

Comme nous pouvons le voir, le concept est très similaire à RCaller, bien qu'il soit moins verbeux , car nous pouvons appeler des fonctions directement par nom en utilisant la méthode eval .

Le principal avantage de Renjin est qu'il ne nécessite pas d'installation R car il utilise un interpréteur basé sur JVM. Cependant, Renjin n'est actuellement pas compatible à 100% avec GNU R.

5. Réserver

Les bibliothèques que nous avons examinées jusqu'à présent sont de bons choix pour exécuter du code localement. Mais que se passe-t-il si nous voulons que plusieurs clients invoquent notre script R? C'est là que Rserve entre en jeu, nous permettant d'exécuter du code R sur une machine distante via un serveur TCP .

La configuration de Rserve implique l'installation du package associé et le démarrage du serveur en chargeant notre script, via la console R:

> install.packages("Rserve") ... > library("Rserve") > Rserve(args = "--RS-source ~/script.R") Starting Rserve...

Ensuite, nous pouvons maintenant inclure Rserve dans notre projet en ajoutant, comme d'habitude, la dépendance Maven:

 org.rosuda.REngine Rserve 1.8.1 

Enfin, enveloppons notre script R dans une méthode Java. Ici, nous allons utiliser un objet RConnection avec notre adresse de serveur, par défaut à 127.0.0.1:6311 s'il n'est pas fourni:

public double mean(int[] values) throws REngineException, REXPMismatchException { RConnection c = new RConnection(); c.assign("input", values); return c.eval("customMean(input)").asDouble(); }

6. FastR

La dernière bibliothèque dont nous allons parler est FastR. une implémentation R haute performance basée sur GraalVM. Au moment d'écrire ces lignes , FastR n'est disponible que sur les systèmes Linux et Darwin x64 .

Pour l'utiliser, nous devons d'abord installer GraalVM à partir du site officiel. Après cela, nous devons installer FastR lui-même à l'aide du Graal Component Updater, puis exécuter le script de configuration qui l'accompagne:

$ bin/gu install R ... $ languages/R/bin/configure_fastr

Cette fois, notre code dépendra de Polyglot, l'API interne de GraalVM pour l'intégration de différents langages invités dans Java. Puisque Polyglot est une API générale, nous spécifions la langue du code que nous voulons exécuter. De plus, nous utiliserons la fonction c R pour convertir notre entrée en vecteur:

public double mean(int[] values) { Context polyglot = Context.newBuilder().allowAllAccess(true).build(); String meanScriptContent = RUtils.getMeanScriptContent(); polyglot.eval("R", meanScriptContent); Value rBindings = polyglot.getBindings("R"); Value rInput = rBindings.getMember("c").execute(values); return rBindings.getMember("customMean").execute(rInput).asDouble(); }

Lorsque vous suivez cette approche, gardez à l'esprit que cela rend notre code étroitement couplé avec la JVM . Pour en savoir plus sur GraalVM, consultez notre article sur le compilateur Graal Java JIT.

7. Conclusion

Dans cet article, nous avons passé en revue certaines des technologies les plus populaires pour intégrer R dans Java. Pour résumer:

  • RCaller est plus facile à intégrer puisqu'il est disponible sur Maven Central
  • Renjin offre un support d'entreprise et ne nécessite pas que R soit installé sur la machine locale, mais il n'est pas 100% compatible avec GNU R
  • Rserve peut être utilisé pour exécuter du code R sur un serveur distant
  • FastR permet une intégration transparente avec Java mais rend notre code dépendant de la VM et n'est pas disponible pour tous les systèmes d'exploitation

Comme toujours, tout le code utilisé dans ce didacticiel est disponible à l'adresse over sur GitHub.