JuliaInterop / RCall.jl

Call R from Julia
Other
317 stars 59 forks source link

Extract object from R string #258

Closed DominiqueMakowski closed 6 years ago

DominiqueMakowski commented 6 years ago
R"""
df <- iris
fit <- lm(Sepal.Length ~ Sepal.Width, data=df)
result <- summary(fit)
"""

I would like to retrieve the result object to use it in julia? Is is possible? In general, how do you extract objects from the R string?

dmbates commented 6 years ago

The value returned from that expression is not a string, it is an R list which becomes a RObject{VecSxp} in Julia. The printed value you see is actually the result of the print method in R.

You can retrieve the numerical values in Julia with rcopy.

julia> rcopy(R"result")
DataStructures.OrderedDict{Symbol,Any} with 11 entries:
  :call          => :(lm(formula = (Sepal.Length ~ Sepal.Width), data = df))
  :terms         => Formula: Sepal.Length ~ Sepal.Width
  :residuals     => [-0.644459, -0.956139, -1.11147, -1.2338, -0.722123, -0.255114, -1.16679, -0.766795, -1.47848, -0.933803  …  0.866197, 1.0662, -0.123148,…
  :coefficients  => [6.52622 0.478896 13.6276 6.4697e-28; -0.223361 0.155081 -1.44029 0.151898]
  :aliased       => Bool[false, false]
  :sigma         => 0.825097
  :df            => [2, 148, 2]
  :r_squared     => 0.0138227
  :adj_r_squared => 0.00715929
  :fstatistic    => [2.07443, 1.0, 148.0]
  :cov_unscaled  => [0.336879 -0.108007; -0.108007 0.035327]
DominiqueMakowski commented 6 years ago

Awesome thanks.

However, just to let you know, it seems that rcopy doesn't work for lme4's summary:

R"""
library(lme4)
df <- iris
fit <- lme4::lmer(Sepal.Length ~ Sepal.Width + (1|Species), data=df)
result <- summary(fit)
"""
rcopy(R"result")
MethodError: no method matching -(::Nothing, ::Int64)
Closest candidates are:
  -(!Matched::Complex{Bool}, ::Real) at complex.jl:298
  -(!Matched::Missing, ::Number) at missing.jl:93
  -(!Matched::Base.CoreLogging.LogLevel, ::Integer) at logging.jl:107
  ...
try_yieldto(::typeof(Base.ensure_rescheduled), ::Base.RefValue{Task}) at event.jl:196
wait() at event.jl:255
wait(::Condition) at event.jl:46
_wait(::Task) at task.jl:189
fetch at task.jl:205 [inlined]
macro expansion at dynamic.jl:67 [inlined]
(::getfield(Atom, Symbol("##107#112")))(::Dict{String,Any}) at eval.jl:82
handlemsg(::Dict{String,Any}, ::Dict{String,Any}) at comm.jl:168
(::getfield(Atom, Symbol("##14#17")){Array{Any,1}})() at task.jl:262
randy3k commented 6 years ago

@DominiqueMakowski

It seems that there is a missing conversion rule, 18c2ef6 has fixed it. With that said, RCall doesn't convert S4 object to any julia types because there is such correspondence. (Maybe we could use Vector{Any}!?)

With the new fix and your example code, I got

julia> rcopy(R"result")
DataStructures.OrderedDict{Symbol,Any} with 18 entries:
  :methTitle    => "Linear mixed model fit by REML"
  :objClass     => "lmerMod"
  :devcomp      => DataStructures.OrderedDict{Symbol,Any}(:cmp=>Union{Missing, …
  :isLmer       => true
  :useScale     => true
  :logLik       => -97.3181
  :family       => nothing
  :link         => nothing
  :ngrps        => 3.0
  :coefficients => [3.40617 0.668308 5.0967; 0.797154 0.106206 7.50571]
  :sigma        => 0.437958
  :vcov         => RObject{S4Sxp}…
  :varcor       => DataStructures.OrderedDict{Symbol,Any}(:Species=>1.01976)
  :AICtab       => 194.636
  :call         => :((lme4 :: lmer)(formula = Formula: Sepal.Length ~ Sepal.Wid…
  :residuals    => [0.0738871, 0.527303, -0.293394, -0.33971, -0.336461, 0.0308…
  :fitMsgs      => String[]
  :optinfo      => DataStructures.OrderedDict{Symbol,Any}(:optimizer=>"bobyqa",…

I also worth mentioning that you could convert specific members of the result, eg., rcopy(R"result$logLik")

DominiqueMakowski commented 6 years ago

Awesome thanks a lot!