【问题标题】:Python partitioning an N-dimensional volume into uniform sub-volumesPython将N维卷划分为统一的子卷
【发布时间】:2023-03-05 12:18:02
【问题描述】:

我有一个对象占用了一个底层的 N 维方形网格(由一个 numpy 数组表示),因此只有 25% 的网格点被占用。此网格中的每个 1x1x1x...N 立方体(即超立方体)包含相同数量的此对象(仅位于此超立方体的某些顶点处)。我有一个所有占用网格点的坐标数组。任务是循环遍历这个数组并提取每个 1x1x1... 超立方体的占用坐标并将它们存储在一个新数组中以供进一步处理。

最好通过例子来解释这种情况。考虑选择底层网格的 3-D 情况,以便1<=i,j,k<=4 给出 2d numpy 数组: A = [ [1 1 1] [1 2 1] [1 3 1] [1 4 1] [2 1 1] [2 2 1] [2 3 1] [2 4 1] [3 1 1] [3 2 1] [3 3 1] [3 4 1] [4 1 1] [4 2 1] [4 3 1] [4 4 1] [1 1 2] [1 2 2] [1 3 2] [1 4 2] [2 1 2] [2 2 2] [2 3 2] [2 4 2] [3 1 2] [3 2 2] [3 3 2] [3 4 2] [4 1 2] [4 2 2] [4 3 2] [4 4 2] [1 1 3] [1 2 3] [1 3 3] [1 4 3] [2 1 3] [2 2 3] [2 3 3] [2 4 3] [3 1 3] [3 2 3] [3 3 3] [3 4 3] [4 1 3] [4 2 3] [4 3 3] [4 4 3] [1 1 4] [1 2 4] [1 3 4] [1 4 4] [2 1 4] [2 2 4] [2 3 4] [2 4 4] [3 1 4] [3 2 4] [3 3 4] [3 4 4] [4 1 4] [4 2 4] [4 3 4] [4 4 4] ]

在这种情况下我需要处理的 2d numpy 数组的一个示例是: B = [[1,1,1],[1,2,1],[1,3,1],[1,4,1],[2,2,1],[2,3, 1],[2,4,1],[3,2,1],[3,3,1],[3,4,1],[4,1,1],[4,3,1] ,[1,1,2],[1,4,2],[2,1,2],[2,2,2],[2,4,2],[3,1,2],[ 3,2,2],[3,4,2],[4,1,2],[4,2,2],[4,3,2],[4,4,2],[1, 1,3],[1,4,3],[2,1,3],[2,2,3],[2,3,3],[2,4,3],[3,1, 3],[3,2,3],[3,3,3],[4,1,3],[4,2,3],[4,3,3],[4,4,3] ,[1,2,4],[1,3,4],[1,4,4],[2,1,4],[2,2,4],[2,3,4],[ 3,1,4],[3,2,4],[3,3,4],[4,3,4],[4,4,4]]

B 仅是占用网格点的数组。循环通过B,我想获得与底层网格的每个立方体相关的占用坐标。立方体边缘由1<=i,j,k<=2、(3<=i<=4) & (1<=j,k<=2) 等定义。例如,对于由1<=i,j,k<=2 划分的立方体,我想提取数组 [[1,1,1 ],[1,1,2],[1,2,1],[2,1,2],[2,2,1],[2,2,2]] 来自B 并将其存储在用于进一步处理的新数组。然后重复此操作,直到本示例中的所有 8 个立方体都被计算在内。请注意,始终选择均匀的网格,以便始终可以进行这种类型的分区。虽然我可以选择均匀的网格,但我无法控制对象的场地占用。

Numpy 数组切片不起作用,因为通常B 中的网格点不连续。我尝试了一个使用“for”循环的代码来强加立方体边缘的范围,但它很快就变得太复杂了,而且它似乎不是正确的方法。然后是“numpy.where”函数;但条件的复杂性使其相当棘手。 “numpy.extract”也有类似的挑战。

【问题讨论】:

  • 所以你的输入总是一个完全格在一些区间的乘积中?如果是这样,您只需要这些区间的边界即可生成所有小数组……
  • @DavisHerring 对不起戴维斯,最初的问题不是很清楚。我现在已经对它进行了广泛的修改,所以我希望现在我想要做的事情更清楚了。
  • 显然你的“查询”立方体是不相交的——例如,在你的例子中没有2<=i,j,k<=3。如果我猜对了,你应该这么说。
  • 它更清楚了,但A 仍然仅在其范围内相关(以防B 没有触及边界框的每个面)。
  • @DavisHerring 是的,它们是故意不相交的,因此每个顶点只属于一个立方体。

标签: python arrays numpy


【解决方案1】:

如果您将网格作为 ndim+1 维坐标数组,像这样

a = np.stack(np.mgrid[1:5, 1:5], -1)

那么这只是一个明智的重塑和转置的问题:

import itertools as it

# dimensions for reshape:
# split all coordinate axes into groups of two, leave the
# "dimension subscript" axis alone     
chop = *it.chain.from_iterable((i//2, 2) for i in a.shape[:-1]),

# shuffle for transpose:
# regroup axes into coordinates then pairs then subscript
ax_shuf = *(1 ^ np.r_[1:4*a.ndim-3:2] % (2*a.ndim-1)), -1

# put it together and flatten, i.e. join coordinates and join pairs
a.reshape(*chop, -1).transpose(*ax_shuf).reshape(np.prod(chop[::2]), -1, a.shape[-1])

结果:

array([[[1, 1],
        [1, 2],
        [2, 1],
        [2, 2]],

       [[1, 3],
        [1, 4],
        [2, 3],
        [2, 4]],

       [[3, 1],
        [3, 2],
        [4, 1],
        [4, 2]],

       [[3, 3],
        [3, 4],
        [4, 3],
        [4, 4]]])

更新

如果 B 是完整网格的无序子集,您可以执行以下技巧:

  1. 减去按列的最小值以确保奇偶校验从偶数开始
  2. 地板除以 2,每个感兴趣的立方体的角将折叠成一个点
  3. 现在在行上使用 np.unique 来获取组

注意:如果需要,您可以通过将下面代码中的 argsort 替换为 Most efficient way to sort an array into bins specified by an index array? 的解决方案之一来加快速度。

B = np.array(B)
unq, idx, cts = np.unique((B-B.min(0))//2, axis=0, return_inverse=True, return_counts=True)
if (cts[0]==cts).all():
    result = B[idx.argsort()].reshape(len(unq), cts[0], -1)
else:
    result = np.split(B[idx.argsort()], cts[:-1].cumsum())

结果:

array([[[1, 1, 1],
        [1, 2, 1],
        [2, 2, 1],
        [2, 2, 2],
        [2, 1, 2],
        [1, 1, 2]],

       [[2, 2, 3],
        [2, 1, 3],
        [1, 1, 3],
        [2, 1, 4],
        [2, 2, 4],
        [1, 2, 4]],

       [[1, 4, 2],
        [2, 4, 2],
        [1, 3, 1],
        [1, 4, 1],
        [2, 3, 1],
        [2, 4, 1]],

       [[1, 4, 4],
        [1, 3, 4],
        [2, 4, 3],
        [2, 3, 3],
        [1, 4, 3],
        [2, 3, 4]],

       [[4, 1, 1],
        [4, 1, 2],
        [3, 2, 1],
        [3, 2, 2],
        [4, 2, 2],
        [3, 1, 2]],

       [[4, 2, 3],
        [3, 2, 4],
        [3, 1, 3],
        [3, 2, 3],
        [3, 1, 4],
        [4, 1, 3]],

       [[4, 4, 2],
        [4, 3, 2],
        [3, 4, 2],
        [4, 3, 1],
        [3, 4, 1],
        [3, 3, 1]],

       [[4, 3, 3],
        [3, 3, 3],
        [4, 3, 4],
        [3, 3, 4],
        [4, 4, 3],
        [4, 4, 4]]])

【讨论】:

  • 对不起,保罗,看来我可能过于简化了导致误解的问题。我描述的网格仅由一些对象填充了 25% 的点。实际上,数组 A 就是这些点的数组。网格的每个 1x1x1x...N 立方体包含相同数量的位于顶点(即网格点上)的对象。任务是从数组 A 中为每个超立方体提取对象的坐标,并将它们存储在另一个数组中进行处理。我只能选择均匀的网格,但我无法控制站点占用。
  • @ooter 不用担心。但是你能更好地描述你的问题吗?或者更好的是,更新您的示例以更好地描述您的实际任务?就目前而言,它在我看来确实像一个扁平的网格。如果不是这种情况,请选择一个更具代表性的例子。最重要的是添加一个预期的结果。谢谢。
  • 我已经完全更新了这个问题。希望现在任务更清楚了!
  • @ooter 我已经更新了答案。它仍然假设坐标是连续的整数。如果这不正确,它会变得有点复杂,但仍然非常可行。
  • 抱歉,我还没来得及测试代码就走了。它会变魔术!感谢您的帮助 - 仍然无法相信您这么快就解决了这个问题!
猜你喜欢
  • 1970-01-01
  • 2020-11-15
  • 1970-01-01
  • 1970-01-01
  • 2017-01-06
  • 2018-10-27
  • 1970-01-01
  • 2021-06-26
相关资源
最近更新 更多