1 初识NumPy
1.1 NumPy
概述NumPy(如图6.1所示),更像是一个魔方(如图6.2所示),它是Python数组计算、矩阵运算和科学计算的核心库,NumPy这个词来源于Numerical和Python两个单词的结合。NumPy提供了一个高性能的数组对象,让我们轻松创建一维数组、二维数组和多维数组,以及大量的函数和方法,帮助我们轻松地进行数组计算,从而广泛地应用于数据分析、机器学习、图像处理和计算机图形学、数学任务等领域当中。
NumPy是数据分析的三大剑客之一,它的用途是以数组的形式对数据进行操作。机器学习中充斥了大量的数组运算,而NumPy使得这些操作变得简单。由于NumPy是通过C语言实现的,所以其运算速度非常快。具体功能如下:
■ 有一个强大的N维数组对象ndarray。■ 广播功能函数。■ 线性代数、傅立叶变换、随机数生成、图形操作等功能。■ 整合C/C++/Fortran代码的工具。

1.2 安装NumPy模块
安装NumPy有以下两种方法:
1.2.1 使用pip工具安装
安装NumPy最简单的方法就是使用pip工具,安装命令如下:
pip install numpy
1.2.2 在PyCharm开发环境中安装
(1)运行PyCharm,选择File→Settings菜单项,打开“Settings”窗口,然后在“Project Interpreter”窗口中选择添加模块的按钮(+),如图6.3所示。

图6.3 选择添加模块的按钮
单击(+)按钮以后,在搜索栏输入需要添加的模块名称为“numpy”,然后选择需要安装的模块,如图6.4所示,单击“Install Package”按钮即可安装NumPy模块。

图6.4 在PyCharm开发环境中安装NumPy模块
1.2.3 安装验证
测试是否安装成功,程序代码如下:
01 from numpy import * #导入numpy库
02 print(eye(4)) #生成对角矩阵
1.3 数组的相关概念
学习NumPy前,我们先了解一下数组的相关概念。数组可分为一维数组、二维数组、三维数组,其中三维数组是常见的多维数组,如图6.5所示。

图6.5 数组示意图■ 一维数组
一维数组很简单,基本和Python列表一样,区别在于数组切片针对的是原始数组(这就意味着,如果对数组进行修改,原始数组也会跟着更改)。
■ 二维数组二维数组的本质是以数组作为数组元素。二维数组包括行和列,类似于表格形状,又称为矩阵。
■ 三维数组
三维数组是指维数为三的数组结构,也称矩阵列表。三维数组是最常见的多维数组,由于其可以用来描述三维空间中的位置或状态而被广泛使用。
■ 轴的概念
轴是NumPy模块里的axis,指定某个axis,就是沿着这个axis做相关操作,其中二维数组的两个axis的指向如图6.6所示。

图6.6 二维数组两个轴
对于一维数组,情况有点特殊,它不像二维数组从上向下地操作,而是水平的,因此一维数组其'axis=0'的指向如图6.7所示。

图6.7 一维数组一个轴
2 创建数组
2.1 创建简单的数组
NumPy创建简单的数组主要使用array函数,语法如下:
numpy.array(object,dtype=None,copy=True,order='K',subok=False,ndmin=0)
参数说明:
■ object:任何具有数组接口方法的对象。
■ dtype:数据类型。
■ copy:布尔型,可选参数,默认值为True,则object对象被复制;否则,只有当__array__方法返回副本,object参数为嵌套序列,或者需要副本满足数据类型和顺序要求时,才会生成副本。
■ order:元素在内存中的出现顺序,值为K、A、C、F。如果object参数不是数组,则新创建的数组将按行排列(C),如果值为F,则按列排列;如果object参数是一个数组,则以下内容成立:C(按行)、F(按列)、A(原顺序)、K(元素在内存中的出现顺序)。
■ subok:布尔型。如果值为True,则将传递子类,否则返回的数组将强制为基类数组(默认值)。
■ ndmin:指定生成数组的最小维数。快速示例01 演示如何创建数组
下面创建几个简单的数组,效果如图6.8所示。

