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.
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_valuecasting behaves inconsistently. For instance (see example code) for a string ("<U1") input array, the inputfill_valuecannot generally be cast to int. However an exception is raised only iffill_valueis explicitly accessed or set and, oddly enough, not for scalar arrays.Reproduce the code example:
Error message:
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.vectorizein conjunction with masked arrays. In its current status,fill_valuecasting cannot be relied upon (e.g. the defaultintfill value can be cast tofloat/strworks but not vice versa). To me it would make sense not to try casting the input arrayfill_valueto the dtypes inotypesbut rather using thenp.ma.default_fill_value. Moreover, it would be very practical if the vectorized function could skip masked values all together, setting the result(s) tonp.ma.masked, but this is a separate issue.