本文最后更新于:星期二, 八月 2日 2022, 9:32 晚上
numpy的一大特色就是其内部的矩阵向量运算。矩阵之间的拼接方法,你掌握多少?
1. append拼接
我们都知道对于Python原生列表list来说,append是最方便的添加元素的方法,一句list.append(elem)就能在列表最后添加一个元素。
在numpy中,append也是一个直观且好用的方法,np.append(A,B)能够直接拼合两个ndarray数组。
首先我们新建两个三维数组,一个全为零,一个全为一。
C = np.zeros((2,2,2))
D = np.ones((2,2,2))
print("C: ", C, C.shape)
print("D: ", D, D.shape)
C: [[[0. 0.]
[0. 0.]]
[[0. 0.]
[0. 0.]]]
shape=(2, 2, 2)
D: [[[1. 1.]
[1. 1.]]
[[1. 1.]
[1. 1.]]]
shape=(2, 2, 2)
然后我们采用不同的方法将其拼合在一起。
首先是append(C,D)这种直观的方法,可以看到C和D都被展开成了一维。
np.append(C,D)
array([0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 1., 1., 1., 1., 1.])
在很多时候我们希望数组拼接时能够保持原有的维度,按照行拼接/列拼接/其他维度拼接。此时只需要改动append的参数axis即可。
np.append(C,D,axis=0)
array([[[0., 0.],
[0., 0.]],
[[0., 0.],
[0., 0.]],
[[1., 1.],
[1., 1.]],
[[1., 1.],
[1., 1.]]])
np.append(C,D,axis=1)
array([[[0., 0.],
[0., 0.],
[1., 1.],
[1., 1.]],
[[0., 0.],
[0., 0.],
[1., 1.],
[1., 1.]]])
np.append(C,D,axis=2)
array([[[0., 0., 1., 1.],
[0., 0., 1., 1.]],
[[0., 0., 1., 1.],
[0., 0., 1., 1.]]])
对于三维数组,axis=0为层,axis=1为行,axis=2为列。这不难理解,因为确定单位数组中元素位置的坐标就是(层,行,列)
2. concatenate拼接
concatenate从字面意义上就让人明白这个函数专门负责数组拼接。不仅仅是两个,还可以负责多个数组一起拼接。理论上来说concatenate的速度和内存消耗都比append要小,但我并没有实际做实验验证。
np.concatenate((C,D)) # default axis=0
array([[[0., 0.],
[0., 0.]],
[[0., 0.],
[0., 0.]],
[[1., 1.],
[1., 1.]],
[[1., 1.],
[1., 1.]]])
np.concatenate((C,D), axis=1) # =np.append(C,D,axis=1)
array([[[0., 0.],
[0., 0.],
[1., 1.],
[1., 1.]],
[[0., 0.],
[0., 0.],
[1., 1.],
[1., 1.]]])
3. stack系列
stack系列函数包括np.stack/hstack/vstack/dstack/column_stack/row_stack,顾名思义,hstack是按照横向拼接,vstack竖着拼接,dstack则是层叠数组。其实我最烦这种抽象描述了,因为二维数组和三维数组/高维数组的抽象描述根本不一致,还是axis好。不明白axis的同学可以看这篇文章。
np.hstack((C,D)) # = np.append(C,D,axis=1) = np.column_stack()
array([[[0., 0.],
[0., 0.],
[1., 1.],
[1., 1.]],
[[0., 0.],
[0., 0.],
[1., 1.],
[1., 1.]]])
np.vstack((C,D)) # =np.append(C,D,axis=0) = np.row_stack()
array([[[0., 0.],
[0., 0.]],
[[0., 0.],
[0., 0.]],
[[1., 1.],
[1., 1.]],
[[1., 1.],
[1., 1.]]])
np.dstack((C,D)) # =np.append(C,D,aixs=2)
array([[[0., 0., 1., 1.],
[0., 0., 1., 1.]],
[[0., 0., 1., 1.],
[0., 0., 1., 1.]]])
4. np.r_[]
神奇的numpy总能给出神奇的解法。np.r是构建数组/拼合数组的最简便写法,但不一定是好理解的。这种写法和之前写的append没什么不同,但是更加简洁。你也可以使用np.r做出更加复杂的功能。
一言以蔽之,np.r_[]表达式能够快速使得多个在中括号里面的array/array切片,按照axis=0拼接起来。
np.r_[]存在两种使用情况:
- 如果中括号内部是由若干逗号(comma,)分隔的array,就将他们按照axis=0拼接起来。
- 如果中括号内部包括矩阵切片(slices)或者标量(scalars),就将他们全部变成一维数组首尾相接。
注意:
- 中括号
[3:6:1]
内部代表的切片,其含义相当于np.arange(3,6,1)
,即在[3,6)
范围内,从3开始走一步取一个元素,也就是[3,4,5]
。 - 中括号
[0:5:3j]
在最后加了字母j
,相当于np.linspace(0,5,3,endpoint=True)
,在[0,5]
范围内,均匀地取三个元素。
np.r_[C,D] # =np.append(C,D,axis=0)
array([[[0., 0.],
[0., 0.]],
[[0., 0.],
[0., 0.]],
[[1., 1.],
[1., 1.]],
[[1., 1.],
[1., 1.]]])
np.r_[0:10:3, 0:5:4j]
array([0. , 3. , 6. , 9. , 0. ,
1.66666667, 3.33333333, 5. ])
在中括号内,如果最开始是一个特定的字符串,np.r_会试图根据字符串的含义,改变其输出格式。
np.r_['r', index_expression]
和np.r_['c', index_expression]
将输出从array类型转变成matrix类型。np.r_['c', index_expression]
会把一维index_expression组装成N*1的列向量。
np.r_["r", 0:10:3, 0:5:4j]
matrix([[0. , 3. , 6. , 9. , 0. ,
1.66666667, 3.33333333, 5. ]])
np.r_["c", 0:10:3, 0:5:4j]
matrix([[0. ],
[3. ],
[6. ],
[9. ],
[0. ],
[1.66666667],
[3.33333333],
[5. ]])
np.r_["n", index_expression]
前面字符串是整数,则拼接时将会按照axis=n进行拼接。
np.r_["-1",C,D]
array([[[0., 0., 1., 1.],
[0., 0., 1., 1.]],
[[0., 0., 1., 1.],
[0., 0., 1., 1.]]])
5. np.c_
在日常使用时,我们经常需要按照最后一个维度拼合两个数组,也就是np.r[‘-1’,index_expression]。此时我们可以直接使用`np.c[]`
np.c_[C,D] # =np.append(C,D,axis=2)
array([[[0., 0., 1., 1.],
[0., 0., 1., 1.]],
[[0., 0., 1., 1.],
[0., 0., 1., 1.]]])
np.c_[0:10:3, 0:5:4j]
array([[0. , 0. ],
[3. , 1.66666667],
[6. , 3.33333333],
[9. , 5. ]])
关于numpy中的np.c_
和np.r_
相关知识,可以参考官方文档,里面有关于中括号前参数的详细解释。
notes Python array numpy concatenate
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!