图6.8 创建简单的数组
程序代码如下:
01 import numpy as np #导入numpy模块
02 n1 = np.array([1,2,3]) #创建一个简单的一维数组
03 n2 = np.array([0.1,0.2,0.3])#创建一个包含小数的一维数组
04 n3 = np.array([[1,2],[3,4]])#创建一个简单的二维数组
2.1.1 为数组指定数据类型
快速示例02 为数组指定数据类型NumPy支持比Python更多种类的数据类型,通过dtype参数可以指定数组的数据类型,程序代码如下:
01 import numpy as np #导入numpy模块
02 list = [1, 2, 3] #列表
03 #创建浮点型数组
04 n1 = np.array(list,dtype=np.float_)
05 #或者
06 n1= np.array(list,dtype=float)
07 print(n1)
08 print(n1.dtype)
09 print(type(n1[0]))
2.1.2 数组的复制
快速示例03 复制数组
当运算和处理数组时,为了不影响到原数组,就需要对原数组进行复制,而对复制后的数组进行修改和删除等操作都不会影响到原数组。数组的复制可以通过copy参数实现,程序代码如下:
01 import numpy as np #导入numpy模块
02 n1 = np.array([1,2,3]) #创建数组
03 n2 = np.array(n1,copy=True) #复制数组
04 n2[0]=3 #修改数组中的第一个元素为3
05 n2[2]=1 #修改数组中的第三个元素为1
06 print(n1)
07 print(n2)
数组n2是数组n1的副本,从运行结果得知:虽然修改了数组n2,但是数组n1没有发生变化。
2.1.3 通过ndmin参数控制最小维数
数组可分为一维数组、二维数组和多维数组,通过ndmin参数可以控制数组的最小维数。无论给出的数据的维数是多少,ndmin参数都会根据最小维数创建指定维数的数组。
【快速示例】 修改数组的维数
对于'ndmin=3',虽然给出的数组是一维的,但是同样会创建一个三维数组,程序代码如下:
01 import numpy as np
02 nd1 = [1, 2, 3]
03 nd2 = np.array(nd1, ndmin=3) #三维数组
04 print(nd2)
2.2 不同方式创建数组
2.2.1 创建指定维度和数据类型未初始化的数组
【快速示例】 创建指定维度和未初始化的数组
创建指定维度和数据类型未初始化的数组时,主要使用empty函数,程序代码如下:
01 import numpy as np
02 n = np.empty([2,3])
03 print(n)
这里的数组元素为随机值,因为它们未被初始化。如果要改变数组类型,可以使用dtype参数,如整型,'dtype=int'。
2.2.2 创建指定维度(以0填充)的数组
【快速示例】 创建指定维度(以0填充)的数组
在创建指定维度并以0填充的数组时,主要使用zeros函数,程序代码如下:
01 import numpy as np
02 n = np.zeros(3)
03 print(n)
输出结果默认是浮点型(float)。
2.2.3 创建指定维度(以1填充)的数组
【快速示例】 创建指定维度并以1填充的数组
在创建指定维度并以1填充的数组时,主要使用ones函数,程序代码如下:
01 import numpy as np
02 n = np.ones(3)
03 print(n)
2.2.4 创建指定维度和类型的数组并以指定值填充
【快速示例】 创建以指定值填充的数组
在创建指定维度和类型的数组并以指定值填充时,主要使用full函数,程序代码如下:
01 import numpy as np
02 n = np.full((3,3), 8)
03 print(n)
2.3 从数值范围创建数组
2.3.1 通过arange函数
创建数组arange函数同Python内置的range函数相似,区别在于返回值,arange函数的返回值是数组,而range函数的返回值是列表。arange函数的语法如下:
arange([start,] stop[, step,], dtype=None)
参数说明:■ start:起始值,默认值为0。■ stop:终止值(不包含)。■ step:步长,默认值为1。■ dtype:创建数组的数据类型,如果不设置数据类型,则使用输入数据的数据类型。
【快速示例】 通过数值范围创建数组
使用arange函数时,主要通过数值范围创建数组,程序代码如下:
01 import numpy as np
02 n=np.arange(1,12,2)
03 print(n)
2.3.2 使用linspace函数创建等差数列
首先简单了解一下等差数列,等差数列是指如果一个数列从第2项起,每一项与它的前一项的差等于同一个常数,那么这个数列就叫作等差数列。
例如,一般成年男鞋的各种尺码,如图6.9所示。

图6.9 男鞋尺码对照表
关于马拉松的赛前训练,一周每天的训练量(单位:m),如图6.10所示。

