python/numpy 对掩码数组(和/或选择性排名)进行二维内核排名过滤的最快方法

标签 python numpy scipy median

给定一个二维 numpy 数组

MyArray = np.array([[ 8.02,  9.54,  0.82,  7.56,  2.26,  9.47],
           [ 2.68,  7.3 ,  2.74,  3.03,  2.25,  8.84],
           [ 2.21,  3.62,  0.55,  2.94,  5.77,  0.21],
           [ 5.78,  5.72,  8.85,  0.24,  5.37,  9.9 ],
           [ 9.1 ,  7.21,  4.14,  9.95,  6.73,  6.08],
           [ 1.8 ,  5.14,  5.02,  6.52,  0.3 ,  6.11]])

和掩码数组

MyMask =  np.array([[ 0.,  0.,  1.,  1.,  0.,  1.],
            [ 1.,  0.,  0.,  0.,  0.,  1.],
            [ 0.,  0.,  0.,  1.,  0.,  0.],
            [ 0.,  1.,  1.,  1.,  1.,  0.],
            [ 0.,  1.,  0.,  1.,  0.,  0.],
            [ 0.,  1.,  0.,  0.,  1.,  1.]])

我希望运行忽略屏蔽元素的“漏洞”中值过滤器。

例如,带有内核的排名过滤器

k = np.array([[ 1, 1, 1],
              [ 1, 0, 1],
              [ 1, 1, 1]]); 

将在 MyArray 上运行:对内核为 MyArray 的每个元素定义的邻域进行排序,并仅返回非屏蔽元素的中值(如果数组是偶数)。

现在,目前我正在非 Python 循环中执行此操作,使用 bottleneck.nanmedian 通过将掩码映射到 NaN。这正是我所需要的,但我希望依靠二维数组操作例程。

scipy.signal.order_filterscipy.ndimage.filters.rank_filter 都可用(rank_filter 似乎快得多),但它们似乎排序 NaNInf 在返回排名和偏置结果之前位于数组的顶部。似乎这些方法都不支持 numpy.ma 数组(掩码),也不接受选择性等级数组(然后我可以用 0 填充所有掩码并偏移我的等级),也没有明显的方法来改变内核每个位置。

我想知道我是否错过了组合和/或 python 功能,或者我是否应该寻求在 Cython 中实现一个新例程。

忽略边界处理,上述问题的内部点为

[[ 0.     0.     0.     0.     0.     0.   ]
 [ 0.     3.18   3.62   2.26   2.645  0.   ]
 [ 0.     2.74   3.325  2.74   2.64   0.   ]
 [ 0.     3.88   3.62   4.955  6.08   0.   ]
 [ 0.     5.02   5.77   5.77   6.52   0.   ]
 [ 0.     0.     0.     0.     0.     0.   ]]

最佳答案

一种方法是牺牲 RAM 使用以放弃 Python 循环。 IE。我们炸毁了原始数组,以便我们可以一次对所有子数组应用过滤器。这有点类似于 Numpy broadcasting.

在我的测试中,对于 1000x1000 的数组,向量化函数的执行速度大约快 100 倍。

在我的代码中,我使用了 NaN 进行屏蔽,但是通过一些额外的代码行,您还可以使用 numpy.ma 数组。而且我没有 nanmedian 函数,所以我使用了 nanmean,不过性能应该相当。

import numpy as np
from numpy.lib.stride_tricks import as_strided

# test data
N = 1000
A = np.random.rand(N, N)*10
mask = np.random.choice([True, False], size=(N, N))

def filter_loop(A, mask):
    kernel = np.array([[1,1,1],[1,0,1],[1,1,1]], bool)
    A = A.copy()
    A[mask] = np.nan
    N = A.shape[0] - 2  # assuming square matrix
    out = np.empty((N, N))
    for i in xrange(N):
        for j in xrange(N):
            out[i,j] = np.nanmean(A[i:i+3, j:j+3][kernel])
    return out    

def filter_broadcast(A, mask):
    A = A.copy()
    A[mask] = np.nan
    N = A.shape[0] - 2
    B = as_strided(A, (N, N, 3, 3), A.strides+A.strides)
    B = B.copy().reshape((N, N, 3*3))
    B[:,:,4] = np.nan
    return np.nanmean(B, axis=2)

关于python/numpy 对掩码数组(和/或选择性排名)进行二维内核排名过滤的最快方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23829097/

相关文章:

python - 我如何在某种意义上 ndarrays 中的 "juggle"元素?

python - 确定 numpy 数组的字节顺序

Python 与 C++ OpenCV matchTemplate

python - Itertools.count Python

python - 代码优化/减少运行时间

python - 计算数据框列中每个值的百分位数

python - NumPy 日志函数抛出 int 属性错误

python - 使用 python 类型时,Visual Studio Code 颜色不起作用

python - 在 Python 中,如何获取已知键的 JSON 值

python - 如何在python中创建矩阵向量