我有一个可变维度numpy数组,例如它可以具有以下形状
(64, 64)
(64, 64, 2, 5)
(64, 64, 40)
(64, 64, 10, 20, 4)
我想要做的是,如果维度的数量大于3,我想在保留顺序的同时将其他所有内容折叠/堆叠到第三维。所以,在上面的例子中,操作后的形状应该是:
(64, 64)
(64, 64, 10)
(64, 64, 40)
(64, 64, 800)
此外,需要保留订单。例如,形状(64, 64, 2, 5)
的数组应该堆叠为
(64, 64, 2)
(64, 64, 2)
(64, 64, 2)
(64, 64, 2)
(64, 64, 2)
即。 3D切片一个接一个。此外,在操作之后,我想将其重新塑造回原始形状而没有任何排列,即保留原始顺序。
我能做的一种方法是将所有尺寸值从3乘以最后一个尺寸,即
shape = array.shape
if len(shape) > 3:
final_dim = 1
for i in range(2, len(shape)):
final_dim *= shape[i]
然后重塑数组。类似的东西:
array.reshape(64, 64, final_dim)
但是,我首先不确定订单是否按照我的要求保留,以及是否有更好的pythonic方法来实现这一目标?
答案 0 :(得分:2)
编辑:正如在其他答案中所指出的那样,仅提供-1作为reshape
的第三维更为容易。 Numpy会自动确定正确的形状。
我不确定这里的问题是什么。您只需使用np.reshape
即可保留订单。请参阅以下代码:
import numpy as np
A = np.random.rand(20,20,2,2,18,5)
print A.shape
new_dim = np.prod(A.shape[2:])
print new_dim
B = np.reshape(A, (A.shape[0], A.shape[1], np.prod(A.shape[2:])))
print B.shape
C = B.reshape((20,20,2,2,18,5))
print np.array_equal(A,C)
输出结果为:
(20L, 20L, 2L, 2L, 18L, 5L)
360
(20L, 20L, 360L)
True
这完全符合您的要求。
答案 1 :(得分:2)
重塑接受自动重新维度:
a=rand(20,20,8,6,4)
s=a.shape[:2]
if a.ndim>2 : s = s+ (-1,)
b=a.reshape(s)
答案 2 :(得分:0)
根据给定(64, 64, 2, 5)
样本的堆叠要求,我认为您需要对轴进行置换。对于置换,我们可以使用np.rollaxis
,就像这样 -
def collapse_dims(a):
if a.ndim>3:
return np.rollaxis(a,-1,2).reshape(a.shape[0],a.shape[1],-1)
else:
return a
在给定的四个样本形状上运行样本 -
1)样品形状:
In [234]: shp1 = (64, 64)
...: shp2 = (64, 64, 2, 5)
...: shp3 = (64, 64, 40)
...: shp4 = (64, 64, 10, 20, 4)
...:
案例#1:
In [235]: a = np.random.randint(11,99,(shp1))
In [236]: np.allclose(a, collapse_dims(a))
Out[236]: True
案例#2:
In [237]: a = np.random.randint(11,99,(shp2))
In [238]: np.allclose(a[:,:,:,0], collapse_dims(a)[:,:,0:2])
Out[238]: True
In [239]: np.allclose(a[:,:,:,1], collapse_dims(a)[:,:,2:4])
Out[239]: True
In [240]: np.allclose(a[:,:,:,2], collapse_dims(a)[:,:,4:6]) # .. so on
Out[240]: True
案例#3:
In [241]: a = np.random.randint(11,99,(shp3))
In [242]: np.allclose(a, collapse_dims(a))
Out[242]: True
案例#4:
In [243]: a = np.random.randint(11,99,(shp4))
In [244]: np.allclose(a[:,:,:,:,0].ravel(), collapse_dims(a)[:,:,:200].ravel())
Out[244]: True
In [245]: np.allclose(a[:,:,:,:,1].ravel(), collapse_dims(a)[:,:,200:400].ravel())
Out[245]: True
答案 3 :(得分:0)
我将尝试说明@Divaker
提出的问题。
In [522]: arr = np.arange(2*2*3*4).reshape(2,2,3,4)
In [523]: arr
Out[523]:
array([[[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]],
[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]],
[[[24, 25, 26, 27],
[28, 29, 30, 31],
[32, 33, 34, 35]],
[[36, 37, 38, 39],
[40, 41, 42, 43],
[44, 45, 46, 47]]]])
4是最内层的维度,因此它将数组显示为3x4块。如果你注意空格和[],你会看到有2x2块。
请注意当我们使用reshape
:
In [524]: arr1 = arr.reshape(2,2,-1)
In [525]: arr1
Out[525]:
array([[[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
[12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]],
[[24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35],
[36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47]]])
现在是2个2x12块。您可以对这12个元素行执行任何操作,并将它们重新整形为3x4块
In [526]: arr1.reshape(2,2,3,4)
Out[526]:
array([[[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
...
但我也可以在最后一个维度上拆分这个数组。 np.split
可以做到,但列表理解更容易理解:
In [527]: alist = [arr[...,i] for i in range(4)]
In [528]: alist
Out[528]:
[array([[[ 0, 4, 8],
[12, 16, 20]],
[[24, 28, 32],
[36, 40, 44]]]),
array([[[ 1, 5, 9],
[13, 17, 21]],
[[25, 29, 33],
[37, 41, 45]]]),
array([[[ 2, 6, 10],
[14, 18, 22]],
[[26, 30, 34],
[38, 42, 46]]]),
array([[[ 3, 7, 11],
[15, 19, 23]],
[[27, 31, 35],
[39, 43, 47]]])]
这包含4(2,2,3)个数组。请注意,3个元素行在4d显示中显示为列。
我可以使用np.stack
(类似np.array
)改造为4d数组,但可以更好地控制数组的连接方式:
In [529]: np.stack(alist, axis=-1)
Out[529]:
array([[[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]],
...
[[36, 37, 38, 39],
[40, 41, 42, 43],
[44, 45, 46, 47]]]])
==========
split
等效于[x[...,0] for x in np.split(arr, 4, axis=-1)]
。没有索引拆分产生(2,2,3,1)数组。
collapse_dims
产生(对于我的例子):
In [532]: np.rollaxis(arr,-1,2).reshape(arr.shape[0],arr.shape[1],-1)
Out[532]:
array([[[ 0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11],
[12, 16, 20, 13, 17, 21, 14, 18, 22, 15, 19, 23]],
[[24, 28, 32, 25, 29, 33, 26, 30, 34, 27, 31, 35],
[36, 40, 44, 37, 41, 45, 38, 42, 46, 39, 43, 47]]])
A(2,2,12)数组,但行中的元素顺序不同。它在展平之前对内部2维进行转置。
In [535]: arr[0,0,:,:].ravel()
Out[535]: array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
In [536]: arr[0,0,:,:].T.ravel()
Out[536]: array([ 0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11])
将其恢复为原始订单需要另一次滚动或转置
In [542]: arr2.reshape(2,2,4,3).transpose(0,1,3,2)
Out[542]:
array([[[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]],
....
[[36, 37, 38, 39],
[40, 41, 42, 43],
[44, 45, 46, 47]]]])