图6.10 训练计划
在Python中,创建等差数列可以使用NumPy的linspace函数,该函数用于创建一个一维的等差数列的数组,它与arange函数不同,arange函数是从开始值到结束值的左闭右开区间(即包括开始值,但不包括结束值),第三个参数(如果存在)是步长;而linespace函数是从开始值到结束值的闭区间(可以通过参数endpoint=False设置,使结束值不是闭区间),并且第三个参数是值的个数。
知识胶囊:本文经常会提到诸如“左闭右开区间”“左开右闭区间”“闭区间”等,这里简单介绍一下。“左闭右开区间”是指包括起始值但不包括终止值的一个数值区间;“左开右闭区间”是指不包括起始值但包括终止值的一个数值区间;“闭区间”是指既包括起始值又包括终止值的一个数值区间。linspace函数的语法如下:
linspace(start,stop,num=50,endpoint=True,retstep=False,dtype=None)
参数说明:■ start:序列的起始值。■ stop:序列的终止值,如果endpoint参数的值为True,则该值包含于数列中。■ num:要生成的等步长的样本数量,默认值为50。■ endpoint:如果值为Ture,数列中包含stop参数的值;反之则不包含,默认值为True。■ retstep:如果值为True,则生成的数组中会显示间距,反之则不显示。■ dtype:数组的数据类型。
【快速示例】 创建马拉松赛前训练的等差数列数组
创建马拉松赛前训练的等差数列数组,程序代码如下:
01 import numpy as np
02 n1 = np.linspace(7500,10000,6)
03 print(n1)
2.3.3 使用logspace函数创建等比数列
首先了解一下等比数列,等比数列是指从第二项起,每一项与它的前一项的比值等于同一个常数的一种数列。例如,在古印度,国王要重赏发明国际象棋的大臣,对他说:“我可以满足你的任何要求。”,大臣说:“请给我的棋盘的64个格子都放上小麦,第1个格子放1粒小麦,第2个格子放2粒小麦,第3个格子放4粒小麦,第4个格子放8粒小麦,如图6.11所示,后面每个格子放的小麦数都是前一个格子里放的2倍,直到第64个格子。”。

图6.11 放小麦的棋盘
在Python中,创建等比数列可以使用NumPy的logspace函数,语法如下:
numpy.logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None)
参数说明:
■ start:序列的起始值。
■ stop:序列的终止值。如果endpoint参数值为True,则该值包含于数列中。
■ num:要生成的等步长的数据样本数量,默认值为50。
■ endpoint:如果值为Ture,则数列中包含stop参数值;反之则不包含,默认值为True。
■ base:对数log的底数。
■ dtype:数组的数据类型。
【快速示例】 通过logspace函数解决棋盘放置小麦的问题
通过logspace函数计算棋盘中的每个格子里放的小麦数是前一个格子里的2倍,直到第64个格子时,每个格子里会放多少小麦,程序代码如下:
01 import numpy as np
02 n = np.logspace(0,63,64,base=2,dtype='int')
03 print(n)
运行程序,输出结果如图6.12所示。

图6.12 每个格子里放的小麦数
上述举例,出现一个问题:后面大数出现负数,而且都是一样的,这是由于程序中指定的数据类型是int,是32位的,数据范围为-2147483648~2147483647,而我们计算后的数据远远超出了这个范围,便出现了溢出现象。解决这一问题,需要指定数据类型为uint64(即无符号整数,数据范围为0~18446744073709551615),关键代码如下:
n = np.logspace(0,63,64,base=2,dtype='uint64')
运行程序,输出结果如图6.13所示。

