Python编程系列5-Numpy库

NumPy数组的优势

NumPy数组通常是由相同种类的元素组成的,既数组中的数据项的类型必须一致。

In [1]:
import numpy as np
In [2]:
a = np.arange(5)
a.dtype
Out[2]:
dtype('int64')

以上数组的数据类型为int64,除了知道数据类型之外,还要注意其形状,这一点非常重要

In [3]:
a
Out[3]:
array([0, 1, 2, 3, 4])
In [4]:
a.shape
Out[4]:
(5,)

如你所见,该向量有5个元素,他们的值分别是从0到4,该数组的shape属性是一个元组,存放的是数组在每一个维度的长度。

创建多维数组

既然我们已经知道了创建向量的方法,下面开始学习如何建设多维NumPy数组。生成矩阵后,再来看它的形状,

In [5]:
m = np.array([np.arange(2),np.arange(2)])
m
Out[5]:
array([[0, 1],
       [0, 1]])
In [6]:
m.shape
Out[6]:
(2, 2)

选择NumPy数组元素

有时,我们可能想从数组中选择指定的元素。如何做到这一点呢?不妨从创建一个2行2列的矩阵着手:

In [7]:
a = np.array([[1,2],[3,4]])

上面的矩阵是通过向array()函数传递一个由列表组成的列表得到的,接下来,我们要逐个选择矩阵的各个元素,代码如下所示。别忘了,下标是从0开始的:

In [8]:
a[0,0]
Out[8]:
1
In [9]:
a[0,1]
Out[9]:
2
In [10]:
a[1,0]
Out[10]:
3
In [11]:
a[1,1]
Out[11]:
4

可见,选择数组元素是一件非常简单的事情,对于数组a,只要通过a[m,n]的形态,就能访问数组内的元素,其中m和n为数组元素的下标。

NumPy的数值类型

Python自身虽然支持整型、浮点型和复数型,但对于科学计算来说,还远远不够。现实中,我们仍然需要更多的数据类型,来满足在精度和储存大小方面的各种不同的要求。为此,NumPy提供了更加丰富的数据类型。注意,NumPy跟数学运算有关的数据类型的名称都以数字结尾。而这个数字指示了该类型的变量所占用的二进制位数。

每一种数据类型都有相应的转换函数,如下所示:

In [12]:
float(42)
Out[12]:
42.0
In [13]:
int(42.0)
Out[13]:
42
In [14]:
bool(42)
Out[14]:
True
In [15]:
bool(0)
Out[15]:
False
In [16]:
bool(42.0)
Out[16]:
True
In [17]:
float(True)
Out[17]:
1.0
In [18]:
float(False)
Out[18]:
0.0

许多函数都带有一个指定数据类型的参数,该参数通常是可选的:

In [19]:
np.arange(7,dtype=float)
Out[19]:
array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.])

谨记:不允许把复数类型转化成整型,当你企图进行这种转换时,将会触发TypeError错误,就像下面这样:

In [20]:
float(42.0+1.j)
--------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-20-cc01ef639a6a> in <module>()
----> 1 float(42.0+1.j)

TypeError: can't convert complex to float

同样的,也不允许把复数转化成浮点数。另外,复数的分量j是其虚部的系数。

一维数组的切片与索引

一维NumPy数组的切片操作与Python列表的切片一样。下面先来定义包括0、1、2,直到8的一个数组,然后通过指定下标3到7来选择该数组的部分元素,这实际上就是提取数组中值为3到6的那些元素。

In [22]:
a = np.arange(9)
a[3:7]
Out[22]:
array([3, 4, 5, 6])

可以用下标选择元素,下标范围从0到7,并且下标每次递增2

In [23]:
a[:7:2]
Out[23]:
array([0, 2, 4, 6])

恰如使用Python那样,也可用负值下标来反转数组:

In [24]:
 a[::-1]
Out[24]:
array([8, 7, 6, 5, 4, 3, 2, 1, 0])

处理数组形态

前面,我们已经学过了reshape()函数,实际上,除了数组形状的调整外,数组的扩充也是一个经常碰到的乏味工作。比如,可以想象一下将多维数组转换成一维数组时的情形。

In [25]:
print('In:b = arange(24).reshape(2,3,4)')
b = np.arange(24).reshape(2,3,4)
print('In:b')
print(b)
In:b = arange(24).reshape(2,3,4)
In:b
[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]
In [26]:
print('In:b.ravel()')
print(b.ravel())
In:b.ravel()
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23]
In [27]:
print('In:b.flatten()')
print(b.flatten())
In:b.flatten()
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23]
In [28]:
print('In:b.shape = (6,4)')
b.shape = (6,4)
print('In:b')
print(b)
In:b.shape = (6,4)
In:b
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]
 [12 13 14 15]
 [16 17 18 19]
 [20 21 22 23]]
