NumPy之操控ndarray的形状

系列文章

一次性搞定NumPy入门基础知识
NumPy之操控ndarray的形状
NumPy之浅拷贝和深拷贝
NumPy之索引技巧

概述

这里主要总结针对ndarray形状的三种操作:

  • 改变ndarray的形状
  • 堆叠几个ndarray
  • 拆分ndarray

改变ndarray的形状

以下列ndarray为例:

>>> a = np.floor(10*np.random.random((3,4)))
>>> a
array([[ 2.,  8.,  0.,  6.],
       [ 4.,  5.,  1.,  1.],
       [ 8.,  9.,  3.,  6.]])
>>> a.shape
(3, 4)    

如下三个是改变ndarray形状的三个常用命令,注意这三个命令并不改变原始的ndarray:

>>> a.ravel()  # 将原始ndarray转化为一维ndarray并返回
array([ 2.,  8.,  0.,  6.,  4.,  5.,  1.,  1.,  8.,  9.,  3.,  6.])

>>> a.reshape(6,2)  # 指定新的shape,返回不同shape的ndarray
array([[ 2.,  8.],
       [ 0.,  6.],
       [ 4.,  5.],
       [ 1.,  1.],
       [ 8.,  9.],
       [ 3.,  6.]])

>>> a.T  # 返回转置后的ndarray,类似于线性代数中的转置矩阵
array([[ 2.,  4.,  8.],
       [ 8.,  5.,  9.],
       [ 0.,  1.,  3.],
       [ 6.,  1.,  6.]])
>>> a.T.shape
(4, 3)
>>> a.shape
(3, 4)  

注意,上述的几个命令,改变形状时遵循的原则都是“C-style”的。也就是说,最右边的索引,变化的最快。以a.ravel()为例,在改变形状时,a[0][0]之后紧跟的元素是a[0][1]。NumPy的内部存储也是遵循这种顺序,因此,使用ravel()并不会导致拷贝的操作。当然,ravel()reshape()都可以通过参数来进行控制,改变成例如采用"FORTRAN-style"的模式,使得最左边的索引变得最快。

注意下面两个方法的区别:reshape返回一个新的ndarray,而resize则会直接修改这个ndarray本身。

>>> a
array([[ 2.,  8.,  0.,  6.],
       [ 4.,  5.,  1.,  1.],
       [ 8.,  9.,  3.,  6.]])
>>> a.resize((2,6))
>>> a
array([[ 2.,  8.,  0.,  6.,  4.,  5.],
       [ 1.,  1.,  8.,  9.,  3.,  6.]]) 

如果reshape的某一个参数是-1,那么reshape的最终形状将会由函数自动计算出来。

>>> a.reshape(3,-1)
array([[ 2.,  8.,  0.,  6.],
       [ 4.,  5.,  1.,  1.],
       [ 8.,  9.,  3.,  6.]]) 

ndarray的堆叠

几个不同的ndarray可以沿着指定的axis进行堆叠,举例如下:

>>> a = np.floor(10*np.random.random((2,2)))
>>> a
array([[ 8.,  8.],
       [ 0.,  0.]])
>>> b = np.floor(10*np.random.random((2,2)))
>>> b
array([[ 1.,  8.],
       [ 0.,  4.]])

>>> np.vstack((a,b))
array([[ 8.,  8.],
       [ 0.,  0.],
       [ 1.,  8.],
       [ 0.,  4.]])

>>> np.hstack((a,b))
array([[ 8.,  8.,  1.,  8.],
       [ 0.,  0.,  0.,  4.]])    

上例以二维ndarray为例,vstack方法沿着垂直的方向堆叠(也就是第一个axis),hstack方法沿着水平方向堆叠(也就是第二个axis)。

需要注意column_stack方法,对于两个1D的ndarray,它会把它们堆叠成一个2D的ndarray。例如:

>>> a = np.array([1,2,3])
>>> b = np.array([4,5,6])
>>> np.column_stack((a,b))
array([[1, 4],
       [2, 5],
       [3, 6]])

对于2D的ndarray来说,column_stack的作用等同于hstack,否则hstack会把两个1D的ndarray当作行来进行合并:

>>> from numpy import newaxis
>>> a = np.floor(10*np.random.random((2,2)))
>>> b = np.floor(10*np.random.random((2,2)))
>>> np.column_stack((a,b))    
array([[ 8.,  8.,  1.,  8.],
       [ 0.,  0.,  0.,  4.]])
