1

Using SymPy in Julia, how can I transform the example input

feature_names = ["1", "x", "y", "z", "x^2", "x y", "x z", "y^2", "y z", "z^2"]

into a callable method f(x, y, z) which returns the evaluation of the expressions like

julia >>> f(1, 2, 3)
julia >>> 10-element Vector{float64}:
          [1, 1, 2, 3, 1, 2, 3, 4, 6, 9]
Felix
  • 83
  • 9

2 Answers2

2

In Julia you could do something like this:

using SymPy
@vars x y z

feature_names = [1, x, y, z, x^2, x*y, x*z, y^2, y*z, z^2]

f(a,b,c) = feature_names.evalf(subs=Dict(x=>a,y=>b,z=>c)) |> N |> vec

f(1,2,3) # [1.0,1.0,2.0,...]

or, more in general,:

solveMultipleSympyFunctions(values,sympy_symbols,expressions) = expressions.evalf(subs=Dict(zip(sympy_symbols,values))) |> N |> vec

solveMultipleSympyFunctions([1,2,3],[x,y,z],feature_names)

The N(.) function is to retrieve a numerical output instead of a number that is still a symbol, and vec() is to transform the output, that is in matrix form, to a vector as in your request. Finally, |> is the pipe operator (just for convenience instead of writing vec(N(...)))

EDIT:

I did try several ways to start the expressions from a vector of strings, but none of the above works:

feature_names_string = ["1", "x", "y", "z", "x^2", "x*y", "x*z", "y^2", "y*z", "z^2"]
feature_names = symbols.(feature_names_string)
feature_names = symbols.(Symbol.(feature_names_string))
feature_names = sympy.Function.(feature_names_string)
feature_names = convert.(Sym,sympy.Function.(feature_names_string))
feature_names = Sym(feature_names_string)
feature_names = Sym.(feature_names_string)
feature_names = Sym.(sympy.Function.(feature_names_string))
feature_names = sympy.Function.(Sym.(feature_names_string))
Antonello
  • 6,092
  • 3
  • 31
  • 56
  • Thank you for your answer! Great suggestion. One question: Is there a way to get from the list of strings `feature_names` to the list of expressions in your code procedurally? – Felix Oct 05 '21 at 13:54
  • 1
    @Felix: I edited the answer, but no.. unfortunatly I has been unable to find a way. You can write in the [SymPy.jl](https://github.com/JuliaPy/SymPy.jl) issue tracker or in https://discourse.julialang.org to try to get more qualified answers... – Antonello Oct 05 '21 at 15:34
  • Thanks for editing. Thanks also for the hint of filing an issue. One last question: Is it possible to get each individual entry of `feature_names` "translated" into expressions? I was thinking of something like `feature = "x y"` into `f(x,y,z)`. Then one courd iterate through the list. – Felix Oct 05 '21 at 16:06
2

It isn't quite what you are asking, as expressions like "x y" don't work with sympify, so I had to add * as needed, but using sympify and free_symbols allows this to be automated:

feature_names = ["1", "x", "y", "z", "x^2", "x*y", "x*z", "y^2", "y*z", "z^2"]

using SymPy
function F(feature_names)

    xs = sympy.sympify.(feature_names)
    vars = free_symbols(xs)
    function(as...)
        subs.(xs, (vars .=> as)...)
    end
end

λ = F(feature_names)
λ(1,2,3)

The ordering of the variables in the lamda is determined calling sortperm on the stringified symbols, as that is how free_symbols orders things.

jverzani
  • 5,600
  • 2
  • 21
  • 17