我该如何在一个掩码数组上运行numpy函数percentile()?

13
我尝试从一个包含NoData值的数组中获取百分位数。在我的情况下,NoData值由-3.40282347e+38表示。我以为掩码数组会把这些值排除在进一步计算之外。我成功地创建了掩码数组,但是在np.percentile()函数中,掩码没有效果。
>>> DataArray = np.array(data)
>>> DataArray

([[ value, value...]], dtype=float32)

>>> masked_data = ma.masked_where(DataArray < 0, DataArray)
>>> p5 = np.percentile(masked_data, 5)
>>> print p5

 -3.40282347e+38

1
最好使用掩码方法或np.ma函数。许多np函数委托给这些方法,但不要指望它。 - hpaulj
2个回答

13

如果您将掩码值填充为np.nan,则可以使用np.nanpercentile

import numpy as np
data = np.arange(-5.5,10.5) # Note that you need a non-integer array to store NaN
mdata = np.ma.masked_where(data < 0, data)
mdata = np.ma.filled(mdata, np.nan)
np.nanpercentile(mdata, 50) # 50th percentile

1
这肯定是一个方便的解决方案(例如,它允许在特定的“轴”上应用百分位数,而仅仅调用mdata.compressed()则不行),但我担心它很昂贵。 - Paul Price

10

np.percentile 的代码很明显它对掩码数组没有特殊处理。

def percentile(a, q, axis=None, out=None,
               overwrite_input=False, interpolation='linear', keepdims=False):
    q = array(q, dtype=np.float64, copy=True)
    r, k = _ureduce(a, func=_percentile, q=q, axis=axis, out=out,
                    overwrite_input=overwrite_input,
                    interpolation=interpolation)
    if keepdims:
        if q.ndim == 0:
            return r.reshape(k)
        else:
            return r.reshape([len(q)] + k)
    else:
        return r

_ureduce_percentile 是定义在 numpy/lib/function_base.py 中的内部函数。因此实际操作更加复杂。

掩码数组有两种使用 numpy 函数的策略。一种是使用 fill - 用无害的值替换掩码值,例如在进行求和时用0,进行乘积时用1。另一种是compress数据——也就是删除所有的掩码值。

例如:

In [997]: data=np.arange(-5,10)
In [998]: mdata=np.ma.masked_where(data<0,data)

In [1001]: np.ma.filled(mdata,0)
Out[1001]: array([0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

In [1002]: np.ma.filled(mdata,1)
Out[1002]: array([1, 1, 1, 1, 1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

In [1008]: mdata.compressed()
Out[1008]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

填充还是压缩会使你得到期望的百分位数呢?还是不用?你需要充分理解百分位数的概念,以便知道如何在掩码值的情况下应用它。


Compressed() 对我很有帮助。因为在百分位数计算之前,我需要完全排除 NoData 值。 - EikeMike

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