图6.13 修改后的每个格子里放的小麦数
以上就是每一个格子里需要放的小麦数,可见发明国际象棋的大臣是多么聪明。说明:关于NumPy数据类型的详细介绍可参见6.3.1小节。
2.4 生成随机数组
随机数组的生成主要使用NumPy中的random模块,下面介绍几种常用的随机生成数组的函数。
2.4.1 rand函数
rand函数用于生成(0,1)之间的随机数组,传入一个值随机生成一维数组,传入一对值随机生成二维数组,语法如下:
numpy.random.rand(d0,d1,d2,d3....dn)
参数d0、d1…dn为整数,表示维度,可以为空。
【快速示例】 随机生成0到1之间的数组
随机生成0~1之间的一维数组和二维数组,代码如下:
01 import numpy as np
02 n=np.random.rand(5)
03 print('随机生成0到1之间的一维数组:')
04 print(n)
05 n1=np.random.rand(2,5)
06 print('随机生成0到1之间的二维数组:')
07 print(n1)
说明:此处笔者得到的结果会与读者朋友的不同,属于正常情况。
2.4.2 randn函数
randn函数用于从正态分布中返回随机生成的数组,语法如下:
numpy.random.randn(d0,d1,d2,d3....dn)
参数d0、d1…dn为整数,表示维度,可以为空。
【快速示例】 随机生成满足正态分布的数组
在随机生成满足正态分布的数组时,程序代码如下:
01 import numpy as np
02 n1=np.random.randn(5)
03 print('随机生成满足正态分布的一维数组:')
04 print(n1)
05 n2=np.random.randn(2,5)
06 print('随机生成满足正态分布的二维数组:')
07 print(n2)
2.4.3 randint函数
randint函数与NumPy中的arange函数类似。randint函数用于生成一定范围内的随机数组,左闭右开区间,语法如下:
numpy.random.randint(low,high=None,size=None)
参数说明:■ low:低值(起始值),整数,且当参数high不为空时,参数low应小于参数high,否则程序会出现错误。■ high:高值(终止值),整数。■ size:数组维数,整数或者元组,整数表示一维数组,元组表示多维数组。默认值为空,如果为空,则仅返回一个整数。
【快速示例】 生成一定范围内的随机数组
在生成一定范围内的随机数组时,程序代码如下:
01 import numpy as np
02 n1=np.random.randint(1,3,10)
03 print('随机生成10个1到3之间且不包括3的整数:')
04 print(n1)
05 n2=np.random.randint(5,10)
06 print('size数组大小为空随机返回一个整数:')
07 print(n2)
08 n3=np.random.randint(5,size=(2,5))
09 print('随机生成5以内二维数组')
10 print(n3)
2.4.4 normal函数
normal函数用于生成正态分布的随机数,语法如下:
numpy.random.normal(loc,scale,size)
参数说明:■ loc:正态分布的均值,对应正态分布的中心。'loc=0'说明是一个以y轴为对称轴的正态分布。■ scale:正态分布的标准差,对应正态分布的宽度,scale值越大,正态分布的曲线越矮胖;scale值越小,曲线越高瘦。■ size:表示数组维数。
【快速示例】 生成正态分布的随机数组
生成正态分布的随机数组,程序代码如下:
01 import numpy as np
02 n = np.random.normal(0, 0.1, 10)
03 print(n)
2.5 从已有的数组中创建数组
2.5.1 asarray函数
asarray函数用于创建数组,其与array函数类似,语法如下:
numpy.asarray(a,dtype=None,order=None)
参数说明:■ a:可以是列表、列表的元组、元组、元组的元组、元组的列表或多维数组。■ dtype:数组的数据类型。■ order:值为“C”和“F”,分别代表按行排列和按列排列,即数组元素在内存中的出现顺序。
【快速示例】 使用asarray函数创建数组
使用asarray函数创建数组,程序代码如下:
01 import numpy as np #导入numpy模块
02 n1 = np.asarray([1,2,3]) #通过列表创建数组
03 n2 = np.asarray([(1,1),(1,2)]) #通过列表的元组创建数组
04 n3 = np.asarray((1,2,3)) #通过元组创建数组
05 n4= np.asarray(((1,1),(1,2),(1,3))) #通过元组的元组创建数组
06 n5 = np.asarray(([1,1],[1,2])) #通过元组的列表创建数组
07 print(n1)
08 print(n2)
09 print(n3)
10 print(n4)
11 print(n5)
2.5.2 frombuffer函数
NumPy中的ndarray数组对象不能像Python列表一样动态地改变其大小,因为在做数据采集时很不方便。下面介绍如何通过frombuffer函数实现动态数组。frombuffer函数接受buffer输入参数,以流的形式将读入的数据转换为数组。frombuffer函数的语法如下:
numpy.frombuffer(buffer,dtype=float,count=-1,offset=0)
参数说明:■ buffer:实现了__buffer__方法的对象。■ dtype:数组的数据类型。■ count:读取的数据数量,默认值为-1,表示读取所有数据。■ offset:读取的起始位置,默认值为0。快速示例17 将字符串“mingrisoft”转换为数组
将字符串“mingrisoft”转换为数组,程序代码如下:
01 import numpy as np
02 n=np.frombuffer(b'mingrisoft',dtype='S1')
03 print(n)
关键代码解析:
当buffer参数值为字符串时,Python 3版本默认字符串是Unicode类型,所以要转换成Byte string类型,需要在原字符串前加上b。
2.5.3 fromiter函数
fromiter函数用于从可迭代对象中建立数组对象,语法如下:
numpy.fromiter(iterable,dtype,count=-1)
参数说明:■ iterable:可迭代对象。■ dtype:数组的数据类型。■ count:读取的数据数量,默认值为-1,表示读取所有数据。
【快速示例】 通过可迭代对象创建数组
通过可迭代对象创建数组,程序代码如下:
01 import numpy as np
02 iterable = (x * 2 for x in range(5)) #遍历0~5并乘以2,返回可迭代对象
03 n = np.fromiter(iterable, dtype='int') #通过可迭代对象创建数组
04 print(n)
2.5.4 empty_like函数
empty_like函数用于创建一个与给定数组具有相同维度和数据类型且未初始化的数组,语法如下:
numpy.empty_like(prototype,dtype=None,order='K',subok=True)
参数说明:■ prototype:给定的数组。■ dtype:覆盖结果的数据类型。■ order:指定数组的内存布局。C(按行)、F(按列)、A(原顺序)、K(数据元素在内存中的出现顺序)。■ subok:默认情况下,返回的数组被强制为基类数组。如果值为True,则返回子类。
【快速示例】 创建未初始化的数组
下面使用empty_like函数创建一个与给定数组具有相同维数、数据类型以及未初始化的数组,程序代码如下:
01 import numpy as np
02 n = np.empty_like([[1, 2], [3, 4]])
03 print(n)
2.5.5 zeros_like函数
【快速示例】 创建以0填充的数组zeros_like函数用于创建一个与给定数组维度和数据类型相同,并以0填充的数组,程序代码如下:
01 import numpy as np
02 n = np.zeros_like([[0.1,0.2,0.3], [0.4,0.5,0.6]])
03 print(n)
2.5.6 ones_like函数
【快速示例】 创建以1填充的数组ones_like函数用于创建一个与给定数组维度和数据类型相同,并以1填充的数组,程序代码如下:
01 import numpy as np
02 n = np.ones_like([[0.1,0.2,0.3], [0.4,0.5,0.6]])
03 print(n)
2.5.7 full_like函数
full_like函数用于创建一个与给定数组维度和数据类型相同,并以指定值填充的数组,语法如下:
numpy.full_like(a, fill_value, dtype=None, order='K', subok=True)
参数说明:■ a:给定的数组。■ fill_value:填充值。■ dtype:数组的数据类型,默认值为None,则使用给定数组的数据类型。■ order:指定数组的内存布局。C(按行)、F(按列)、A(原顺序)、K(数组元素在内存中的出现顺序)。
■ subok:默认情况下,返回的数组被强制为基类数组。如果值为True,则返回子类。
【快速示例】 创建以指定值“0.2”填充的数组
创建一个与给定数组维度和数据类型相同,以指定值“0.2”填充的数组,程序代码如下:
01 import numpy as np
02 a = np.arange(6) #创建一个数组
03 print(a)
04 n1 = np.full_like(a, 1) #创建一个与数组a维度和数据类型相同的数组,以1填充
05 n2 = np.full_like(a,0.2) #创建一个与数组a维度和数据类型相同的数组,以0.2填充
06 #创建一个与数组a维度和数据类型相同的数组,以0.2填充,浮点型
07 n3 = np.full_like(a, 0.2, dtype='float')
08 print(n1)
09 print(n2)
10 print(n3)
3 数组的基本操作
3.1 数组的数据类型
在对数组进行基本操作前,首先了解一下NumPy的数据类型。NumPy的数据类型比Python数据类型增加了更多种类的数值类型,如表6.1所示,为了区别于Python的数据类型,像bool、int、float、complex等数据类型的名称末尾都加了短下划线“_”。
表6.1 NumPy的数据类型及描述