In [29]:
print('In:b.transpose()')
print(b.transpose())
In:b.transpose()
[[ 0  4  8 12 16 20]
 [ 1  5  9 13 17 21]
 [ 2  6 10 14 18 22]
 [ 3  7 11 15 19 23]]
In [30]:
print('In:b.resize((2,12))')
b.resize((2,12))
print('In:b')
print(b)
In:b.resize((2,12))
In:b
[[ 0  1  2  3  4  5  6  7  8  9 10 11]
 [12 13 14 15 16 17 18 19 20 21 22 23]]

拆解:可以用ravel()函数将多维数组变成一维数组

In [31]:
b.shape = (6,4)
b
Out[31]:
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]])
In [32]:
b.ravel()
Out[32]:
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])

拉直:flatten()函数的名字取得非常贴切,其功能与ravel()相同。可是,flatten()返回的是真实的数组,需要分配新的内存空间;而ravel()函数返回的只是数组的视图。这意味着,我们可以像下面这样的直接操作数组:

In [33]:
b.flatten()
Out[33]:
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])

用元组指定数组形状:除reshape()函数外,还可以用元组来轻松定义数组的形状:

转置:在线性代数中,矩阵的转置操作非常常见。转置是一种数据变换方法,对于二维表而言,转置就意味着行变成列,同时列变成行。转置也可以通过下列代码完成:

In [34]:
b.transpose()
Out[34]:
array([[ 0,  4,  8, 12, 16, 20],
       [ 1,  5,  9, 13, 17, 21],
       [ 2,  6, 10, 14, 18, 22],
       [ 3,  7, 11, 15, 19, 23]])

调整大小:函数resize()的作用类似于reshape(),但是会改变所作用的数组:

In [35]:
b.resize((2,12))
b
Out[35]:
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]])

堆叠数组

从深度看,数组既可以横向叠放,也可以竖向叠放,为此,可以使用vstack()、dstack()、hstack()、column_stack()、row_stack()和concatenate()等函数。
在此之前,我们先要建立某些数组:

In [36]:
a = np.arange(9).reshape(3,3)
a
Out[36]:
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])
In [37]:
b= 2*a
b
Out[37]:
array([[ 0,  2,  4],
       [ 6,  8, 10],
       [12, 14, 16]])

水平叠加:先介绍水平叠加方式,即用元组确定ndarrays数组的形状,然后交由hstack()函数来码放这些数组。

In [38]:
np.hstack((a,b))
Out[38]:
array([[ 0,  1,  2,  0,  2,  4],
       [ 3,  4,  5,  6,  8, 10],
       [ 6,  7,  8, 12, 14, 16]])

用concatenate()函数也能达到相同的效果。

In [39]:
np.concatenate((a,b),axis = 1)
Out[39]:
array([[ 0,  1,  2,  0,  2,  4],
       [ 3,  4,  5,  6,  8, 10],
       [ 6,  7,  8, 12, 14, 16]])

垂直叠加:使用垂直叠加方法时,先要构建一个元祖,然后将元祖交给vstack()函数来码放数组。

In [40]:
np.vstack((a,b))
Out[40]:
array([[ 0,  1,  2],
       [ 3,  4,  5],
       [ 6,  7,  8],
       [ 0,  2,  4],
       [ 6,  8, 10],
       [12, 14, 16]])

当参数axis置0时,concatenate()函数也会得到相同的效果。实际上,这是该参数的缺省值:

In [41]:
np.concatenate((a,b),axis = 0)
Out[41]:
array([[ 0,  1,  2],
       [ 3,  4,  5],
       [ 6,  7,  8],
       [ 0,  2,  4],
       [ 6,  8, 10],
       [12, 14, 16]])

深度叠加:除此之外,还有一种深度叠加方法,这要用到dstack()函数和一个元组。这种方法是沿着第三个坐标轴(纵向)的方向来叠加一摞数组。举例来说,可以在一个图像数据的二维数组上叠加另一幅图像的数据。

In [42]:
np.dstack((a,b))
Out[42]:
array([[[ 0,  0],
        [ 1,  2],
        [ 2,  4]],

       [[ 3,  6],
        [ 4,  8],
        [ 5, 10]],

       [[ 6, 12],
        [ 7, 14],
        [ 8, 16]]])

