如何在Numpy中创建数组的带有掩码值的直方图?

17
在Numpy 1.4.1中,计算一个掩码数组的直方图最简单或最有效的方法是什么?默认情况下,numpy.histogrampyplot.hist会统计掩码元素的数量!我目前能想到的唯一简单解决方案涉及创建一个新数组,该数组包含非掩码值:
histogram(m_arr[~m_arr.mask])

这种方法效率不太高,因为它不必要地创建了一个新的数组。我很乐意阅读更好的想法!


2
说句实话,在numpy.histogram中这可能被认为是一个bug。你应该提交一个bug报告并在邮件列表中提到它。通过在numpy.histogram源代码中将asarray替换为asanyarray,可以轻松解决这个问题。 - Joe Kington
3
我向列表发送了一个快速问题。 http://mail.scipy.org/pipermail/numpy-discussion/2010-September/052575.html 我们将看看人们是否认为这是一个 bug。至少对我来说,这似乎是违反直觉的。 - Joe Kington
2
就这个问题而言,普遍共识是这是预期行为,并且这样的修复可能会引起更多问题而不是解决问题。例如:http://mail.scipy.org/pipermail/numpy-discussion/2010-September/052578.html - Joe Kington
谢谢,乔。你能把你的评论总结成一个答案吗?我想将其标记为被接受的答案,因为它表明没有比tillsten的好解决方案更好的了。 - Eric O. Lebigot
@Denis - 对我来说,这似乎是个合理的想法……如果你愿意,随时可以开始!请记住,在处理掩码数组和NaN时,“misbehave”可能会有点主观。无论哪种方式,很多默认行为都可能与直觉相悖,在我看来。 - Joe Kington
显示剩余3条评论
4个回答

16

(根据以上讨论,恢复此内容...)

我不确定numpy开发人员是否认为这是一个bug还是期望的行为。我在邮件列表中进行了询问,所以我们将看到他们的回答。

无论如何,这是一个很容易解决的问题。在修补numpy/lib/function_base.py时,将输入函数的数组改用numpy.asanyarray而不是numpy.asarray,就可以使其正确地使用掩码数组(或任何ndarray的子类),而不创建副本。

编辑:看起来这是期望的行为。 就像这里讨论的那样

  

如果要忽略掩码数据,就只需要多加一个函数调用

     

histogram(m_arr.compressed())

     

我认为这会额外复制一份不会有影响,   因为我猜在直方图内部处理完整的掩码数组会更昂贵。

     

使用asanyarray也允许   矩阵和其他可能无法正确处理的子类型   直方图计算。

     

除了放弃掩码观测之外,如果要进行其他任何操作,则需要弄清楚直方图的掩码数组定义,如Bruce所指出的那样。


谢谢。反对在直方图中处理掩码数组的一个论点是,如果直方图处理掩码值,那么就必须决定如何处理带有掩码权重的掩码数据。我认为这个问题没有明显更好的解决方案:看起来histogram()的特性与掩码输入+权重数组不太搭配。 - Eric O. Lebigot

9
尝试使用hist(m_arr.compressed())

1
这个想法比我的 m_arr[~m_arr.mask] 更好。然而,它并没有解决不必要地创建新数组的问题。 - Eric O. Lebigot

6

这是一个非常老的问题,但现在我只使用:

numpy.histogram(m_arr, bins=.., range=.., density=False, weights=m_arr_mask)

m_arr_mask是一个与m_arr形状相同的数组,由0值组成,用于从直方图中排除m_arr的元素,并且由1值组成,用于包含要包括的元素。


此外,如果您尝试将字符串传递给“bins”,则无法正常工作。除此之外,这是一个很好的答案。 - Mad Physicist
我似乎无法使其正常工作。当我传递一个权重的掩码数组时,结果似乎与没有掩码的结果不一致。 我尝试传递一个随机0和1值的掩码,并期望每个箱中的计数被大约2除以。但实际上它被除以超过20。 - PiRK
请查看 https://filebin.net/jp4x16ekgiyuupgu/Untitled.html?t=2w07ir8v 的内容。 - PiRK
我对更简单的例子(数组更小)可以正常工作。看起来是 numpy 的一个 bug,可能是因为权重导致 numpy.histogram 使用 uint8 数组作为输出,从而导致了溢出。 - PiRK

0

在尝试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)的图像上:

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接