NumPy是一个功能强大的Python库,主要用于对多维数组执行计算。NumPy这个词来源于两个单词-- Numerical和Python。NumPy广泛用于以下任务:
机器学习模型:在编写机器学习算法时,需要对矩阵进行各种数值计算。例如矩阵乘法、换位、加法等。NumPy提供了一个非常好的库,用于简单(在编写代码方面)和快速(在速度方面)计算。NumPy数组用于存储训练数据和机器学习模型的参数。
图像处理和计算机图形学:计算机中的图像表示为多维数字数组。NumPy成为同样情况下最自然的选择。实际上,NumPy提供了一些优秀的库函数来快速处理图像。例如,镜像图像、按特定角度旋转图像等。
数学任务:NumPy对于执行各种数学任务非常有用,如数值积分、微分、内插、外推等。因此,当涉及到数学任务时,它形成了一种基于Python的MATLAB的快速替代。
(以上一段来自NumPy官方说明)
NumPy中的数据基本类型(结构)是数组,称之为ndarrays。数组有两种理解方式:
数学角度,具体来说是线性代数的角度:向量或者矩阵、
计算机的角度:同类型的“items”的列表(一维或者多维)。这里的列表与python自己的列表相比,由于存储的对象是同类型的,所以后续的处理上,效率会大大提高。
本文会从数学和计算机角度分别阐述NumPy的一些应用。
一、创建数组
NumPy创建数组有两种方式:
1、先创建一维数组,然后将其重新摆放成符合要求的多维数组:
NumPy可以接收python的列表/元组,将其转化成一维的数组。也可以通过自身的函数运算创建一维数组,例如arange函数(类似python中的range函数)、linspace(创建等差序列)等。然后通过reshape函数调整维数。
2、NumPy直接创建,通过函数、切片或者运算:
zeros/ones/random等函数可以直接创建多维数组,维数是此类函数的参数;
如果把单个数值理解为仅有一个值的1维数组,则NumPy中的运算返回的也都是数组,维数根据运算的特点来确定;
通过索引切片也可以创建数组。其中,数组索引和花式索引是建立与原数组结构一样的数组;布尔索引生成的是一维数组。
另,此处不得不提的就是轴这个概念。在NumPy中,维度称为轴。我自己想象中,轴是将1维数组(类似列表)逐层拆分的结果,每拆一次,增加一个轴。轴为1的时候,就是列表或向量;轴为2时,可以看作一个矩阵。至于这个矩阵的秩,需要结合具体的数据来计算。当轴的数量是3时,我个人的理解是多个矩阵映射的结果,也可以理解为面板数据(计量经济学的概念,pandas里面有),用正方体(三维数组)表示;轴大于等于4的时候,想象起来就比较困难了。
官方帮助的解释:
轴用来为超过一维数组定义的属性,二维数据拥有两个轴:第0轴沿着行的方向垂直向下,第1轴沿着列的方向水平延申。
轴的取值是个人理解轴以及应用轴时的一个工具。轴的顺序与shape函数里面的顺序是一致的,当数组的shape(a,b,c)时,轴有0轴,0轴的具体数值(0,1,…a-1);1轴对应的是b,依次类推。当运算中需要界定对某一轴运算时,意思就是当其他轴的值不变时,以特定轴的取值展开成一维数组来进行运算。

二、数组的基本操作
NumPy中的数组的操作有索引与切片、迭代。
1、索引与切片
索引与切片是联系在一起的,在numpy中,数组的每一个元素都有位置参数,即索引。切片就是按照位置参数将数据提取出来,并且按照一定的结构摆放。除了与python中序列的索引切片一样的操作方式之外,NumPy中还包括整数数组索引、布尔索引、花式索引。(不同的教材中的叫法稍有不同)。索引的关键就是提取哪些数据;这些数据按照什么结构展示出来。
(1)、整数数组索引
整数数组索引有两种:一维数组,多维数组。
i. 一维数组索引:分为一个一维数组索引,对第一轴的取值加以操作;多个一维数组索引,按顺序对于后续的轴加以操作。

  1. 一个一维数组索引:
import numpy as np
x=np.arange(48).reshape((4,4,3))
print(x)
 [[[ 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]
  [27 28 29]
  [30 31 32]
  [33 34 35]]

 [[36 37 38]
  [39 40 41]
  [42 43 44]
  [45 46 47]]]

print(x[[3,2,1,0]])
[[[36 37 38]
  [39 40 41]
  [42 43 44]
  [45 46 47]]

 [[24 25 26]
  [27 28 29]
  [30 31 32]
  [33 34 35]]

 [[12 13 14]
  [15 16 17]
  [18 19 20]
  [21 22 23]]

 [[ 0  1  2]
  [ 3  4  5]
  [ 6  7  8]
  [ 9 10 11]]]
  1. 多个一维数组索引:以上面的数组X为例
