Passing NAs from R to a Julia function using JuliaCall

Viewed 115

I am trying to write a Julia function (weighted_sum in this example) and use it in R.

The function works well in Julia (first code block below), but fails to work with NAs when called from R using the JuliaCall package (second block of code below).

Is there a way around this problem? E.g. Could I modify the Array type somehow in the R version of the function (within JuliaCall::julia_eval()) so that it accepts R's NAs?

Julia code:

function weighted_sum(v::Vector, w::Vector, skipmissing::Bool)
    if skipmissing
        v = v[findall(!ismissing, v)]
        w = w[findall(!ismissing, v)]
    end
    return sum(v .* w)
end

println(weighted_sum([1, 2, 3, 1], [1, 2, 2, 1], true))
#> 12
println(weighted_sum([1, 2, 3, missing], [1, 2, 2, 1], true))
#> 11

R code:

library(JuliaCall)

julia_weighted_sum_function <- JuliaCall::julia_eval("function weighted_sum(v::Vector, w::Vector, skipmissing::Bool)
    if skipmissing
        v = v[findall(!ismissing, v)]
        w = w[findall(!ismissing, v)]
    end
    return sum(v .* w)
end")
#> Julia version 1.5.0 at location C:\Users\{path_to_julia}\julia\V15~1.0\bin will be used.
#> Loading setup script for JuliaCall...
#> Finish loading setup script for JuliaCall.

weighted_sum_jl <- function(x, weights, epsilon, na.rm = TRUE){
  
  JuliaCall::julia_call("weighted_sum", x, weights, na.rm)
  
}

weighted_sum_jl(x = c(1, 2, 3, 1), w = c(1, 2, 2, 1), TRUE)
#> [1] 12


weighted_sum_jl(x = c(1, 2, 3, NA), w = c(1, 2, 2, 1), TRUE)
#> Error: Error happens in Julia.
#> MethodError: no method matching weighted_sum(::Base.ReshapedArray{Union{Missing, Float64},1,Array{Union{Missing, Float64},1},Tuple{}}, ::Array{Float64,1}, ::Bool)
#> Closest candidates are:
#>   weighted_sum(!Matched::Array{T,1} where T, ::Array{T,1} where T, ::Bool) at none:1
#> Stacktrace:
#>  [1] docall(::Ptr{Nothing}) at C:\Users\{path_to_R}\R\win-library\4.0\JuliaCall\julia\setup.jl:176

Created on 2021-09-05 by the reprex package (v2.0.1)

Session info
sessioninfo::session_info()
#> - Session info ---------------------------------------------------------------
#>  setting  value                       
#>  version  R version 4.0.5 (2021-03-31)
#>  os       Windows 10 x64              
#>  system   x86_64, mingw32             
#>  ui       RTerm                       
#>  language (EN)                        
#>  collate  English_United Kingdom.1252 
#>  ctype    English_United Kingdom.1252 
#>  tz       Europe/Berlin               
#>  date     2021-09-05                  
#> 
#> - Packages -------------------------------------------------------------------
#>  package     * version date       lib source        
#>  cli           2.4.0   2021-04-05 [1] CRAN (R 4.0.5)
#>  digest        0.6.27  2020-10-24 [1] CRAN (R 4.0.5)
#>  evaluate      0.14    2019-05-28 [1] CRAN (R 4.0.5)
#>  fs            1.5.0   2020-07-31 [1] CRAN (R 4.0.5)
#>  glue          1.4.2   2020-08-27 [1] CRAN (R 4.0.5)
#>  highr         0.8     2019-03-20 [1] CRAN (R 4.0.5)
#>  htmltools     0.5.1.1 2021-01-22 [1] CRAN (R 4.0.5)
#>  JuliaCall   * 0.17.4  2021-05-16 [1] CRAN (R 4.0.5)
#>  knitr         1.32    2021-04-14 [1] CRAN (R 4.0.5)
#>  magrittr      2.0.1   2020-11-17 [1] CRAN (R 4.0.5)
#>  ps            1.6.0   2021-02-28 [1] CRAN (R 4.0.5)
#>  Rcpp          1.0.7   2021-07-07 [1] CRAN (R 4.0.5)
#>  reprex        2.0.1   2021-08-05 [1] CRAN (R 4.0.5)
#>  rlang         0.4.10  2020-12-30 [1] CRAN (R 4.0.5)
#>  rmarkdown     2.7     2021-02-19 [1] CRAN (R 4.0.5)
#>  rstudioapi    0.13    2020-11-12 [1] CRAN (R 4.0.5)
#>  sessioninfo   1.1.1   2018-11-05 [1] CRAN (R 4.0.5)
#>  stringi       1.5.3   2020-09-09 [1] CRAN (R 4.0.3)
#>  stringr       1.4.0   2019-02-10 [1] CRAN (R 4.0.5)
#>  withr         2.4.1   2021-01-26 [1] CRAN (R 4.0.5)
#>  xfun          0.22    2021-03-11 [1] CRAN (R 4.0.5)
#>  yaml          2.2.1   2020-02-01 [1] CRAN (R 4.0.4)
3 Answers

According to this, the missing in julia is kind of a generalization of the missing values in other languages. It is not clear why the NA from R is having a problem. Tried changing to NaN as input and it works by using isnan

library(JuliaCall)
julia_weighted_sum_function <- JuliaCall::julia_eval("function weighted_sum(v::Vector, w::Vector, skipmissing::Bool)
    
    if skipmissing
        v = v[findall(!isnan, v)]
        v = v[findall(!ismissing, v)]
        w = w[findall(!ismissing, v)]
    end
    return sum(v .* w)
end")
weighted_sum_jl <- function(x, weights, epsilon, na.rm = TRUE){
  
  JuliaCall::julia_call("weighted_sum", x, weights, na.rm)
  
}

-testing

> weighted_sum_jl(x = c(1, 2, 3, 1), w = c(1, 2, 2, 1), TRUE)
[1] 12
> weighted_sum_jl(x = c(1, 2, 3, NaN), w = c(1, 2, 2, 1), TRUE)
[1] 11

The function seems to work well if the type of v is not declared when defining the function.

library(tidyverse)
library(JuliaCall)

julia_weighted_sum_function <- JuliaCall::julia_eval("function weighted_sum(v, w, skipmissing::Bool)
    if skipmissing
        v = v[findall(!ismissing, v)]
        w = w[findall(!ismissing, v)]
    end
    return sum(v .* w)

end")
#> Julia version 1.5.0 at location C:\Users\{path_to_julia}\julia\V15~1.0\bin will be used.
#> Loading setup script for JuliaCall...
#> Finish loading setup script for JuliaCall.

weighted_sum_jl <- function(x, weights, na.rm = TRUE){
  
  JuliaCall::julia_call("weighted_sum", x, weights, na.rm)
  
}

weighted_sum_jl(x = c(1, 2, 3, 1), w = c(1, 2, 2, 1), TRUE)
#> [1] 12


weighted_sum_jl(x = c(1, 2, 3, NA), w = c(1, 2, 2, 1), TRUE)
#> [1] 11

Created on 2021-09-07 by the reprex package (v2.0.1)

Have you tried using x::AbstractVector instead of ::Vector? The error message indicates that a ReshapedArray is passed by JuliaCall, so you need a wider than than Vector.

Related