Skip to content

BUG: inconsistent fill_value casting for masked arrays #27165

Description

@rgbmrc

Describe the issue:

When a vectorized function acts on a masked array, its result is masked as well. However, when the dtype of the result is different from that of the input, fill_value casting behaves inconsistently. For instance (see example code) for a string ("<U1") input array, the input fill_value cannot generally be cast to int. However an exception is raised only if fill_value is explicitly accessed or set and, oddly enough, not for scalar arrays.

Reproduce the code example:

import numpy as np

f = np.vectorize(lambda c: ord(c) if c else -1, otypes=[int])

a = np.ma.masked_all(1, str)
x = f(a)  # ok
x = a.fill_value
x = f(a)  # raises TypeError: Cannot convert fill_value N/A to dtype int64

a = np.ma.masked_array([""], True)
x = f(a)  # ok
x = a.fill_value
x = f(a)  # raises TypeError: Cannot convert fill_value N/A to dtype int64
a = np.ma.masked_array([""], True, fill_value="?")
x = f(a)  # raises TypeError: Cannot convert fill_value ? to dtype int64

a = np.ma.masked_array("", True)
x = f(a)  # ok
x = a.fill_value
x = f(a)  # ok
a = np.ma.masked_array("", True, fill_value="?")
x = f(a)  # ok

Error message:

Traceback (most recent call last):
  File ".../lib/python3.12/site-packages/numpy/ma/core.py", line 489, in _check_fill_value
    fill_value = np.asarray(fill_value, dtype=ndtype)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: invalid literal for int() with base 10: 'N/A'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File ".../lib/python3.12/site-packages/numpy/lib/_function_base_impl.py", line 2397, in __call__
    return self._call_as_normal(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../lib/python3.12/site-packages/numpy/lib/_function_base_impl.py", line 2390, in _call_as_normal
    return self._vectorize_call(func=func, args=vargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../lib/python3.12/site-packages/numpy/lib/_function_base_impl.py", line 2483, in _vectorize_call
    res = asanyarray(outputs, dtype=otypes[0])
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../lib/python3.12/site-packages/numpy/ma/core.py", line 3092, in __array_finalize__
    self._fill_value = _check_fill_value(self._fill_value, self.dtype)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../lib/python3.12/site-packages/numpy/ma/core.py", line 495, in _check_fill_value
    raise TypeError(err_msg % (fill_value, ndtype)) from e
TypeError: Cannot convert fill_value N/A to dtype int64

Python and NumPy Versions:

numpy: 2.0.1
python: 3.12.5 | packaged by conda-forge | (main, Aug 8 2024, 18:36:51) [GCC 12.4.0]

Runtime Environment:

No response

Context for the issue:

I stumbled upon this while testing np.vectorize in conjunction with masked arrays. In its current status, fill_value casting cannot be relied upon (e.g. the default int fill value can be cast to float/str works but not vice versa). To me it would make sense not to try casting the input array fill_value to the dtypes in otypes but rather using the np.ma.default_fill_value. Moreover, it would be very practical if the vectorized function could skip masked values all together, setting the result(s) to np.ma.masked, but this is a separate issue.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions