【问题标题】:Numpy Routine(s) to create a regular grid inside a 2d arrayNumpy Routine(s) 在二维数组中创建规则网格
【发布时间】:2013-10-14 15:50:20
【问题描述】:

我正在尝试编写一个函数,该函数将在 2d 数组中创建一个 5 x 5 像素的规则网格。我希望numpy.arangenumpy.repeat 的某种组合可以做到这一点,但到目前为止我还没有运气,因为numpy.repeat 只会在同一行重复。

这是一个例子:

假设我想要在形状为(20, 15) 的二维数组内有一个 5x5 网格。它应该看起来像:

array([[ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2],
       [ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2],
       [ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2],
       [ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2],
       [ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2],
       [ 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5],
       [ 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5],
       [ 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5],
       [ 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5],
       [ 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5],
       [ 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8],
       [ 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8],
       [ 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8],
       [ 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8],
       [ 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8],
       [ 9, 9, 9, 9, 9,10,10,10,10,10,11,11,11,11,11],
       [ 9, 9, 9, 9, 9,10,10,10,10,10,11,11,11,11,11],
       [ 9, 9, 9, 9, 9,10,10,10,10,10,11,11,11,11,11],
       [ 9, 9, 9, 9, 9,10,10,10,10,10,11,11,11,11,11],
       [ 9, 9, 9, 9, 9,10,10,10,10,10,11,11,11,11,11]])

我意识到我可以简单地使用循环和切片来完成此操作,但我可能会将其应用于非常大的数组,我担心其性能会太慢或不切实际。

谁能推荐一个方法来完成这个?

提前致谢。

更新

提供的所有答案似乎都很好。谁能告诉我哪个对大型阵列最有效?大数组是指100000 x 100000 或更多15 x 15 网格单元大小。

【问题讨论】:

  • 这里有两种解决方案,一种涉及numpy.kron,一种涉及numpy.repeatstackoverflow.com/questions/7525214/how-to-scale-a-numpy-array
  • 我在这里发布了一个答案,但事实证明它与您链接问题中使用的@NPE方法相同。
  • @Brionius - numpy.kron 绝对有效。你认为这和@Mr. 之间有很大的性能差异吗? E的答案?
  • 输出数组在你的问题中占主导地位,所以差异会很小。如果大小为(m, n),单元格为(d, d),则E先生构建两个大小为(m,)(n,)的数组,并执行m * n加法。我的解决方案创建了一个数组 (m * n / d / d,) 并且不执行其他操作。我的猜测是,对于较大的mn 和相对较小的d,E 先生的解决方案会更快、更高效,但不会很多。通过查看source code,我很确定np.kron 的表现会更差。

标签: python numpy grid


【解决方案1】:

广播就是答案:

m, n, d = 20, 15, 5
arr = np.empty((m, n), dtype=np.int)
arr_view = arr.reshape(m // d, d, n // d, d)
vals = np.arange(m // d * n // d).reshape(m // d, 1, n // d, 1)
arr_view[:] = vals

>>> arr
array([[ 0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  2,  2,  2,  2,  2],
       [ 0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  2,  2,  2,  2,  2],
       [ 0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  2,  2,  2,  2,  2],
       [ 0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  2,  2,  2,  2,  2],
       [ 0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  2,  2,  2,  2,  2],
       [ 3,  3,  3,  3,  3,  4,  4,  4,  4,  4,  5,  5,  5,  5,  5],
       [ 3,  3,  3,  3,  3,  4,  4,  4,  4,  4,  5,  5,  5,  5,  5],
       [ 3,  3,  3,  3,  3,  4,  4,  4,  4,  4,  5,  5,  5,  5,  5],
       [ 3,  3,  3,  3,  3,  4,  4,  4,  4,  4,  5,  5,  5,  5,  5],
       [ 3,  3,  3,  3,  3,  4,  4,  4,  4,  4,  5,  5,  5,  5,  5],
       [ 6,  6,  6,  6,  6,  7,  7,  7,  7,  7,  8,  8,  8,  8,  8],
       [ 6,  6,  6,  6,  6,  7,  7,  7,  7,  7,  8,  8,  8,  8,  8],
       [ 6,  6,  6,  6,  6,  7,  7,  7,  7,  7,  8,  8,  8,  8,  8],
       [ 6,  6,  6,  6,  6,  7,  7,  7,  7,  7,  8,  8,  8,  8,  8],
       [ 6,  6,  6,  6,  6,  7,  7,  7,  7,  7,  8,  8,  8,  8,  8],
       [ 9,  9,  9,  9,  9, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11],
       [ 9,  9,  9,  9,  9, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11],
       [ 9,  9,  9,  9,  9, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11],
       [ 9,  9,  9,  9,  9, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11],
       [ 9,  9,  9,  9,  9, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11]])

【讨论】:

  • 感谢您的回答。不幸的是,这对我不起作用。我最终得到了arr_view.shape = (4L, 5L, 3L, 5L) 而不是(20, 15)
  • @Brian arr_view 是原始数组的视图,仅用于具有可广播的形状。你想看的是arr:它的形状仍然是(20, 15)
  • 我明白了。感谢您的澄清。我不熟悉视图的概念。我得调查一下。
【解决方案2】:

类似于 Jaime 的回答:

np.repeat(np.arange(0, 10, 3), 4)[..., None] + np.repeat(np.arange(3), 5)[None, ...]

【讨论】:

  • 这似乎比 Jaime 的答案简单得多,也更接近我想要做的事情。我不熟悉[..., None]。这到底是什么意思?
  • 这叫广播。 herehere 给出了最佳解释。阅读省略号和更多关于广播here 的信息。您可能会在文档中看到使用 np.newaxis 而不是 None
【解决方案3】:

kron 将执行此扩展(正如 Brionius 在 cmets 中也建议的那样):

xi, xj, ni, nj = 5, 5, 4, 3
r = np.kron(np.arange(ni*nj).reshape((ni,nj)), np.ones((xi, xj)))

虽然我还没有测试过,但我认为它的效率不如广播方法,但更简洁且更易于理解(我希望如此)。它的效率可能较低,因为:1) 它需要一个数组,2) 它执行 xi*xj 乘以 1,以及 3) 它执行一堆 concat。

【讨论】:

  • 这实际上不起作用。需要进行小的修正。 np.ones((xi*ni, xj*nj)) 应该是 np.ones((xi, xj))。通过更正,它确实起作用了。感谢效率的解释。
猜你喜欢
  • 1970-01-01
  • 2023-01-04
  • 2015-10-27
  • 2012-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多