每一种数据类型都有相应的数据转换函数。举例如下:
np.int8(3.141)
结果为:3。
np.float64(8)
结果为:8.0。
np.float(True)
结果为:1.0。
bool(1)
结果为:True。
在创建ndarray数组时,可以直接指定数值类型,关键代码如下:
a = np.arange(8, dtype=float)
结果为:[0. 1. 2. 3. 4. 5. 6. 7.]
注意:复数不能转换成为整数类型或者浮点数,例如,下面的代码会出现错误提示:float(8+ 1j)
3.2 数组运算
不用编写循环即可对数据执行批量运算,这就是NumPy数组运算的特点,NumPy称之为矢量化。大小相等的数组之间的任何算术运算,通过NumPy都可以实现。本节主要介绍简单的数组运算,如加、减、乘、除、幂运算等。下面创建两个简单的NumPy数组n1和n2,数组n1包括元素1、2;数组n2包括元素3、4,如图6.14所示,接下来实现这两个数组的运算。

图6.14 数组示意图

图6.15 数组加法运算示意图
3.2.1 加法运算
加法运算是数组中对应位置的元素相加(即每行对应相加),如图6.15所示。
【快速示例】 实现数组加法运算
在程序中直接将两个数组相加即可,即n1+n2,程序代码如下:
01 import numpy as np
02 n1=np.array([1,2]) #创建一维数组
03 n2=np.array([3,4])
04 print(n1+n2) #加法运算
3.2.2 减法和乘、除法运算
除了加法运算,还可以实现数组的减法、乘法和除法,如图6.16所示。

图6.16 数组减法和乘、除法运算示意图
【快速示例】 实现数组的减法和乘、除法运算
实现数组的减法和乘、除法运算,在程序中直接将两个数组相减、相乘或相除即可,程序代码如下:
01 import numpy as np
02 n1=np.array([1,2]) #创建一维数组
03 n2=np.array([3,4])
04 print(n1-n2) #减法运算
05 print(n1*n2) #乘法运算
06 print(n1/n2) #除法运算
3.2.3 幂运算
幂是数组中对应位置元素的幂运算,用两个“*”表示,如图6.17所示。

图6.17 数组幂运算示意图
【快速示例】 实现数组的幂运算
从图中得知:数组n1的元素1和数组n2的元素3,通过幂运算得到的是1的3次幂;数组n1的元素2和数组n2的元素4,通过幂运算得到的是2的4次幂,程序代码如下:
01 import numpy as np
02 n1=np.array([1,2]) #创建一维数组
03 n2=np.array([3,4])
04 print(n1**n2) #幂运算
3.2.4 比较运算
【快速示例】 实现数组的比较运算
数组的比较运算是数组中对应位置元素的比较运算,比较后的结果是布尔值数组,程序代码如下:
01 import numpy as np
02 n1=np.array([1,2]) #创建一维数组
03 n2=np.array([3,4])
04 print(n1>=n2) #大于或等于
05 print(n1==n2) #等于
06 print(n1<=n2) #小于或等于
07 print(n1!=n2) #不等于
3.2.5 数组的标量运算
首先了解两个概念,即标量和向量。标量其实就是一个单独的数;而向量是一组数,这组数是顺序排列的,这里我们理解为数组。那么,数组的标量运算也可以理解为是向量与标量之间的运算。例如,马拉松赛前训练,在一周里每天的训练量以“米”(m)为单位,下面将其转换为以“公里”为单位的形式,如图6.18所示。

图6.18 数组的标量运算示意图
【快速示例】 实现数组的标量运算
在程序中,“米”转换为“公里”时直接输入n1/1000即可,程序代码如下:
01 import numpy as np
02 n1 = np.linspace(7500,10000,6,dtype='int') #创建等差数列数组
03 print(n1) #输出数组
04 print(n1/1000) #“米”转换为“公里”
上述运算过程,在NumPy中叫作“广播机制”,它是一个非常有用的功能。
3.3 数组的索引和切片
NumPy数组元素是通过数组的索引和切片来访问和修改的,因此索引和切片是NumPy中最重要、最常用的操作。
3.3.1 索引
所谓数组的索引,即用于标记数组当中对应元素的唯一数字,从0开始,即数组中的第一个元素的索引是0,依次类推。NumPy数组可以使用标准Python语法x[obj]的语法对数组进行索引,其中x是数组,obj是索引。
【快速示例】 获取一维数组中的元素
获取一维数组n1中的索引为0的元素,程序代码如下:
01 import numpy as np
02 n1=np.array([1,2,3]) #创建一维数组
03 print(n1[0]) #输出一维数组的第一个元素
【快速示例】 获取二维数组中的元素
再举一个例子,通过索引获取二维数组中的元素,程序代码如下:
01 import numpy as np
02 n1=np.array([[1,2,3],[4,5,6]]) #创建二维数组
03 print(n1[1][2]) #输出二维数组中第2行第3列的元素
3.3.2 切片式索引
数组的切片可以理解为对数组的分割,按照等分或者不等分,将一个数组切割为多个片段,它与Python中列表的切片操作一样。NumPy中的切片用冒号分隔切片,参数来进行切片操作,语法如下:
[start:stop:step]
参数说明:■ start:起始索引。■ stop:终止索引。■ step:步长。快速示例30 实现简单的数组切片式操作
实现简单的切片操作,对数组n1进行切片式的索引操作,如图6.19所示。

图6.19 切片式索引示意图
程序代码如下:
01 import numpy as np
02 n1=np.array([1,2,3]) #创建一维数组
03 print(n1[0]) #输出第1个元素
04 print(n1[1]) #输出第2个元素
05 print(n1[0:2]) #输出第1个元素至第3个元素(不包括第3个元素)
06 print(n1[1:]) #输出从第2个元素开始以后的元素
07 print(n1[:2]) #输出第1个元素(0省略)至第3个元素(不包括第3个元素)
切片式索引操作需要注意以下几点:
(1)索引是左闭右开区间,如上述代码中的n1[0:2],只能获取到索引从0到1的元素,而获取不到索引为2的元素。
(2)当没有start参数时,代表从索引0开始取数,如上述代码中的n1[:2]。
(3)start、stop和step 3个参数都可以是负数,代表反向索引。以step参数为例,如图6.20所示。

图 6.20 反向索引示意图
【快速示例】 常用的切片式索引操作
设置常用的切片式索引操作,程序代码如下:
01 import numpy as np
02 n = np.arange(10) #使用arange函数创建一维数组
03 print(n) #输出一维数组
04 print(n[:3]) #输出第1个元素(0省略)至第4个元素(不包括第4个元素)
05 print(n[3:6]) #输出第4个元素至第7个元素(不包括第7个元素)
06 print(n[6:]) #输出第7个元素至最后一个元素
07 print(n[::]) #输出所有元素
08 print(n[:]) #输出第1个元素至最后一个元素
09 print(n[::2]) #输出步长是2的元素
10 print(n[1::5]) #输出第2个元素至最后一个元素且步长是5的元素
11 print(n[2::6]) #输出第3个元素至最后一个元素且步长是6的元素
12 #start、stop、step参数为负数时
13 print(n[::-1]) #输出所有元素且步长是-1的元素
14 print(n[:-3:-1]) #输出倒数第3个元素至倒数第1个元素(不包括倒数第3个元素)
15 print(n[-3:-5:-1]) #输出倒数第3个元素至倒数第5个元素且步长是-1的元素
16 print(n[-5::-1]) #输出倒数第5个元素至最后一个元素且步长是-1的元素
3.3.3 二维数组索引
二维数组索引可以使用参数array[n,m]的方式,以逗号分割,表示第n个数组的中的第m个元素。
【快速示例】 二维数组的简单索引操作
创建一个3行4列的二维数组,实现简单的索引操作,效果如图6.21所示。

图6.21 二维数组索引示意图
程序代码如下:
01 import numpy as np
02 #创建3行4列的二维数组
03 n=np.array([[0,1,2,3],[4,5,6,7],[8,9,10,11]])
04 print(n[1]) #输出第2行的元素
05 print(n[1,2]) #输出第2行第3列的元素
06 print(n[-1]) #输出倒数第1行的元素
上述代码中,n[1]表示第2个数组;n[1,2]表示第2个数组第3个元素,它等同于n[1][2],表示数组n中第2行第3列的值。实际上n[1][2]是先索引的第一个维度得到一个数组,然后在此基础上再索引。
3.3.4 二维数组切片式索引
【快速示例】 二维数组的切片式操作
创建一个二维数组,实现各种切片式索引操作,效果如图6.22所示。

图6.22 二维数组切片式索引示意图
程序代码如下:
01 import numpy as np
02 #创建3行3列的二维数组
03 n=np.array([[1,2,3],[4,5,6],[7,8,9]])
04 print(n[:2,1:]) #输出第1行至第3行(不包括第3行)的第2列至最后一列的元素
05 print(n[1,:2]) #输出第2行的第1列至第3列(不包括第3列)的元素
06 print(n[:2,2]) #输出第1行至第3行(不包括第3行)的第3列的元素
07 print(n[:,:1]) #输出所有行的第1列至第2列(不包括第2列)的元素
3.4 数组重塑
数组重塑实际是更改数组的形状,例如,将原来2行3列的数组重塑为3行4列的数组。在NumPy中主要使用reshape方法,该方法用于改变数组的形状。
3.4.1 一维数组重塑
一维数组重塑就是将数组重塑为多行多列的数组。
【快速示例】 将一维数组重塑为二维数组
创建一个一维数组,然后通过reshape方法将其改为2行3列的二维数组,程序代码如下:
01 import numpy as np
02 n=np.arange(6) #创建一维数组
03 print(n)
04 n1=n.reshape(2,3) #将数组重塑为2行3列的二维数组
05 print(n1)
需要注意的是,数组重塑是基于数组元素不发生改变的情况下实现的,重塑后的数组所包含的元素个数必须与原数组的元素个数相同,如果数组元素发生改变,程序就会报错。
【快速示例】 将一行古诗转换为4行5列的二维数组
将一行20列的数据转换为4行5列的二维数组,效果如图6.23所示。

