MaskedArray
является подклассом базы numpy ndarray
. У него нет собственного скомпилированного кода. Подробности смотрите в каталоге numpy/ma/
или в главном файле:
/usr/local/lib/python3.6/dist-packages/numpy/ma/core.py
Маскированный массив имеет ключевые атрибуты, data
и mask
, один из них - массив данных, который вы использовали для его создания. другой логический массив того же размера.
Таким образом, все операции должны учитывать эти два массива. Он не только вычисляет новый data
, но также должен вычислять новый mask
.
. Может потребоваться несколько подходов (в зависимости от операции):
использовать data
как есть
использовать сжатый data
- новый массив с удаленными маскированными значениями
использовать заполненный data
, где замаскированные значения заменены fillvalue
или некоторым безобидным значением (например, 0 при выполнении сложения, 1 при выполнении умножения).
Количество маскируемых значений, 0 или все, мало что делает, если есть, разница в скорости.
Так что разница в скорости, которую вы видите, не удивительна. Там много дополнительных вычислений происходит. В файле ma.core.py
говорится, что этот пакет был впервые разработан за 10 * 10 дней и включен в numpy
около 2005 года. Несмотря на то, что были внесены изменения, чтобы поддерживать его в актуальном состоянии, я не думаю, что он был существенно переработан .
Вот код для np.ma.max
метода:
def max(self, axis=None, out=None, fill_value=None, keepdims=np._NoValue):
kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
_mask = self._mask
newmask = _check_mask_axis(_mask, axis, **kwargs)
if fill_value is None:
fill_value = maximum_fill_value(self)
# No explicit output
if out is None:
result = self.filled(fill_value).max(
axis=axis, out=out, **kwargs).view(type(self))
if result.ndim:
# Set the mask
result.__setmask__(newmask)
# Get rid of Infs
if newmask.ndim:
np.copyto(result, result.fill_value, where=newmask)
elif newmask:
result = masked
return result
# Explicit output
....
Ключевые шаги:
fill_value = maximum_fill_value(self) # depends on dtype
self.filled(fill_value).max(
axis=axis, out=out, **kwargs).view(type(self))
Вы можете поэкспериментировать с filled
, чтобы увидеть, что происходит с ваш массив.
In [40]: arr = np.arange(10.)
In [41]: arr
Out[41]: array([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])
In [42]: Marr = np.ma.masked_array(arr, mask=[0]*9 + [1])
In [43]: Marr
Out[43]:
masked_array(data=[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, --],
mask=[False, False, False, False, False, False, False, False,
False, True],
fill_value=1e+20)
In [44]: np.ma.maximum_fill_value(Marr)
Out[44]: -inf
In [45]: Marr.filled()
Out[45]:
array([0.e+00, 1.e+00, 2.e+00, 3.e+00, 4.e+00, 5.e+00, 6.e+00, 7.e+00,
8.e+00, 1.e+20])
In [46]: Marr.filled(_44)
Out[46]: array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., -inf])
In [47]: arr.max()
Out[47]: 9.0
In [48]: Marr.max()
Out[48]: 8.0