print(x[[3,2],[0,1]])
        [[36 37 38]
        [27 28 29]]

ii. 多维数组索引:说明:首先多维数组的结构必须一样,因为这个结构就是最后展示的结构;每一维的数组的数值就是原数组的轴的值,按照轴数取出想要的数据。

x=np.array([[0,1,2],[3,4,5],[6,7,8],[9,10,11]])
print(x)

a=np.array([[0,0,0],[3,3,3]])
b=np.array([[0,1,2],[0,1,2]])

y=x[a,b]
print(y)

程序运算结果为

[[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]]
[[ 0  1  2]
 [ 9 10 11]]

iii. 其他情况:可以借助:或 … 与索引数组组合
(2)、布尔索引: 通过布尔运算(如:比较运算符)来获取符合指定条件的元素的数组。
i. 比较运算符:

x=np.array([[0,1,2],[3,4,5],[6,7,8],[9,10,11]])
print(x)
print(x[x>5])
[ 6  7  8  9 10 11]

ii. 内置函数:

a=np.array([1,2+6j,5,3.5+5j])
print(a[np.iscomplex(a)])
[2. +6.j 3.5+5.j]

(3)、花式索引:使用ix_,后面跟与N个1维数组,并不是多维数组。N表示小于等于轴数的一个数。花式索引同时操作选择多个轴以及对于轴进行排序。N可以小于轴数,说明对于前N轴操作。

x=np.arange(48).reshape((4,4,3))
print(x)  
[[[ 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]
  [27 28 29]
  [30 31 32]
  [33 34 35]]

 [[36 37 38]
  [39 40 41]
  [42 43 44]
  [45 46 47]]]
print(x[np.ix_([1,0,3,2],[0,3,1,2],[0,2])])
[[[12 14]
  [21 23]
  [15 17]
  [18 20]]

 [[ 0  2]
  [ 9 11]
  [ 3  5]
  [ 6  8]]

 [[36 38]
  [45 47]
  [39 41]
  [42 44]]

 [[24 26]
  [33 35]
  [27 29]
  [30 32]]]

2、 迭代
NumPy 迭代器对象 numpy.nditer 提供了一种灵活访问一个或者多个数组元素的方式。迭代器最基本的任务的可以完成对数组元素的访问。
(1)、基本迭代

a=np.arange(6).reshape(2,3)
print(a)
for x in np.nditer(a):
    print(x,end=",")
[[0 1 2]
 [3 4 5]]
0,1,2,3,4,5,

(2)、控制遍历顺序
for x in np.nditer(a, order=‘F’):Fortran order,即是列序优先;
for x in np.nditer(a, order=‘C’):C order,即是行序优先;

(3)、修改数组中元素的值
nditer 对象有另一个可选参数 op_flags。 默认情况下,nditer 将视待迭代遍历的数组为只读对象(read-only),为了在遍历数组的同时,实现对数组元素值得修改,必须指定 read-write 或者 write-only 的模式。

a=np.arange(0,60,5).reshape(3,4)
print(a)

for x in np.nditer(a,op_flags=['readwrite']):
    x[...]=2*x
print(a)
[[ 0  5 10 15]
 [20 25 30 35]
 [40 45 50 55]]

[[  0  10  20  30]
 [ 40  50  60  70]
 [ 80  90 100 110]]

(4)、控制输出的形式
使用参数flags = [‘external_loop’],可以将输出的形式从0维变成1维。结合order参数,分别的结果如下:

a=np.arange(0,60,5).reshape(3,4)
print(a)
[[ 0  5 10 15]
 [20 25 30 35]
 [40 45 50 55]]

Order=’C’

for x in np.nditer(a,flags=['external_loop'],order='C'):
print(x)
[ 0  5 10 15 20 25 30 35 40 45 50 55]

Order=’F’

for x in np.nditer(a,flags=['external_loop'],order='F'):
print(x)
[ 0 20 40]
[ 5 25 45]
[10 30 50]
[15 35 55]

(5)、组合迭代:numpy.nditer可以实现组合迭代,并且将numpy中的广播功能应用其中。
普通组合:

a=np.arange(0,60,5).reshape(3,4)
b=np.arange(0,12).reshape(3,4)
for x,y in np.nditer([a,b]):
print("{0}:{1}".format(x,y))
0:0
5:1
10:2
15:3
20:4
25:5
30:6
35:7
40:8
45:9
50:10
55:11

应用了广播功能:

a=np.arange(0,60,5).reshape(3,4)
b=np.arange(0,4)

for x,y in np.nditer([a,b]):
print("{0}:{1}".format(x,y))
0:0
5:1
10:2
15:3
20:0
25:1
30:2
35:3
40:0
45:1
50:2
55:3