Wednesday, February 15, 2012

Calling R from Scala

My main programming language is still R. Incanter, while a nice attempt, is definitely not anywhere close to allowing Clojure to be a replacement for R. The JVM is not suitable for the numerical programming I do, and I find myself spending too much time trying to figure out how to change the code to speed it up.

Thus, as I've started learning Scala, I want to make sure I've got the backup of easy interoperability with R. That's basically what I did when I started learning Clojure. Here is my attempt to do the same thing in Scala. I'm still a beginner, so I won't claim to be able to write good Scala code yet.

My preference when using JVM languages is Eclipse. For Scala, there is an excellent IDE available. I followed the usual instructions to install it. (There is plenty of information on the internet, but it's basically pasting the link they provide into Eclipse, clicking some buttons, and restarting).

I switched to the Scala perspective, started a new Scala project, and added a new file under src. I then started typing. I was really impressed with the Scala IDE. It's still early in this adventure, but based on what I'd read, I was expecting it to be a piece of garbage. It was incredible for the small things I did with it. I especially like how it points out errors while you type. It's just a pleasure to use.

To access R, I downloaded the two jar files that are made available for Rserve. I use Linux, so I opened R in a terminal window, did "library(Rserve)", then "Rserve()".

Back in Eclipse, I right-clicked on the project name, went to "Build Path", then "Add External Archives...". I chose Rengine.jar and then RserveEngine.jar. Those names appeared under "Referenced Libraries" below the project name.

After a few small mistakes, this is the program I came up with. (It's released under the GPL version 2 or greater if you're wondering.)

object rs {
  import org.rosuda.REngine
  import org.rosuda.REngine.Rserve.RConnection
 
  def main(args: Array[String]) {
    val c = new RConnection
    val d = c.eval("rnorm(10)")
    val e = d.asDoubles
 
    for (i <- 0 until 10) {
        println(e(i))
    }
  }
}

Edit: Scala has a better way to print an array than the C-style for loop that I used. You can replace the for loop with  

println(e.deep.mkString("\n"))

I chose "Run" from the menu, followed by "Run" again. After a brief wait (presumably for compilation), I got the following output:

1.1357939434863817
0.45168475066687624
0.8312101791389808
-0.8825102796935446
0.9597726735219193
0.5916220359121344
-0.8979526251577276
0.2217958737969706
-0.013414880990143055
0.021108802828942192

That's it! Super easy. I called R from Scala, had R generate 10 random numbers, shipped those random numbers back to Scala, and printed them out. I can now do anything with "e" that I would do if I had created the random numbers in Scala.

The only drawback is all the syntax. I'm resigned to the fact that most programmers think syntax is good.

6 comments:

  1. Hi,

    Did you manage to call Scala methods from R?
    I tried to use rJava but didn't manage...

    Best,
    P

    ReplyDelete
  2. I tried it out and it worked like a charm, I am simplifying it further here.

    object rs {
    import org.rosuda.REngine
    import org.rosuda.REngine.Rserve.RConnection

    def main(args: Array[String]) {
    ((new RConnection).eval("rnorm(10)").asDoubles).map(println(_))
    }
    }

    ReplyDelete
  3. Doing a minor simplification further -

    object rs extends App {
    import org.rosuda._
    import org.rosuda.REngine.Rserve.RConnection
    override def main(args: Array[String]) = ((new RConnection).eval("rnorm(10)").asDoubles).map(println(_))
    }

    ReplyDelete
  4. Where do you specify the host & port to connect to Rserve ? (What if Rserve runs in another host ?).

    Thank you very much ! Nice post ;)

    ReplyDelete
  5. Amazing! This blog looks just likе my old one!

    Ιt's on a completely different topic but it has pretty much the same layout and design. Great choice of colors!

    My blog post: http://www.ares.com/

    ReplyDelete