列式堆叠:columns_stack()函数以列方式对一维数组进行堆叠。

In [43]:
oned =np.arange(2)
oned
Out[43]:
array([0, 1])
In [44]:
twice_oned = 2*oned
twice_oned
Out[44]:
array([0, 2])
In [45]:
np.column_stack((oned,twice_oned))
Out[45]:
array([[0, 0],
       [1, 2]])

用这种方法堆叠二维数组时,过程类似于hstack()函数。

In [46]:
np.column_stack((a,b))
Out[46]:
array([[ 0,  1,  2,  0,  2,  4],
       [ 3,  4,  5,  6,  8, 10],
       [ 6,  7,  8, 12, 14, 16]])
In [47]:
np.column_stack((a,b)) == np.hstack((a,b))
Out[47]:
array([[ True,  True,  True,  True,  True,  True],
       [ True,  True,  True,  True,  True,  True],
       [ True,  True,  True,  True,  True,  True]], dtype=bool)

行式堆叠:同时,NumPy自然也有以行方式对数组进行堆叠的函数,这个用于一维数组的函数名为row_stack(),它将数组作为行码放到二维数组中:

In [48]:
np.row_stack((oned,twice_oned))
Out[48]:
array([[0, 1],
       [0, 2]])

对于二维数组,row_stack()函数相当于vstack()函数:

In [49]:
np.row_stack((a,b))
Out[49]:
array([[ 0,  1,  2],
       [ 3,  4,  5],
       [ 6,  7,  8],
       [ 0,  2,  4],
       [ 6,  8, 10],
       [12, 14, 16]])
In [50]:
np.row_stack((a,b)) == np.vstack((a,b))
Out[50]:
array([[ True,  True,  True],
       [ True,  True,  True],
       [ True,  True,  True],
       [ True,  True,  True],
       [ True,  True,  True],
       [ True,  True,  True]], dtype=bool)

拆分NumPy数组

可以从纵向,横向和深度方向来拆分数组,相关函数有hsplit(),vsplit(),dsplit()和split()。我们即可以把数组分成相同的形状的数组,也可以从规定的位置开始切取数组。

横向拆分:对于一个3行3列数组,可以沿着横轴方向将其分解为3部分,并且各部分的大小和形状完全一致。

In [51]:
a
Out[51]:
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])
In [52]:
np.hsplit(a,3)
Out[52]:
[array([[0],
        [3],
        [6]]), array([[1],
        [4],
        [7]]), array([[2],
        [5],
        [8]])]

这个相当于调用了参数axis = 1的split()函数:

In [53]:
np.split(a,3,axis = 1)
Out[53]:
[array([[0],
        [3],
        [6]]), array([[1],
        [4],
        [7]]), array([[2],
        [5],
        [8]])]

纵向拆分:同理

In [54]:
np.vsplit(a,3)
Out[54]:
[array([[0, 1, 2]]), array([[3, 4, 5]]), array([[6, 7, 8]])]
In [55]:
np.split(a,3,axis = 0)
Out[55]:
[array([[0, 1, 2]]), array([[3, 4, 5]]), array([[6, 7, 8]])]

深向拆分:dsplit()函数会沿着深度方向分解数组。下面以秩为3的数组为例进行说明:

In [56]:
c = np.arange(27).reshape(3,3,3)
c
Out[56]:
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 [57]:
np.dsplit(c,3)
Out[57]:
[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]]])]

NumPy数组的属性:

下面举例说明NumPy数组各种属性的详细用法。

In [58]:
b = np.arange(24).reshape(2,12)
print('In:b')
print(b)
In:b
[[ 0  1  2  3  4  5  6  7  8  9 10 11]
 [12 13 14 15 16 17 18 19 20 21 22 23]]
In [59]:
print('In:b.ndim')
print(b.ndim)
In:b.ndim
2
In [60]:
print('In:b.size')
print(b.size)
In:b.size
24
In [61]:
print('In:b.itemsize')
print(b.itemsize)
In:b.itemsize
8

 

Python编程系列目录:
1. Python编程系列1-变量、字符串与列表
2. Python编程系列2-字典、元组与集合
3. Python编程系列3-条件与循环
4. Python编程系列4-函数
当前阅读> 5. Python编程系列5-Numpy库
6. Python编程系列6-Scipy库
7. Python编程系列7-Pandas库
8. Python编程系列8-Matplotlib库

发表评论

邮箱地址不会被公开。 必填项已用*标注