RProvider icon indicating copy to clipboard operation
RProvider copied to clipboard

Suggest some Extension methods to allow fluent-style accessing R objects

Open renkun-ken opened this issue 11 years ago • 3 comments

RDotNet provides SymbolicExpression object to get access to R objects. Most R objects are constructed as Lists.

For example, a t-test result is a list of statistics and other things, a linear model (lm) is a list of coefficients, residuals and other useful list members. However, it is quite inconvenient to extract the members from a list without chaining several methods and convert the value to appropriate types.

In some packages, the R functions returns S4 object. For example, fUnitRoots package provides a unitrootTest function which returns S4 object that stores much richer information than offered by official R stats packages. But it's a nightmare to extract wanted information from these Lists or the slots of S4 objects. R methods package provide slot() function to extract slots from S4 objects.

As a user of C# and F#, I just want to conveniently get access to the inner information of the R objects without caring too much about the nature of the R object.

Here I developed a very rough RDotNet.Extensions project using F# and RProvider to extend SymbolicExpression:

module RDotNet.Extensions

open RDotNet
open RDotNet.Internals
open RProvider
open RProvider.``base``
open RProvider.methods

type SymbolicExpression with
    /// Get the member symbolic expression of List or S4 object.
    member this.Member (name: string) =
        match this.Type with
        | SymbolicExpressionType.List -> this.AsList().[name]
        | SymbolicExpressionType.S4 -> R.slot(this,name)
        | _ -> invalidOp "Unsupported operation on R object"

    /// Convert the symbolic expression to a typed array.
    member this.ToArray<'a> () = this.Value :?> 'a[]

    /// Get the value from the typed vector by name.
    member this.ValueOf<'a> (name: string) =
        match this.Type with
        | SymbolicExpressionType.NumericVector -> box(this.AsNumeric().[name]) :?> 'a
        | SymbolicExpressionType.CharacterVector -> box(this.AsCharacter().[name]) :?> 'a
        | SymbolicExpressionType.LogicalVector -> box(this.AsLogical().[name]) :?> 'a
        | SymbolicExpressionType.IntegerVector -> box(this.AsInteger().[name]) :?> 'a
        | SymbolicExpressionType.ComplexVector -> box(this.AsComplex().[name]) :?> 'a
        | SymbolicExpressionType.RawVector -> box(this.AsRaw().[name]) :?> 'a
        | _ -> invalidOp "Unsupported operation on R object"

    /// Get the value from the typed vector by index.
    member this.ValueAt<'a> (index: int) = box(this.ToArray<'a>().[index]) :?> 'a

    /// Get the first value from the typed vector.
    member this.First<'a> () = this.ValueAt<'a>(0)

    /// Assign this symbolic expression to a string symbolic identifier in current R environment.
    member this.AssignTo(name:string) = R.assign(name,this) |> ignore

This extension currently allows me to write code in a fluent style like this:

    let dic = dict [("ma",R.c(0.6,0.4,0.1).Value)]
    let list = R.list(dic)
    let data1 = R.arima_sim(model=list,n=500)
    let model = R.arima(x=data1,order=R.c(0,0,5))
    let coef:double[] = model.Member("coef").ToArray()
    let data = R.rnorm(1000)
    let test = R.unitrootTest(data)
    let pvalue:double = test.Member("test").Member("p.value").ValueOf("n") // test is S4 object

I suggest that RDotNet or RProvider adopt some extensions to allow such fluent-style of accessing the data members of R objects. This issue is raised in RDotNet community, I hope RProvider can also do something about it.

renkun-ken avatar Oct 24 '13 13:10 renkun-ken

I think the Member extension could probably be a dynamic operator, so that you can write:

test?test?p_value

There is also an issue for better support for S3/S4 values: https://github.com/BlueMountainCapital/FSharpRProvider/issues/8

Generally speaking, I think these are all useful extensions. Would you be able to submit a pull request with these?

tpetricek avatar May 21 '14 21:05 tpetricek

Seems like a dup of #63.

hmansell avatar May 21 '14 21:05 hmansell

Yes, closing this one.

tpetricek avatar May 21 '14 21:05 tpetricek