数组变形总结主要来自于两个方面:
数组中元素组织方式的变化导致的变形。
多个数组合并或单个数组拆分产生的维度变化导致的变形。
transpose()
例如,一个数组维度是(360,180,3),第一维度是经度,第二维度是维度,第三维度是年份中的碳排放总量。
现在想要把其转换为3年的排放量为外层维度:
carbon = np.random.rand(360,180,3) # 随机示意
res = carbon.transpose(2,0,1) # 最后一个维度前置,其他维度向后顺移
res.shape
>>>
(3,360,180)
T 操作(转置)可以看做一种特殊的 transpose()
的应用,它把原来维度从d1,d2,...,dk
逆向变换至dk,...d1
:
res = carbon.T # 等价于 carbon.transpose(2,1,0)
res.shape
>>>
(3,180,360)
特别地, 当数组维度为2时,T操作可被看作矩阵转置:
my_matrix = np.array([[1,2],[3,4]])
my_matrix.T
>>>
array([[1,3],
[2,4]])
在数组维度较多时,只想交换其中两个维度,使用transpose()
就不得不把所有维度都列出,非常繁琐。此时,可以使用swapaxes
:
np.swapaxes(arr,a,b)
其中,arr代表给定的数组,a,b是需要转换的2个维度。
reshape()
例如,有一个一维数组,现在想把其转换为成一个[2,4]大小的数组:
my_matrix = np.arange(8)
my_matrix.reshape(2,4)
>>>
array([[0,1,2,3],
[4,5,6,7]])
可以发现,reshape()
在填入数组时是以行顺序或内层优先的顺序进行填充的。
参数 order 控制写入和读取顺序:
事实上,可以通过指定参数order
为F,表示以列的顺序或以外层的顺序进行填充。
默认的时order = "C"
,字符串C和F分别代表C数组风格和Fortran数组风格。
# 行的顺序
my_matrix = np.arange(8)
my_matrix.reshape((2,4),order = "C")
>>>
array([[0,1,2,3],
[4,5,6,7]])
# 列的顺序
my_matrix = np.arange(8)
my_matrix.reshape((2,4),order = "F")
>>>
array([[0,2,4,6],
[1,3,5,7]])
进一步,参数order不仅控制写入的顺序,还控制数组的读取顺序,其顺序和写入顺序保持一致。
my_matrix = np.arange(8)
my_matrix.reshape((2,4),order = "C").reshape(8,order = "F")
>>>
array([0, 4, 1, 5, 2, 6, 3, 7]) #参考上例的行顺序
维度空缺的补充:
实际上,reshape()
允许有一个维度存在空缺,在转换的对应维度上填充 -1, 但要保证原数组个数能够被新矩阵给定的维度的维数乘积整除。
my_matrix.reshape(2,2,-1)
>>>
array([[[0, 1],
[2, 3]],
[[4, 5],
[6, 7]]])
上面这个方式即与转换为2*2*2的数组是相同的。
相同点:
不同点:
stack()
会产生新的维度,而concatenate()
不会。
stack()
拼接的数组维度必须完全一致,concatenate()
只需在非拼接的维度上匹配。
pop_man =np.random.rand(20,6,3)
pop_women = np.random.rand(20,6,3)
res = np.stack([pop_man,pop_women],axis=2) # 新维度为新数组的第三维
res.shape
>>>
(20,6,2,3)
相对于stack()
的异质性拼接,concatenate()
是一种同质性或连续性的拼接。
pop_1_6 = np.random_rand(20,6,3)
pop_7_12 = np.random.rand(20,6,3)
res = np.concatenate([pop_1_6,pop_7_12],axis = 1) # 在月份维度拼接
res.shape
>>>
(20,12,3)
如果此时使用stack()
,结果的意义完全不同,新结果增加表示上半年或下半年的维度。它会把两组月份“割裂”去看待,而不是连续的拼接。
np.split(ary, indices_or_sections, axis=0)
函数功能: 把一个数组从左到右按顺序切分
参数:
ary:要切分的数组
indices_or_sections:如果是一个整数,就用该数**平均切分****,如果是一个数组,为沿轴切分的位置
axis:沿着哪个维度进行切向,默认为0,横向切分
均匀平均分割:
res = np.split(pop_1_6,indices_or_sections = 3, axis = 1)
for i in res:
print(i.shape)
>>>
(20,2,3)
(20,2,3)
(20,2,3)
指定分割点:
res = np.split(pop_1_6,indices_or_sections = [1,4], axis = 1)
for i in res:
print(i.shape)
>>>
(20,1,3)
(20,3,3)
(20,2,3)
split()函数更类似于concatenate()的逆操作,首先stack必须由多个尺寸相同的数组来拼接,新产生的维度大小取决于拼接数组的数量,而concatenate的被拼接数组在拼接维度上可以不一致且不会产生新维度。下面的例子更清楚地反映了这组互逆操作的特性:
arr = np.random.rand(10, 20, 30)
arr_new = np.concatenate(np.split(arr, indices_or_sections=5, axis=1), axis=1)
(arr == arr_new).all()
>>>
True
numpy.repeat(a,repeats,axis=None);
参数:
axis=None,时候就会flatten当前矩阵,实际上就是变成了一个行向量
axis=0,增加行数,列数不变
axis=1,增加列数,行数不变
repeats 复制次数或者按照特定方式复制
它的变形方式是通过对数组内的元素按照给定的次数进行重复来实现:
a = np.arange(3)
np.repeat(a,repeats = 2)
>>>
array([0,0,1,1,2,2])
对于二维数组而言,还可以指定发生重复的维度:
np.array([[1,2],[3,4]])
np.repeat(a,repeats=[1,2],axis = 1) # 在最内层的维度上,第i个元素重复i遍
>>>
array([[1,2,2],
[3,4,4]])
c = np.array(([1,2],[3,4],[4,5]))
d=np.repeat(c,[2,3],axis=1)#对行操作,增加的是列,一行2个元素,[2,3]就是2个元素(行不变,列变:第一列复制2次,第二列复制3次)
print(d)
print('d形状:',d.shape)
>>>
[[1 1 2 2 2]
[3 3 4 4 4]
[4 4 5 5 5]]
d形状: (3, 5)