简体   繁体   English

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

[英]Reshaping a Numpy Array into lexicographical list of cubes of shape (n, n, n)

In order to understand what I'm trying to achieve let's imagine an ndarray a with shape (8,8,8) from which I lexicographically take blocks of shape (4,4,4) .为了理解我想要实现的目标,让我们想象一个形状为(8,8,8)的 ndarray a ,我按字典顺序从中获取形状(4,4,4)的块。 So while iterating through such blocks the indexes would look as follows:因此,在遍历此类块时,索引将如下所示:

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]  

It is these blocks of data which I'm trying to access.我试图访问的正是这些数据块。 Obviously, this can be described by using an expression which converts the current iteration to the corresponding indexes.显然,这可以通过使用将当前迭代转换为相应索引的表达式来描述。 An example of that is given below.下面给出了一个例子。

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)}")

My apologies for having to do that to your eyes but it generates the following output:我很抱歉不得不对你的眼睛这样做,但它会生成以下 output:

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

So this does actually generate the right indexes, but it only allows you to access multiple blocks at once if they have the same index in the 0th and 1st axis, so no wrapping around.所以这确实生成了正确的索引,但它只允许您一次访问多个块,如果它们在第 0 轴和第 1 轴具有相同的索引,所以没有环绕。 Ideally I would reshape this whole ndarray into an ndarray b with shape (4, 4, 32) and be ordered in such a way that b[:, :, :4] would return a[0:4, 0:4, 0:4] , b[:, :, 4:12] returns an ndarray of shape (4, 4, 8) which contain a[0:4, 0:4, 4:8] and a[0:4, 4:8, 0:4] etc. I want this to be as fast as possible, so ideally, I keep the memory layout and just change the view on the array.理想情况下,我会将整个 ndarray 重塑为形状为(4, 4, 32)的 ndarray b并以b[:, :, :4]将返回a[0:4, 0:4, 0:4] , b[:, :, 4:12]返回一个形状为(4, 4, 8)的 ndarray,其中包含a[0:4, 0:4, 4:8]a[0:4, 4:8, 0:4]等。我希望它尽可能快,所以理想情况下,我保留 memory 布局并仅更改阵列上的视图。
Lastly, if it helps to think about this conceptually, this is basically a variant of the ndarray.flatten() method but using blocks of shape (4, 4, 4) as "atomic size" if you will.最后,如果从概念上考虑这一点会有所帮助,这基本上是ndarray.flatten()方法的变体,但如果您愿意,可以使用形状(4, 4, 4)的块作为“原子大小”。

Hope this makes it clear enough!希望这足够清楚!

It is a bit unclear what you want as output.有点不清楚你想要什么 output。 Are you looking for this:您是否正在寻找这个:

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)

suggested by @Paul with similar result (I prefer this answer in fact): @Paul 建议的结果相似(实际上我更喜欢这个答案):

N = 8
b = a.reshape(2,N//2,2,N//2,N).transpose(1,3,0,2,4).reshape(N//2,N//2,N*4)

output: output:

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)

EDIT:编辑:

the function applies C-style flattening to the array, as shown below function 对数组应用 C 样式展平,如下所示

NOTE: this method and @Ehsan's method both produce "copies" NOT "views", im looking into it and would update the answer when if i find a solution注意:这种方法和@Ehsan 的方法都产生“副本”而不是“视图”,我正在调查它,如果我找到解决方案会更新答案

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM