JuliaPy / PyCall.jl

Package to call Python functions from the Julia language
MIT License
1.45k stars 186 forks source link

Handling None -> Missing conversions in matrices #1009

Open fipelle opened 1 year ago

fipelle commented 1 year ago

Hi,

I have noticed that trying to convert a numpy array containing None to a Matrix{Union{Missing, Float64}} does not work smoothly. Indeed, it gives the following error: TypeError('must be real number, not NoneType').

Have you ever encountered this issue before? Are there any working solutions?

fipelle commented 1 year ago

I have written down the following workaround:

"""
    ndarray_to_matrix(X::Matrix{PyCall.PyObject})

Converts `X` into a Matrix{Union{Missing, Float64}} handling `None` appropriately.

    ndarray_to_matrix(X::Matrix{Float64})

Converts `X` into a Matrix{Union{Missing, Float64}} for internal consistency.
"""
function ndarray_to_matrix(X::Matrix{PyCall.PyObject})
    out = zeros(size(X)) |> Matrix{Union{Missing, Float64}};
    for j in axes(out, 2), i in axes(out, 1)
        try
            out[i,j] = convert(Float64, X[i,j]);
        catch e
            if "$(e.val)" == "PyObject TypeError('must be real number, not NoneType')"
                out[i,j] = missing;
            else
                throw(e);
            end
        end
    end

    return out;
end

ndarray_to_matrix(X::Matrix{Float64}) = convert(Matrix{Union{Missing, Float64}}, X);

Not sure if there are better ways to handle this issue.

stevengj commented 1 year ago

I thought numpy arrays don't have a missing value? Can you give an example of what you have on the Python side?

fipelle commented 1 year ago

Yes, of course. I am writing a wrapper for a public package (happy to pass along the references if it may help). I have attached a short screenshot to highlight what's happening on the Python side.

python