Logo RProvider

Working with R expressions

RProvider represents R objects and values through an RExpr type. RProvider includes an RExpr module that allows you to work with R expressions in a more idiomatic way using forward pipes (|>). First, open RProvider, its custom operators and any packages you need:

open RProvider
open RProvider.Operators

open RProvider.datasets
open RProvider.stats

Next, let's use a sample R dataframe to demonstrate core R expression functions.

let df = R.penguins

Note: in most cases, there are equivalent functions available using either the module (RExpr.*) or using dot notation as we preference below.

Inpecting a value

You may print the expression identically to using R print() using the .Print function or RExpr.printToString.

df.Print()

When using F# interactive (fsi), you may register a pretty-printer to print R values automatically into the terminal using fsi.AddPrinter FSIPrinters.rValue.

We can also inspect the 'semantic type' - the standard R shape - of the R expression. The possible shapes are listed in the Runtime.RTypes.RSemanticType discriminated union.

df.Type
DataFrameType

Similarly, you may retrieve the classes of an R object using the classes property.

df.Class
[|"data.frame"|]

Printing R values to the console (F# interactive)

Add this line to your script to tell F# interactive how to print out the values of R objects:

fsi.AddPrinter FSIPrinters.rValue

Extracting values (R -> F#)

We can extract a value from R memory space into to F# primitive values in two ways: type-specific or default type. For more information, see passing data.

For example, let's extract the bill length column from the penguin dataset using the RExpr directly (without using the semantic types layer). To access the column, we can use the ? operator; see operators for details.

let billLength = df?bill_len
let billVal = df?bill_len |> RExpr.getValue<float[]>

Extracting using the semantic R types layer

It is also possible to extract values through semantic types. Each semantic type has its own extraction functions specific to the type. For more information, see semantic R types.

Here, we can show how to extract a factor column using a type-safe pattern matching approach.

let speciesFactorSafe =
    match df?species.TryAsTyped with
    | Some t ->
        match t with
        | Runtime.RTypes.FactorInR f -> f.AsStringVector.Value
        | _ -> [||]
    | _ -> [||]

We can also do the same thing without try methods if we are certain of the type:

let speciesFactor = df?species.AsFactor().AsStringVector.Value
speciesFactor
[|"Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie";
  "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie";
  "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie";
  "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie";
  "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie";
  "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie";
  "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie";
  "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie";
  "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie";
  "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie";
  "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie";
  "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie"; "Adelie";
  "Adelie"; "Adelie"; "Adelie"; "Adelie"; ...|]

Note: Older RProvider versions contained a plugin system to register custom converters between .NET types and R types. This has been removed. The new preferred approach is to convert explicitly from semantic type wrappers. For example, an F# data frame library like Deedle could implement a custom conversion function from RProvider's DataFrame type.

Viewing as an R semantic type

A set of functions enable viewing an RExpr as RProvider's R semantic type wrappers.

Quick access to common properties

The RExpr type has members for quick access into common required fields or properties of R objects. These are mirrored in the RExpr, which are easier to call with forward pipes for example.

Vectors

You can quickly access a single value within a vector using .ValueAt and the index.

let v =  [ 0.1 .. 3.5 ] |> R.c

let y : Runtime.RTypes.RScalar<1> = v.ValueAt 0
y.AsReal().FromR.Value

let z : Runtime.RTypes.RScalar<1> = v |> RExpr.typedVectorByIndex 0
z.AsReal().FromR.Value

Lists and list-based objects

S3 objects in R are basic R objects, but with a class attribute attached. More often than not, they are lists.

There are multiple quick-access methods to list items:

let x = 10.
let summary = R.binom_test(x, 100., 0.5) // alternative = true

summary?``p.value``.FromR<float>()
summary?statistic.FromR<float>()

RExpr.listItem "p.value" summary

S4 objects (slots)

For this example, let's set up an S4 class and object from scratch:

R.parse(text = "setClass('testclass', representation(foo='character', bar='integer'))") |> R.eval
let s4 = R.parse(text = "new('testclass', foo='s4', bar=1:4)") |> R.eval
s4.Print()
"An object of class "testclass"
Slot "foo":
[1] "s4"

Slot "bar":
[1] 1 2 3 4

"

You can find out if there are slots using the slots and trySlots functions:

s4 |> RExpr.slots
R.mtcars |> RExpr.trySlots

You can access slot values similarly with the slot and trySlot functions:

s4 |> RExpr.slot "foo"
s4 |> RExpr.trySlot "foo"
s4 |> RExpr.trySlot "doesntexist"

Parallel processing

R itself is not thread-safe. Most R parallel processing libraries focus on running multiple R processes and coordinating work and values between them.

When using RProvider, you may use R from one or many threads. However, the underlying R engine being used is a single R instance. Internally, RBridge uses a concurrent queue to process incoming work. You will only gain the perception of multi-threading but none of the speed advantage when consuming R functions.

[| 1 .. 10 |]
|> Array.Parallel.map(fun i -> (R.sqrt i).AsScalar().AsReal().FromR.Value)
[|Some 1.0; Some 1.414213562; Some 1.732050808; Some 2.0; Some 2.236067977;
  Some 2.449489743; Some 2.645751311; Some 2.828427125; Some 3.0;
  Some 3.16227766|]
[| 1 .. 10 |]
|> Array.map(fun i -> (R.sqrt i).AsScalar().AsReal().FromR.Value)
[|Some 1.0; Some 1.414213562; Some 1.732050808; Some 2.0; Some 2.236067977;
  Some 2.449489743; Some 2.645751311; Some 2.828427125; Some 3.0;
  Some 3.16227766|]

As can be seen, the results are identical.

Important. Although pure functions return identical results, impure functions will not. The internal R instance is sharing it's environment, so you may cross contaminate.

namespace RProvider
module Operators from RProvider
<summary> Custom operators that make composing and working with R symbolic expressions easier. </summary>
namespace RProvider.datasets
namespace RProvider.stats
val df: Abstractions.RExpr
type R = static member AirPassengers: RExpr static member BJsales: RExpr static member BJsales_lead: RExpr static member BOD: RExpr static member CO2: RExpr static member ChickWeight: RExpr static member DNase: RExpr static member EuStockMarkets: RExpr static member Formaldehyde: RExpr static member HairEyeColor: RExpr ...
Base R datasets.
property R.penguins: Abstractions.RExpr with get
member Abstractions.RExpr.Print: unit -> string
property Abstractions.RExpr.Type: Runtime.RTypes.RSemanticType with get
property Abstractions.RExpr.Class: string array with get
val fsi: FSharp.Compiler.Interactive.InteractiveSession
member FSharp.Compiler.Interactive.InteractiveSession.AddPrinter: ('T -> string) -> unit
val billLength: Abstractions.RExpr
val billVal: float array
module RExpr from RProvider
<summary> Functions for working with R expressions. </summary>
val getValue<'a> : (Abstractions.RExpr -> 'a)
Multiple items
val float: value: 'T -> float (requires member op_Explicit)

--------------------
type float = System.Double

--------------------
type float<'Measure> = float
val speciesFactorSafe: string array
union case Option.Some: Value: 'T -> Option<'T>
val t: Runtime.RTypes.RSemantic<1>
namespace RProvider.Runtime
module RTypes from RProvider.Runtime
<summary> Types representing common R types, and functions for working with them. </summary>
union case Runtime.RTypes.RSemantic.FactorInR: Runtime.RTypes.Factor.RFactor -> Runtime.RTypes.RSemantic<'u>
val f: Runtime.RTypes.Factor.RFactor
property Runtime.RTypes.Factor.RFactor.AsStringVector: Lazy<string array> with get
property System.Lazy.Value: string array with get
val speciesFactor: string array
val v: Abstractions.RExpr
type R = static member ``!`` : ?paramArray: obj array -> RExpr + 2 overloads static member ``!=`` : ?paramArray: obj array -> RExpr + 2 overloads static member ``!_hexmode`` : ?a: obj -> RExpr + 2 overloads static member ``!_octmode`` : ?a: obj -> RExpr + 2 overloads static member ``$`` : ?paramArray: obj array -> RExpr + 2 overloads static member ``$<-`` : ?paramArray: obj array -> RExpr + 2 overloads static member ``$<-_POSIXlt`` : ?x: obj * ?name: obj * ?value: obj -> RExpr + 2 overloads static member ``$<-_data_frame`` : ?x: obj * ?name: obj * ?value: obj -> RExpr + 2 overloads static member ``$_DLLInfo`` : ?x: obj * ?name: obj -> RExpr + 2 overloads static member ``$_package__version`` : ?x: obj * ?name: obj -> RExpr + 2 overloads ...
Base R functions.
R.c(?paramArray: obj array) : Abstractions.RExpr
Combine Values into a Vector or List
val y: Runtime.RTypes.RScalar<1>
type RScalar<'u> = | NumericS of RRealScalar<'u> | IntegerS of RIntScalar<'u> | LogicalS of RScalarBase<bool> | CharacterS of RScalarBase<string> | ComplexS of RScalarBase<RComplex> | RawS of RExpr member AsCharacter: unit -> RScalarBase<string> member AsComplex: unit -> RScalarBase<RComplex> member AsInt: unit -> RIntScalar<'u> member AsLogical: unit -> RScalarBase<bool> member AsReal: unit -> RRealScalar<'u>
member Abstractions.RExpr.ValueAt: index: int -> Runtime.RTypes.RScalar<'u>
member Runtime.RTypes.RScalar.AsReal: unit -> Runtime.RTypes.Real.Scalar.RRealScalar<'u>
val z: Runtime.RTypes.RScalar<1>
val typedVectorByIndex: index: int -> expr: Abstractions.RExpr -> Runtime.RTypes.RScalar<'u>
val x: float
val summary: Abstractions.RExpr
type R = static member AIC: ?object: obj * ?k: obj * ?paramArray: obj array -> RExpr + 2 overloads static member ARMAacf: ?ar: obj * ?ma: obj * ?lag_max: obj * ?pacf: obj -> RExpr + 2 overloads static member ARMAtoMA: ?ar: obj * ?ma: obj * ?lag_max: obj -> RExpr + 2 overloads static member BIC: ?object: obj * ?paramArray: obj array -> RExpr + 2 overloads static member Box_test: ?x: obj * ?lag: obj * ?``type`` : obj * ?fitdf: obj -> RExpr + 2 overloads static member C: ?object: obj * ?contr: obj * ?how_many: obj * ?paramArray: obj array -> RExpr + 2 overloads static member D: ?expr: obj * ?name: obj -> RExpr + 2 overloads static member DF2formula: ?x: obj * ?env: obj -> RExpr + 2 overloads static member Gamma: ?link: obj -> RExpr + 2 overloads static member HoltWinters: ?x: obj * ?alpha: obj * ?beta: obj * ?gamma: obj * ?seasonal: obj * ?start_periods: obj * ?l_start: obj * ?b_start: obj * ?s_start: obj * ?optim_start: obj * ?optim_control: obj -> RExpr + 2 overloads ...
R statistical functions.
R.binom_test(paramsByName: List<string * obj>) : Abstractions.RExpr
Exact Binomial Test
R.binom_test(paramsByName: System.Collections.Generic.IDictionary<string,obj>) : Abstractions.RExpr
Exact Binomial Test
R.binom_test(?x: obj, ?n: obj, ?p: obj, ?alternative: obj, ?conf_level: obj) : Abstractions.RExpr
Exact Binomial Test
val listItem: name: string -> expr: Abstractions.RExpr -> Abstractions.RExpr
R.parse(paramsByName: List<string * obj>) : Abstractions.RExpr
Parse R Expressions
R.parse(paramsByName: System.Collections.Generic.IDictionary<string,obj>) : Abstractions.RExpr
Parse R Expressions
R.parse(?file: obj, ?n: obj, ?text: obj, ?prompt: obj, ?keep_source: obj, ?srcfile: obj, ?encoding: obj) : Abstractions.RExpr
Parse R Expressions
R.eval(paramsByName: List<string * obj>) : Abstractions.RExpr
Evaluate an (Unevaluated) Expression
R.eval(paramsByName: System.Collections.Generic.IDictionary<string,obj>) : Abstractions.RExpr
Evaluate an (Unevaluated) Expression
R.eval(?expr: obj, ?envir: obj, ?enclos: obj) : Abstractions.RExpr
Evaluate an (Unevaluated) Expression
val s4: Abstractions.RExpr
val slots: (Abstractions.RExpr -> Map<string,string>)
<summary> For an S4 object, get a dictionary containing first the slot name and second the slot's R type.</summary>
<param name="expr">An R symbolic expression</param>
<returns>A diictionary with key = slot name, and value = R type</returns>
property R.mtcars: Abstractions.RExpr with get
val trySlots: (Abstractions.RExpr -> Map<string,string> option)
<summary> For an S4 object, get a dictionary containing first the slot name and second the slot's R type. If the expression is not an S4 object, returns `None`.</summary>
<param name="expr">An R symbolic expression</param>
<returns>A diictionary with key = slot name, and value = R type</returns>
val slot: name: string -> expr: Abstractions.RExpr -> Abstractions.RExpr
<summary>Gets the value of a slot as a SymbolicExpression</summary>
<param name="name">Slot name to retrieve</param>
<param name="expr">An R symbolic expression</param>
<returns>A symbolic expression containing the slot value</returns>
val trySlot: name: string -> expr: Abstractions.RExpr -> Abstractions.RExpr option
<summary>Gets the value of a slot as a SymbolicExpression</summary>
<param name="name">Slot name to retrieve</param>
<param name="expr">An R symbolic expression</param>
<returns>Some symbolic expression if the expression was an S4 object and had the slot, or None otherwise.</returns>
module Array from Microsoft.FSharp.Collections
module Parallel from Microsoft.FSharp.Collections.ArrayModule
val map: mapping: ('T -> 'U) -> array: 'T array -> 'U array
val i: int
R.sqrt(paramsByName: List<string * obj>) : Abstractions.RExpr
No documentation available
R.sqrt(paramsByName: System.Collections.Generic.IDictionary<string,obj>) : Abstractions.RExpr
No documentation available
R.sqrt(?paramArray: obj array) : Abstractions.RExpr
No documentation available

Type something to start searching.