>>> a = np.array([4.,2.])
>>> b = np.array([3.,8.])
>>> np.column_stack((a,b))     
array([[ 4., 3.],
       [ 2., 8.]])
>>> np.hstack((a,b))           # 结果不同,这时hstack把两个1D ndarray当作行向量来处理了
array([ 4., 2., 3., 8.])
>>> a[:,newaxis]               # 变换axis
array([[ 4.],
       [ 2.]])
>>> np.column_stack((a[:,newaxis],b[:,newaxis]))
array([[ 4.,  3.],
       [ 2.,  8.]])
>>> np.hstack((a[:,newaxis],b[:,newaxis]))   # 这时候结果一致了
array([[ 4.,  3.],
       [ 2.,  8.]])  

另一方面,row_stack在任何时候和vstack都是等同的。总结一下,对于两维以上的ndarray,hstack沿着第二个axis合并,vstack沿着第一个axis合并,concatenate则通过参数控制,来决定沿着哪个方向进行合并。

另外,在一些复杂的场景,可以使用r_c_来创建ndarray,举例如下:

>>> np.r_[1:4,0,4]
array([1, 2, 3, 0, 4])

其中的:和arange方法中的意义相同。在这里,r_c_的作用分别类似于vstackhstack的作用,但也允许通过参数控制来决定沿着哪个axis进行堆叠。

需要注意,沿着某一个axis进行堆叠时,参与堆叠的ndarray的其他axis的length必须相同。
例如一个 3 × 2 3 \times 2 3×2的ndarray可以和另一个 5 × 2 5 \times 2 5×2的ndarray沿着第一个axis进行堆叠,但却不能和另一个 3 × 3 3 \times 3 3×3的ndarray沿着第一个axis进行堆叠。

ndarray的拆分

一个ndarray可以拆分成几个小的ndarray。这里以hsplit为例,该函数可以沿着水平方向拆分ndarray。可以以两种方式给其传参。一种是,指定参数N,说明将原始ndarray拆分成几个小的ndarray,NumPy会根据这个参数,沿着这个方向将原来的ndarray等分成N份(如果列数不能被N整除,将会报错);另一种是,指定在哪些列后面切一刀,NumPy会根据这个指示,将原始的ndarray进行拆分。

举例,对于一个6列的ndarray,如果传入参数3,那么NumPy将会按如下方式,将这个ndarray进行等分:
a 00 a 01 a 02 a 03 a 04 a 05 a 10 a 11 a 12 a 13 a 14 a 15 \begin{array}{cc:cc:cc} a_{00} & a_{01} & a_{02} & a_{03} & a_{04} & a_{05} \\ a_{10} & a_{11} & a_{12} & a_{13} & a_{14} & a_{15} \end{array} a00a10a01a11a02a12a03a13a04a14a05a15
同样的ndarray,如果传入参数(1,3),那么NumPy会在对应的列后面划一条线(第一列后面、第三列后面),进行分拆:
a 00 a 01 a 02 a 03 a 04 a 05 a 10 a 11 a 12 a 13 a 14 a 15 \begin{array}{c:cc:ccc} a_{00} & a_{01} & a_{02} & a_{03} & a_{04} & a_{05} \\ a_{10} & a_{11} & a_{12} & a_{13} & a_{14} & a_{15} \end{array} a00a10a01a11a02a12a03a13a04a14a05a15

代码示例如下:

>>> a = np.floor(10*np.random.random((2,12)))
>>> a
array([[ 9.,  5.,  6.,  3.,  6.,  8.,  0.,  7.,  9.,  7.,  2.,  7.],
       [ 1.,  4.,  9.,  2.,  2.,  1.,  0.,  6.,  2.,  2.,  4.,  0.]])
>>> np.hsplit(a,3)   # Split a into 3
[array([[ 9.,  5.,  6.,  3.],
       [ 1.,  4.,  9.,  2.]]), array([[ 6.,  8.,  0.,  7.],
       [ 2.,  1.,  0.,  6.]]), array([[ 9.,  7.,  2.,  7.],
       [ 2.,  2.,  4.,  0.]])]
>>> np.hsplit(a,(3,4))   # Split a after the third and the fourth column
[array([[ 9.,  5.,  6.],
       [ 1.,  4.,  9.]]), array([[ 3.],
       [ 2.]]), array([[ 6.,  8.,  0.,  7.,  9.,  7.,  2.,  7.],
       [ 2.,  1.,  0.,  6.,  2.,  2.,  4.,  0.]])]     
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值