Python 将Numpy数组重塑为形状(n,n,n)立方体的词典列表

Python 将Numpy数组重塑为形状(n,n,n)立方体的词典列表,python,numpy,scipy,Python,Numpy,Scipy,为了理解我试图实现的目标,让我们想象一个带有形状(8,8,8)的ndarraya,我从中按字典顺序获取形状块(4,4,4)。因此,在遍历这些块时,索引将如下所示: 0: a[0:4, 0:4, 0:4] 1: a[0:4, 0:4, 4:8] 2: a[0:4, 4:8, 0:4] 3: a[0:4, 4:8, 4:8] 4: a[4:8, 0:4, 0:4] 5: a[4:8, 0:4, 4:8] 6: a[4:8, 4:8, 0:4] 7: a[4:8, 4:8,

为了理解我试图实现的目标,让我们想象一个带有形状
(8,8,8)
的ndarray
a
,我从中按字典顺序获取形状块
(4,4,4)
。因此,在遍历这些块时,索引将如下所示:

0: a[0:4, 0:4, 0:4]  
1: a[0:4, 0:4, 4:8]  
2: a[0:4, 4:8, 0:4]  
3: a[0:4, 4:8, 4:8]  
4: a[4:8, 0:4, 0:4]  
5: a[4:8, 0:4, 4:8]  
6: a[4:8, 4:8, 0:4]  
7: a[4:8, 4:8, 4:8]  
我正试图访问这些数据块。显然,这可以通过使用将当前迭代转换为相应索引的表达式来描述。下面给出了一个例子

a = np.ones((8,8,8))
f = 4

length = round(a.shape[0] * a.shape[1] * a.shape[2] / f**3)

x = a.shape[0] / f
y = a.shape[1] / f
z = a.shape[2] / f

for i in range(length):
    print(f"{i}: {round((int(i/(z*y))%x)*f)}:{round(f+(int(i/(z*y))%x)*f)}, {round((int(i/z)%y)*f)}:{round(f+(int(i/z)%y)*f)}, {round((i%z)*f)}:{round(f+(i%z)*f)}")

我很抱歉必须这样做,但它会产生以下输出:

0: 0:4, 0:4, 0:4
1: 0:4, 0:4, 4:8
2: 0:4, 4:8, 0:4
3: 0:4, 4:8, 4:8
4: 4:8, 0:4, 0:4
5: 4:8, 0:4, 4:8
6: 4:8, 4:8, 0:4
7: 4:8, 4:8, 4:8
因此,这确实生成了正确的索引,但它只允许您在第0轴和第1轴上具有相同索引的情况下一次访问多个块,因此没有环绕。理想情况下,我会将整个ndarray重塑为一个带有形状的ndarray
b
(4,4,32),并以这样的方式排序,
b[:,:,:4]
将返回
a[0:4,0:4,0:4]
b[:,:,:,4:12]
返回一个包含
a[0:4,0:4,4,8]
的形状的ndarray
[0:4、4:8、0:4]
等。我希望这一过程尽可能快,因此理想情况下,我保留内存布局,只需更改阵列上的视图即可。
最后,如果有助于从概念上考虑这一点,那么这基本上是
ndarray.flatte()
方法的一个变体,但如果愿意,可以使用形状块
(4,4)
作为“原子大小”


希望这足够清楚!

有点不清楚您想要什么作为输出。您正在寻找以下内容:

from skimage.util.shape import view_as_windows
b = view_as_windows(a,(f,f,f),f).reshape(-1,f,f,f).transpose(1,2,3,0).reshape(f,f,-1)
由@Paul提出,结果类似(事实上我更喜欢这个答案):

输出:

print(np.array_equal(b[:, :, 4:8],a[0:4, 0:4, 4:8]))
#True
print(np.array_equal(b[:, :, 8:12],a[0:4, 4:8, 0:4]))
#True
print(np.array_equal(b[:, :, 12:16],a[0:4, 4:8, 4:8]))
#True
编辑:

该函数将C样式展平应用于阵列,如下所示

注: 这个方法和@Ehsan的方法都会产生“副本”而不是“视图”,我正在研究它,如果找到解决方案,我会更新答案


堆叠很重要。当你说包含[0:4,0:4,4:8]和[0:4,4:8,0:4]
(4,4,8)时,堆叠是垂直的还是水平的,或者其他方式?请提供一个小的输入/所需的输出。我建议使用
a=np.arange(64)。重塑(4,4,4)
f=2
并输出,以便我们更好地理解。谢谢。因此,在这个具体示例中,给定
b
形状
(4,4,8)
b[:,:,4:8]==a[0:4,0:4,4:8]
b[,:,8:12]==a[0:4,4]
。这将扩展到
b[,:,12:16]==a[0:4,4:8]
。重要的是这些形状块
(4,4,4)
在这两种表述中保持一致。希望有帮助!@svenhandrikx请检查我在帖子上的编辑,看看这是否是您想要的。谢谢。@Ehsan是的,第一个建议的解决方案使用了滚动窗口实现,所以这不完全是我想要的,但PaulPanzer建议的编辑是exac这就是我所需要的,非常感谢!我认为你不需要在这里查看窗口。一个简单的
重塑就足够了;
b=A.重塑(2,N//2,2,N//2,N).转置(1,3,0,2,4).重塑(N//2,N//2,N*4)
@PaulPanzer这是真的。我把它添加到了帖子中。最初我不确定OP在寻找什么。谢谢。
transpose()
中的轴编号不是错了吗?应该是
(0,2,4,1,3)
@Hammad No,转置是OP要求的。请检查帖子末尾的数组检查以确认它。@PaulPanzer这正是我想要的,很好的建议!下面已经发布了这个答案。另外,根据OP的要求,转置是不正确的。要更好地理解,请使用
print检查它(np.array_equal(b[:,:,12:16],a[0:4,4:8,4:8])
每一个OP的问题请求。谢谢。@Ehsan我还添加了检查,这个检查可以帮助您检查。不过,这些似乎只是必需的块。请参阅问题的最后一部分或评论部分,了解OP想要最终输出(形状)的方式除非我错过了什么。
print(np.array_equal(b[:, :, 4:8],a[0:4, 0:4, 4:8]))
#True
print(np.array_equal(b[:, :, 8:12],a[0:4, 4:8, 0:4]))
#True
print(np.array_equal(b[:, :, 12:16],a[0:4, 4:8, 4:8]))
#True
def flatten_by(arr, atomic_size):
    a, b, c = arr.shape
    x, y, z = atomic_size
    
    r = arr.reshape([a//x, x, b//y, y, c//z, z])
    r = r.transpose([0, 2, 4, 1, 3, 5])
    r = r.reshape([-1, x, y, z])
    
    return r
flatten_by(arr, [4,4,4]).shape

>>>   (8, 4, 4, 4)
flattened = flatten_by(arr, [4,4,4])

required = np.array([
    arr[0:4, 0:4, 0:4],
    arr[0:4, 0:4, 4:8],  
    arr[0:4, 4:8, 0:4],  
    arr[0:4, 4:8, 4:8],  
    arr[4:8, 0:4, 0:4],  
    arr[4:8, 0:4, 4:8],  
    arr[4:8, 4:8, 0:4],  
    arr[4:8, 4:8, 4:8],  
])
np.array_equal(required, flattened)

>>> True