NumPy
基础3本章示例代码中的输入和输出均来自IPython会话。
NumPy
数组有水平组合、垂直组合和深度组合等多种组合方式,我们将使用vstack
、dstack
、 hstack
、 column_stack
、 row_stack
以及concatenate
函数来完成数组的组合。
首先,我们来创建一些数组:
In [1]: import numpy as np
In [3]: a = np.arange(9).reshape(3,3)
In [4]: a
Out[4]:
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
In [5]: b = 2*a
In [6]: b
Out[6]:
array([[ 0, 2, 4],
[ 6, 8, 10],
[12, 14, 16]])
我们先从水平组合开始练习。将ndarray
对象构成的元组作为参数,传给hstack
函数。如下所示:
In [8]: np.hstack((a, b))
Out[8]:
array([[ 0, 1, 2, 0, 2, 4],
[ 3, 4, 5, 6, 8, 10],
[ 6, 7, 8, 12, 14, 16]])
我们也可以用concatenate
函数来实现同样的效果,如下所示:
In [9]: np.concatenate((a, b), axis=1)
Out[9]:
array([[ 0, 1, 2, 0, 2, 4],
[ 3, 4, 5, 6, 8, 10],
[ 6, 7, 8, 12, 14, 16]])
垂直组合同样需要构造一个元组作为参数,只不过这次的函数变成了vstack
。如下所示:
In [6]: np.vstack((a, b))
Out[6]:
array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 0, 2, 4],
[ 6, 8, 10],
[12, 14, 16]])
同样,我们将concatenate
函数的axis
参数设置为0
即可实现同样的效果。这也是axis
参数的默认值:
In [8]: np.concatenate((a, b), axis = 0)
Out[8]:
array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 0, 2, 4],
[ 6, 8, 10],
[12, 14, 16]])
将相同的元组作为参数传给dstack
函数,即可完成数组的深度组合。所谓深度组合,就是将一系列数组沿着纵轴(深度)方向进行层叠组合。举个例子,有若干张二维平面内的图像点阵数据,我们可以将这些图像数据沿纵轴方向层叠在一起,这就形象地解释了什么是深度组合。
In [9]: np.dstack((a, b))
Out[9]:
array([[[ 0, 0],
[ 1, 2],
[ 2, 4]],
[[ 3, 6],
[ 4, 8],
[ 5, 10]],
[[ 6, 12],
[ 7, 14],
[ 8, 16]]])
column_stack
函数对于一维数组将按列方向进行组合,如下所示:
In [10]: oned = np.arange(2)
In [11]: oned
Out[11]: array([0, 1])
In [12]: twice_oned = 2 * oned
In [13]: twice_oned
Out[13]: array([0, 2])
In [14]: np.column_stack((oned, twice_oned))
Out[14]:
array([[0, 0],
[1, 2]])
而对于二维数组, column_stack
与hstack
的效果是相同的:
In [15]: np.column_stack((a, b))
Out[15]:
array([[ 0, 1, 2, 0, 2, 4],
[ 3, 4, 5, 6, 8, 10],
[ 6, 7, 8, 12, 14, 16]])
In [16]: np.column_stack((a, b)) == np.hstack((a, b))
Out[16]:
array([[ True, True, True, True, True, True],
[ True, True, True, True, True, True],
[ True, True, True, True, True, True]])
是的,你猜对了!我们可以用==
运算符来比较两个NumPy
数组,是不是很简洁?
当然, NumPy
中也有按行方向进行组合的函数,它就是row_stack
。对于两个一维数组,将直接层叠起来组合成一个二维数组。
In [17]: np.row_stack((oned, twice_oned))
Out[17]:
array([[0, 1],
[0, 2]])
对于二维数组, row_stack
与vstack
的效果是相同的:
In [18]: np.row_stack((a, b))
Out[18]:
array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 0, 2, 4],
[ 6, 8, 10],
[12, 14, 16]])
In [19]: np.row_stack((a,b)) == np.vstack((a, b))
Out[19]:
array([[ True, True, True],
[ True, True, True],
[ True, True, True],
[ True, True, True],
[ True, True, True],
[ True, True, True]])
NumPy
数组可以进行水平、垂直或深度分割,相关的函数有hsplit
、 vsplit
、 dsplit
和split
。我们可以将数组分割成相同大小的子数组,也可以指定原数组中需要分割的位置。
下面的代码将把**数组沿着水平方向分割(按列分割)**为3个相同大小的子数组:
In [20]: a
Out[20]:
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
In [21]: np.hsplit(a, 3)
Out[21]:
[array([[0],
[3],
[6]]), array([[1],
[4],
[7]]), array([[2],
[5],
[8]])]
对同样的数组,调用split
函数并在参数中指定参数axis=1
,对比一下结果:
In [23]: np.split(a, 3, axis=1)
Out[23]:
[array([[0],
[3],
[6]]), array([[1],
[4],
[7]]), array([[2],
[5],
[8]])]
vsplit
函数将把数组沿着垂直方向(按行分割)分割:
In [24]: np.vsplit(a, 3)
Out[24]: [array([[0, 1, 2]]), array([[3, 4, 5]]), array([[6, 7, 8]])]
同样,调用split
函数并在参数中指定参数axis=0
,也可以得到同样的结果:
In [25]: np.split(a, 3, axis=0)
Out[25]: [array([[0, 1, 2]]), array([[3, 4, 5]]), array([[6, 7, 8]])]
不出所料, dsplit
函数将按深度方向分割数组。我们先创建一个三维数组:
In [26]: c = np.arange(27).reshape(3, 3, 3)
In [27]: c
Out[27]:
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]]])
In [28]: np.dsplit(c, 3)
Out[28]:
[array([[[ 0],
[ 3],
[ 6]],
[[ 9],
[12],
[15]],
[[18],
[21],
[24]]]), array([[[ 1],
[ 4],
[ 7]],
[[10],
[13],
[16]],
[[19],
[22],
[25]]]), array([[[ 2],
[ 5],
[ 8]],
[[11],
[14],
[17]],
[[20],
[23],
[26]]])]
除了shape
和dtype
属性以外, ndarray
对象还有很多其他的属性,在下面一一列出。
ndim
属性,给出数组的维数,或数组轴的个数:In [29]: b
Out[29]:
array([[ 0, 2, 4],
[ 6, 8, 10],
[12, 14, 16]])
In [30]: b.ndim
Out[30]: 2
size
属性,给出数组元素的总个数,如下所示:In [31]: b.size
Out[31]: 9
itemsize
属性,给出数组中的元素在内存中所占的字节数:In [32]: b.itemsize
Out[32]: 4
nbytes
属性来查看。这个属性的值其实就是itemsize
和size
属性值的乘积:In [33]: b.nbytes
Out[33]: 36
In [34]: b.size * b.itemsize
Out[34]: 36
T
属性的效果和transpose
函数一样,如下所示:In [35]: b.T
Out[35]:
array([[ 0, 6, 12],
[ 2, 8, 14],
[ 4, 10, 16]])
In [36]: b
Out[36]:
array([[ 0, 2, 4],
[ 6, 8, 10],
[12, 14, 16]])
对于一维数组,其T属性就是原数组
NumPy
中,复数的虚部是用j
表示的。例如,我们可以创建一个由复数构成的数组:In [38]: b = np.array([1.j + 1, 2.j + 3])
In [39]: b
Out[39]: array([1.+1.j, 3.+2.j])
real
属性,给出复数数组的实部。如果数组中只包含实数元素,则其real
属性将输出原数组:In [40]: b.real
Out[40]: array([1., 3.])
imag
属性,给出复数数组的虚部:In [41]: b.imag
Out[41]: array([1., 2.])
In [42]: b.dtype
Out[42]: dtype('complex128')
In [43]: b.dtype.str
Out[43]: '
flat
属性将返回一个numpy.flatiter
对象, 这是获得flatiter
对象的唯一方式——我们无法访问flatiter
的构造函数。这个所谓的“扁平迭代器”可以让我们像遍历一维数组一样去遍历任意的多维数组,如下所示:In [45]: b = np.arange(4).reshape(2,2)
In [46]: f = b.flat
In [47]: f
Out[47]: <numpy.flatiter at 0x1aea0d05230>
In [49]: for item in f: print(item)
0
1
2
3
我们还可以用flatiter
对象直接获取一个数组元素:
In [50]: b.flat[2]
Out[50]: 2
或者获取多个元素:
In [51]: b.flat[[1,3]]
Out[51]: array([1, 3])
flat
属性是一个可赋值的属性。对flat
属性赋值将导致整个数组的元素都被覆盖:
In [52]: b.flat = 7
In [53]: b
Out[53]:
array([[7, 7],
[7, 7]])
还可以对flat
属性数组元素进行单独的赋值。
In [54]: b.flat[[1,3]] = 1
In [55]: b
Out[55]:
array([[7, 1],
[7, 1]])
我们可以使用tolist
函数将NumPy
数组转换成Python列表。
(1) 转换成列表:
In [57]: c = np.array([ 1.+1.j, 3.+2.j])
In [58]: c
Out[58]: array([1.+1.j, 3.+2.j])
In [59]: c.tolist()
Out[59]: [(1+1j), (3+2j)]
(2) astype
函数可以在转换数组时指定数据类型:
In [60]: c
Out[60]: array([1.+1.j, 3.+2.j])
In [61]: c.astype(int)
C:\Users\Administrator\AppData\Local\Programs\Python\Python37\Scripts\ipython:1: ComplexWarning: Casting complex values to real discards the imaginary part
Out[61]: array([1, 3])
在上面将复数转换为整数的过程中,我们丢失了复数的虚部。 astype
函数也可以接受数据类型为字符串的参数。使用正确的数据类型则不会再显示任何警告信息。
In [62]: b.astype('complex')
Out[62]:
array([[7.+0.j, 1.+0.j],
[7.+0.j, 1.+0.j]])