本文最后更新于:星期二, 八月 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_[]存在两种使用情况:

  1. 如果中括号内部是由若干逗号(comma,)分隔的array,就将他们按照axis=0拼接起来。
  2. 如果中括号内部包括矩阵切片(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协议 。转载请注明出处!