【问题标题】:Numpy - even more position-based array modificationNumpy - 更多基于位置的数组修改
【发布时间】:2018-07-05 09:04:41
【问题描述】:

我有一个大的二维 numpy 数组,每个值都是 0 或 1。我想创建一个函数,将这个数组作为输入,并返回一个相同大小的新数组,其中每个元素都基于上面、下面和任一侧的元素。返回的数组应该有 0 保持 0,如果有一个 1 在北方,每个 1 将获得 +1,对于右侧的 1,+2,对于下方的 1,+4,对于左侧的 1,+8。这些都是堆叠的,因此被 1 包围的 1 最终应该是 17。对角线无关紧要。使用显式按位运算(4 位,每个位对应一个方向以及其中是否有 1 或 0),这也可能会更快。

我希望尽快完成此操作。我玩了一个 for 循环,但它太慢了,而且我对 numpy 中的掩码理解不够好,无法使用它。

【问题讨论】:

  • 序言,这听起来像是一项任务。你能分享一下你的尝试吗?
  • 听起来像是康威人生游戏的变种。这是一个简单的解释:stackoverflow.com/questions/47648106/…
  • 你到底是怎么得到17的?

标签: python arrays numpy masked-array


【解决方案1】:

您描述的操作可以表示为线性卷积,然后将之前为零的点归零:

>>> import numpy as np
>>> from scipy import signal
>>> 
>>> kernel = np.array([[0,1,0], [8,1,2], [0,4,0]])[::-1, ::-1]
>>> 
>>> pattern = np.random.randint(0, 2, (10, 10))
>>> 
>>> pattern
array([[0, 1, 1, 1, 1, 1, 1, 0, 1, 1],
       [1, 0, 1, 0, 1, 0, 0, 0, 0, 0],
       [0, 1, 0, 1, 1, 1, 0, 1, 0, 1],
       [1, 0, 1, 0, 0, 1, 1, 0, 0, 0],
       [0, 1, 0, 1, 1, 1, 1, 1, 1, 1],
       [0, 1, 0, 0, 0, 1, 0, 1, 1, 0],
       [0, 0, 0, 1, 1, 0, 1, 0, 1, 0],
       [0, 1, 0, 0, 0, 0, 1, 0, 1, 0],
       [0, 1, 1, 1, 0, 1, 0, 1, 1, 0],
       [0, 1, 0, 1, 1, 1, 0, 1, 0, 0]])
>>> 
>>> pattern * signal.convolve(pattern, kernel, 'same')
array([[ 0,  3, 15, 11, 15, 11,  9,  0,  3,  9],
       [ 1,  0,  2,  0,  6,  0,  0,  0,  0,  0],
       [ 0,  1,  0,  3, 12, 13,  0,  1,  0,  1],
       [ 1,  0,  1,  0,  0,  8, 13,  0,  0,  0],
       [ 0,  5,  0,  3, 11, 16, 12, 15, 15,  9],
       [ 0,  2,  0,  0,  0,  2,  0,  4, 14,  0],
       [ 0,  0,  0,  3,  9,  0,  5,  0,  6,  0],
       [ 0,  5,  0,  0,  0,  0,  2,  0,  6,  0],
       [ 0,  8, 11, 13,  0,  5,  0,  7, 10,  0],
       [ 0,  2,  0,  4, 11, 10,  0,  2,  0,  0]])

【讨论】:

    【解决方案2】:

    我希望这会有所帮助。我开始复制原始矩阵,然后添加来自每个方向的贡献。例如,如果我必须添加右侧元素的贡献,他们可能会修改除最后一列之外的所有列,因此我可以写result[:,:-1] += m[:,1:]m 的最后一个乘法确保每个要修改的单元格的起始值是 1 而不是 0,如您所愿。

    import numpy as np
    
    def f(m):
        result = np.copy(m)
        # propagation from the four directions
        result[1:,:] += m[:-1,:]  # north
        result[:,:-1] += 2 * m[:,1:]  # est
        result[:-1,:] += 4 * m[1:,:]  # sud
        result[:,1:] += 8 * m[:,:-1]  # west
        return result * m
    

    【讨论】:

    • @Preamble,它解决了你的问题吗?这似乎是一个非常有效的解决方案。我在 100x100 矩阵上使用 %timeit 对其进行了评估,效果非常好。
    猜你喜欢
    • 2012-04-26
    • 1970-01-01
    • 1970-01-01
    • 2022-01-08
    • 2019-06-14
    • 2018-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多