图6.23 数组重塑示意图
程序代码如下:
01 import numpy as np
02 n=np.array(['床','前','明','月','光','疑','是','地','上','霜','举','头','望','明','月', '低','头','思','故','乡'])
03 n1=n.reshape(4,5) #将数组重塑为4行5列的二维数组
04 print(n1)
3.4.2 多维数组重塑
多维数组重塑同样使用reshape方法。
【快速示例】 将2行3列的数组重塑为3行2列的数组
将2行3列的二维数组重塑为3行2列的二维数组,程序代码如下:
01 import numpy as np
02 n=np.array([[0,1,2],[3,4,5]]) #创建二维数组
03 print(n)
04 n1=n.reshape(3,2) #将数组重塑为3行2列的二维数组
05 print(n1)
3.4.3 数组转置
数组转置是指数组的行列转换,可以通过数组的T属性和transpose函数实现。
【快速示例】 将二维数组中的行列转置
通过T属性将4行6列的二维数组中的行变成列,列变成行,程序代码如下:
01 import numpy as np
02 n = np.arange(24).reshape(4,6) #创建4行6列的二维数组
03 print(n)04 print(n.T) #T属性行列转置
【快速示例】 转换客户销售数据
上述举例可能不太直观,下面再举一个例子,实现转换客户销售数据,对比效果如图6.24所示。

图6.24 客户销售数据转换对比示意图
程序代码如下:
01 import numpy as np
02 n = np.array([['A',100],['B',200],['C',300],['D',400],['E',500]])
03 print(n)
04 print(n.T) #T属性行列转置
transpose函数也可以实现数组转置。例如,上述举例用transpose函数实现,关键代码如下:
01 n = np.array([['A',100],['B',200],['C',300],['D',400],['E',500]])
02 print(n.transpose()) #使用transpose函数行列转置
3.5 数组的增、删、改、查
数组增、删、改、查的方法有很多种,下面介绍几种常用的方法。
3.5.1 数组的增加
数组数据的增加可以按照水平方向增加数据,也可以按照垂直方向增加数据。水平方向增加数据主要使用hstack函数,垂直方向增加数据主要使用vstack函数。
【快速示例】 为数组增加数据
创建两个二维数组,然后实现数组数据的增加,程序代码如下:
01 import numpy as np
02 #创建二维数组
03 n1=np.array([[1,2],[3,4],[5,6]])
04 n2=np.array([[10,20],[30,40],[50,60]])
05 print(np.hstack((n1,n2))) #水平方向增加数据
06 print(np.vstack((n1,n2))) #垂直方向增加数据
3.5.2 数组的删除
数组的删除主要使用delete方法。
【快速示例】 删除指定的数组
实现删除指定的数组,程序代码如下:
01 import numpy as np
02 #创建二维数组
03 n1=np.array([[1,2],[3,4],[5,6]])
04 print(n1)
05 n2=np.delete(n1,2,axis=0) #删除第3行
06 n3=np.delete(n1,0,axis=1) #删除第1列
07 n4=np.delete(n1,(1,2),0) #删除第2行和第3行
08 print('删除第3行后的数组:','\n',n2)
09 print('删除第1列后的数组:','\n',n3)
10 print('删除第2行和第3行后的数组:','\n',n4)
那么,对于不想要的数组或数组元素,还可以通过索引和切片方法只选取需要的数组或数组元素。
3.5.3 数组的修改
当修改数组或数组元素时,直接为数组或数组元素赋值即可。
【快速示例】 修改指定的数组
想要修改指定的数组,程序代码如下:
01 import numpy as np
02 #创建二维数组
03 n1=np.array([[1,2],[3,4],[5,6]])
04 print(n1)
05 n1[1]=[30,40] #修改第2行数组[3,4]为[30,40]
06 n1[2][1]=88 #修改第3行第2个元素6为88
07 print('修改后的数组:','\n',n1)
3.5.4 数组的查询
数组的查询同样可以使用索引和切片方法来获取指定范围的数组或数组元素,还可以通过where函数查询符合条件的数组或数组元素。where函数的语法如下:
numpy.where(condition,x,y)
上述语法,第一个参数为一个布尔数组,第二个参数和第三个参数可以是标量也可以是数组。满足条件(参数condition),输出参数x;不满足条件则输出参数y。
【 快速示例】 按指定条件查询数组
数组查询,大于5输出2,不大于5输出0,程序代码如下:
01 import numpy as np
02 n1 = np.arange(10) #创建一个一维数组
03 print(n1)
04 print(np.where(n1>5,2,0)) #大于5输出2,不大于5输出0
如果不指定参数x和y,则输出满足条件的数组元素的坐标。例如,上述举例不指定参数x和y,关键代码如下:
01 n2=n1[np.where(n1>5)]
02 print(n2)

