numpy.histogram
和pyplot.hist
会统计掩码元素的数量!我目前能想到的唯一简单解决方案涉及创建一个新数组,该数组包含非掩码值:histogram(m_arr[~m_arr.mask])
这种方法效率不太高,因为它不必要地创建了一个新的数组。我很乐意阅读更好的想法!
(根据以上讨论,恢复此内容...)
我不确定numpy开发人员是否认为这是一个bug还是期望的行为。我在邮件列表中进行了询问,所以我们将看到他们的回答。
无论如何,这是一个很容易解决的问题。在修补numpy/lib/function_base.py
时,将输入函数的数组改用numpy.asanyarray
而不是numpy.asarray
,就可以使其正确地使用掩码数组(或任何ndarray的子类),而不创建副本。
编辑:看起来这是期望的行为。 就像这里讨论的那样:
如果要忽略掩码数据,就只需要多加一个函数调用
histogram(m_arr.compressed())
我认为这会额外复制一份不会有影响, 因为我猜在直方图内部处理完整的掩码数组会更昂贵。
使用asanyarray也允许 矩阵和其他可能无法正确处理的子类型 直方图计算。
除了放弃掩码观测之外,如果要进行其他任何操作,则需要弄清楚直方图的掩码数组定义,如Bruce所指出的那样。
histogram()
的特性与掩码输入+权重数组不太搭配。 - Eric O. Lebigothist(m_arr.compressed())
。m_arr[~m_arr.mask]
更好。然而,它并没有解决不必要地创建新数组的问题。 - Eric O. Lebigot这是一个非常老的问题,但现在我只使用:
numpy.histogram(m_arr, bins=.., range=.., density=False, weights=m_arr_mask)
m_arr_mask是一个与m_arr形状相同的数组,由0值组成,用于从直方图中排除m_arr的元素,并且由1值组成,用于包含要包括的元素。
在尝试Erik的解决方案(请参见https://github.com/numpy/numpy/issues/16616)时遇到了转换问题,我决定编写一个numba函数来实现这个行为。
其中一些代码受到了https://numba.pydata.org/numba-examples/examples/density_estimation/histogram/results.html的启发。我添加了mask
位。
import numpy
import numba
@numba.jit(nopython=True)
def compute_bin(x, bin_edges):
# assuming uniform bins for now
n = bin_edges.shape[0] - 1
a_min = bin_edges[0]
a_max = bin_edges[-1]
# special case to mirror NumPy behavior for last bin
if x == a_max:
return n - 1 # a_max always in last bin
bin = int(n * (x - a_min) / (a_max - a_min))
if bin < 0 or bin >= n:
return None
else:
return bin
@numba.jit(nopython=True)
def masked_histogram(img, bin_edges, mask):
hist = numpy.zeros(len(bin_edges) - 1, dtype=numpy.intp)
for i, value in enumerate(img.flat):
if mask.flat[i]:
bin = compute_bin(value, bin_edges)
if bin is not None:
hist[int(bin)] += 1
return hist # , bin_edges
速度提升显著。在一张(1000,1000)的图像上:
numpy.histogram
中这可能被认为是一个bug。你应该提交一个bug报告并在邮件列表中提到它。通过在numpy.histogram
源代码中将asarray
替换为asanyarray
,可以轻松解决这个问题。 - Joe Kington