文章目录
1 Numpy简介
NumPy是Python的一个扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。
NumPy用于数组计算,通常与SciPy和Matplotlib一起使用。
2 Numpy安装
从Python官网下载的Python程序,安装在电脑上后,内部的模块中没有Numpy,需要自己去安装。
在WIN10电脑打开的情况下,同时按Windows键和R键,在对话框输入cmd,按确定后打开cmd命令行,输入:
pip install numpy
通常下载较慢,安装好Numpy后的显示内容为:
打开Python解释器,输入下面内容
>>> import numpy as np
>>> np.eye(3)
array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
和下面的图片显示一样就是成功了。eye(4)生成的是对角矩阵:
3 Ndarray对象
N维数组对象ndarray,是一系列同类型数据的集合,用于存放同类型元素的多维数组。创建一个ndarray只需调用NumPy的array函数即可:
numpy.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0)
参数说明:
名称 | 描述 |
---|---|
object | 数组或嵌套的数列 |
dtype | 数组元素的数据类型,可选 |
copy | 对象是否需要复制,可选 |
order | 创建数组的样式,C为行方向,F为列方向,A为任意方向(默认) |
subok | 默认返回一个与基类类型一致的数组 |
ndmin | 指定生成数组的最小维度 |
下面是一些示例代码:
>>> import numpy as np
>>> a = np.array([1,2,3])
>>> print(a)
[1 2 3]
>>>
>>> a = np.array([[1,2],[3,4]]) # 二维数组
>>> print(a)
[[1 2]
[3 4]]
>>>
>>> a = np.array([1,2,3],dtype=complex)
>>> print(a)
[1.+0.j 2.+0.j 3.+0.j]
ndarray对象由计算机内存的连续一维部分组成,并结合索引模式,将每个元素映射到内存块中的一个位置。内存块以行顺序或列顺序来保存元素。
4 NumPy数据类型
下表列举了常用NumPy基本类型:
名称 | 描述 |
---|---|
bool_ | 布尔型数据类型(True或者False) |
int_ | 默认的整数类型(类似于C语言中的long,int32或int64) |
int8 | 字节(-128to127) |
uint8 | 无符号整数(0to255) |
float16 | 半精度浮点数,包括:1个符号位,5个指数位,10个尾数位 |
数据类型对象(numpy.dtype类的实例)用来描述与数组对应的内存区域是如何使用,示例代码片段:
import numpy as np
dt=np.dtype(np.int32)
print(dt)
输出:
int32
这里省略了很多内容,点击这里查看。
5 数组属性
NumPy的数组中比较重要的ndarray对象属性有:
属性 | 说明 |
---|---|
ndarray.ndim | 秩,即维度的数量 |
ndarray.shape | 数组的维度,如对于矩阵就是n行m列 |
ndarray.size | 数组元素的总个数,相当于.shape中n*m的值 |
ndarray.dtype | ndarray对象的元素类型 |
ndarray.itemsize | ndarray对象中每个元素的大小,以字节为单位 |
ndarray.flags | ndarray对象的内存信息 |
ndarray.real | ndarray元素的实部 |
ndarray.imag | ndarray元素的虚部 |
示例代码如下:
import numpy as np
a=np.array([[1,2],[3,4]])
print(a.ndim)
输出:
2
ndarray.shape表示数组的维度,返回一个元组,这个元组的长度就是维度的数目,即ndim属性(秩)。比如,一个二维数组,其维度表示"行数"和"列数"。ndarray.shape可以用于调整数组大小,另外也可以使用reshape函数来调整数组大小。
>>> import numpy as np
>>>
>>> a=np.array([[1,2,3],[3,4,6]])
>>> print('数组维度如下:')
数组维度如下:
>>> print(a.shape)
(2, 3)
>>>
>>> a.shape=(3,2)
>>> print('调整为三行两列:')
调整为三行两列:
>>> print(a)
[[1 2]
[3 3]
[4 6]]
>>>
>>> b=a.reshape(2,3)
>>> b #又变回来了
array([[1, 2, 3],
[3, 4, 6]])
6 创建数组
numpy.zeros创建指定大小的数组,数组元素以0来填充:
numpy.zeros(shape,dtype=float,order='C')
参数说明:
参数 | 描述 |
---|---|
shape | 数组形状 |
dtype | 数据类型,可选 |
order | 'C’用于C的行数组,或者’F’用于FORTRAN的列数组 |
示例代码如下:
import numpy as np
x=np.zeros((3,2)) #默认为浮点数
print(x)
输出:
[[0. 0.]
[0. 0.]
[0. 0.]]
numpy.ones创建指定形状的数组,数组元素以1来填充:
numpy.ones(shape,dtype=None,order='C')
示例代码如下:
import numpy as np
x=np.ones((3,2),dtype=int) #默认为浮点数,这里修改参数为int型
print(x)
输出:
[[1 1]
[1 1]
[1 1]]
可以从已有的数组创建ndarray数组。
>>> import numpy as np
>>>
>>> a=np.array([3,4,5])
>>> a
array([3, 4, 5])
numpy使用arange函数创建数值范围并返回ndarray对象,函数格式如下:
numpy.arange(start,stop,step,dtype)
参数说明:
参数 | 描述 |
---|---|
start | 起始值,默认为0 |
stop | 终止值(不包含该值) |
step | 步长,默认为1 |
dtype | 返回ndarray的数据类型,如果没有提供,则会使用输入数据的类型。 |
示例代码如下:
>>> import numpy as np
>>>
>>> x=np.arange(5)
>>> print(x)
[0 1 2 3 4]
设置返回类型位float:
>>> import numpy as np
>>>
>>> x=np.arange(5,dtype=float)
>>> print(x)
[0. 1. 2. 3. 4.]
设置起始值、终止值及步长:
>>> import numpy as np
>>>
>>> x=np.arange(1,10,2)
>>> print(x)
[1 3 5 7 9]
numpy.linspace函数用于创建一个一维数组,数组是一个等差数列构成的,格式如下:
np.linspace(start,stop,num=50,endpoint=True,retstep=False,dtype=None)
参数说明:
参数 | 描述 |
---|---|
start | 序列的起始值 |
stop | 序列的终止值,如果endpoint为true,该值包含于数列中 |
num | 要生成的等步长的样本数量,默认为50 |
endpoint | 该值为true时,数列中包含stop值,反之不包含,默认是True。 |
retstep | 如果为True时,生成的数组中会显示间距,反之不显示。 |
dtype | ndarray的数据类型 |
以下实例用到三个参数,设置起始点为4,终止点为20,数列个数为5:
>>> import numpy as np
>>>
>>> x=np.linspace(4,20,5)
>>> print(x)
[ 4. 8. 12. 16. 20.]
将endpoint设为false,不包含终止值:
>>> import numpy as np
>>>
>>> x=np.linspace(4,20,4,endpoint=False)
>>> print(x)
[ 4. 8. 12. 16.]
numpy.logspace函数用于创建一个等比数列。格式如下:
np.logspace(start,stop,num=50,endpoint=True,base=10.0,dtype=None)
base参数意思是取对数的时候log的下标。
参数 | 描述 |
---|---|
start | 序列的起始值为:base的start次方,即base^start |
stop | 序列的终止值为:base^stop。如果endpoint为true,该值包含于数列中 |
num | 要生成的等步长的样本数量,默认为50 |
endpoint | 该值为true时,数列中中包含stop值,反之不包含,默认是True。 |
base | 对数log的底数。 |
dtype | ndarray的数据类型 |
示例代码如下:
>>> import numpy as np
>>>
>>> x=np.logspace(1,2,num=10) #默认底数是10
>>> print(x)
[ 10. 12.91549665 16.68100537 21.5443469 27.82559402
35.93813664 46.41588834 59.94842503 77.42636827 100. ]
将对数的底数设置为2:
>>> import numpy as np
>>>
>>> x=np.logspace(0,9,10,base=2)
>>> print(x)
[ 1. 2. 4. 8. 16. 32. 64. 128. 256. 512.]
7 切片和索引
ndarray对象的内容可以通过索引或切片来访问和修改,与Python中list的切片操作一样。ndarray数组可以基于0-n的下标进行索引,切片对象可以从原数组中切割出一个新数组。示例代码如下:
>>> import numpy as np
>>>
>>> x=np.arange(10)
>>> print(x)
[0 1 2 3 4 5 6 7 8 9]
>>> print(x[2:7])
[2 3 4 5 6]
多维数组同样适用上述索引提取方法:
>>> import numpy as np
>>>
>>> a=np.array([[1,2],[3,4],[5,6]])
>>> print('从数组索引a[1:]处开始切割')
从数组索引a[1:]处开始切割
>>> print(a[1:])
[[3 4]
[5 6]]
NumPy除了用整数和切片的索引外,还有整数数组索引、布尔索引及花式索引。
7.1 整数数组索引
以下实例获取数组中(0,0),(1,1)和(2,0)位置处的元素。
import numpy as np
x=np.array([[1,2],[3,4],[5,6]])
y=x[[0,1,2],[0,1,0]]
print(y)
输出:
[1 4 5]
以下实例获取了4×3数组中的四个角的元素。行索引是[0,0]和[3,3],而列索引是[0,2]和[0,2]。
import numpy as np
x=np.array([[0,1,2],[3,4,5],[6,7,8],[9,10,11]])
print('原始数组为:')
print(x)
print('------')
rows=np.array([[0,0],[3,3]])
cols=np.array([[0,2],[0,2]])
y=x[rows,cols]
print('该数组的四个角元素为:')
print(y)
输出:
原始数组为:
[[ 0 1 2]
[ 3 4 5]
[ 6 7 8]
[ 9 10 11]]
------
该数组的四个角元素为:
[[ 0 2]
[ 9 11]]
可以借助切片:
与索引数组组合。如下面例子:
import numpy as np
x=np.array([[0,1,2],[3,4,5],[6,7,8],[9,10,11]])
print('原始数组为:')
print(x)
print('------')
y=x[1:3,2] #行号是1、2,不包括3,列号是2
print(y)
输出:
原始数组为:
[[ 0 1 2]
[ 3 4 5]
[ 6 7 8]
[ 9 10 11]]
------
[5 8]
7.2 布尔索引
可以通过一个布尔数组来索引目标数组:布尔索引通过布尔运算(如比较运算符)来获取符合指定条件的元素的数组。
import numpy as np
x=np.array([[0,1,2],[3,4,5],[6,7,8],[9,10,11]])
print('原始数组为:')
print(x)
print('------')
print('大于5的元素是:')
print(x[x>5])
输出:
原始数组为:
[[ 0 1 2]
[ 3 4 5]
[ 6 7 8]
[ 9 10 11]]
------
大于5的元素是:
[ 6 7 8 9 10 11]
以下实例演示如何从数组中过滤掉非复数元素:
import numpy as np
x=np.array([1,2+6j,5,3+5j])
print(x[np.iscomplex(x)])
输出:
[2.+6.j 3.+5.j]
7.3 花式索引
花式索引的名称和概念都很迷,不做详细介绍,明白怎么用就行,花式索引跟切片不一样,它总是将数据复制到新数组中。
1、传入顺序索引数组
import numpy as np
x=np.arange(32).reshape((8,4))
print('原始数组为:')
print(x)
print('------')
print(x[[4,2,1,7]])
输出:
原始数组为:
[[ 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]]
------
[[16 17 18 19]
[ 8 9 10 11]
[ 4 5 6 7]
[28 29 30 31]]
2、传入倒序索引数组
import numpy as np
x=np.arange(32).reshape((8,4))
print('原始数组为:')
print(x)
print('------')
print(x[[-4,-2,-1,-7]])
输出:
原始数组为:
[[ 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]]
------
[[16 17 18 19]
[24 25 26 27]
[28 29 30 31]
[ 4 5 6 7]]
3、传入多个索引数组(要使用np.ix_)
import numpy as np
x=np.arange(32).reshape((8,4))
print('原始数组为:')
print(x)
print('------')
print(x[np.ix_([1,5,7,2],[0,3,1,2])])
输出:
原始数组为:
[[ 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]]
------
[[ 4 7 5 6]
[20 23 21 22]
[28 31 29 30]
[ 8 11 9 10]]
8 广播
广播(Broadcast)是numpy对不同形状(shape)的数组进行数值计算的方式,对数组的算术运算通常在相应的元素上进行。如果两个数组a和b形状相同,即满足a.shape==b.shape,那么a*b的结果就是a与b数组对应位相乘。这要求维数相同,且各维度的长度相同。
import numpy as np
a=np.array([1,2,3,4])
b=np.array([10,20,30,40])
c=a*b
print(c)
输出:
[ 10 40 90 160]
当运算中的2个数组的形状不同时,numpy将自动触发广播机制。如:
import numpy as np
x=np.array([[0,1,2],
[3,4,5],
[6,7,8],
[9,10,11]])
y=np.array([1,2,3])
print(x+y)
输出:
[[ 1 3 5]
[ 4 6 8]
[ 7 9 11]
[10 12 14]]
9 迭代数组
NumPy迭代器对象numpy.nditer提供了一种灵活访问一个或多个数组元素的方式。下面使用arange()函数创建一个2×3数组,并使用nditer对它进行迭代。
import numpy as np
a=np.arange(6).reshape(2,3)
print('原始数组为:')
print(a)
print('------')
print('迭代输出元素:')
for x in np.nditer(a):
print(x,end=',')
输出:
原始数组为:
[[0 1 2]
[3 4 5]]
------
迭代输出元素:
0,1,2,3,4,5,
以上实例的顺序是和数组内存布局一致的,这样做是为了提升访问的效率,默认是行序优先。这反映了默认情况下只需访问每个元素,而无需考虑其特定顺序。可以通过迭代上述数组的转置来看到这一点,并与以C顺序访问数组转置的copy方式做对比,如下实例:
import numpy as np
a=np.arange(6).reshape(2,3)
print('原始数组为:')
print(a)
print('------')
for x in np.nditer(a.T):
print(x,end=',')
print('\n------')
for x in np.nditer(a.T.copy(order='C')):
print(x,end=',')
输出:
原始数组为:
[[0 1 2]
[3 4 5]]
------
0,1,2,3,4,5,
------
0,3,1,4,2,5,
从上述例子可以看出,a和a.T的遍历顺序是一样的,也就是他们在内存中的存储顺序也是一样的,但是a.T.copy(order=‘C’)的遍历结果是不同的,那是因为它和前两种的存储方式是不一样的,默认是按行访问。
9.1 控制遍历顺序
如下:
1、for x in np.nditer(a, order=‘F’)——Fortran order,即是列序优先;
2、for x in np.nditer(a.T, order=‘C’)——C order,即是行序优先。
import numpy as np
a=np.arange(0,60,5).reshape(3,4)
print('原始数组为:')
print(a)
print('------')
print('该数组的转置是:')
b=a.T
print(b)
print('------')
print('以C风格顺序排序')
c=b.copy(order='C')
print(c)
for x in np.nditer(c):
print(x,end=',')
print('\n------')
print('以F风格顺序排序')
c=b.copy(order='F')
print(c)
for x in np.nditer(c):
print(x,end=',')
输出:
原始数组为:
[[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]]
------
该数组的转置是:
[[ 0 20 40]
[ 5 25 45]
[10 30 50]
[15 35 55]]
------
以C风格顺序排序
[[ 0 20 40]
[ 5 25 45]
[10 30 50]
[15 35 55]]
0,20,40,5,25,45,10,30,50,15,35,55,
------
以F风格顺序排序
[[ 0 20 40]
[ 5 25 45]
[10 30 50]
[15 35 55]]
0,5,10,15,20,25,30,35,40,45,50,55,
可以通过显式设置,来强制nditer对象使用某种顺序:
import numpy as np
b=np.arange(0,60,5).reshape(3,4)
print('原始数组为:')
print(b)
print('------')
print('以C风格顺序排序')
for x in np.nditer(c,order='C'):
print(x,end=',')
print('\n------')
print('以F风格顺序排序')
for x in np.nditer(c,order='F'):
print(x,end=',')
输出:
原始数组为:
[[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]]
------
以C风格顺序排序
0,20,40,5,25,45,10,30,50,15,35,55,
------
以F风格顺序排序
0,5,10,15,20,25,30,35,40,45,50,55,
9.2 修改数组中元素的值
nditer对象有另一个可选参数op_flags。默认情况下,nditer将待迭代遍历的数组视为只读对象(read-only),为了在遍历数组的同时,实现对数组元素值的修改,必须指定read-write或者write-only的模式。
import numpy as np
a=np.arange(0,60,5).reshape(3,4)
print('原始数组为:')
print(a)
print('------')
for x in np.nditer(a,op_flags=['readwrite']):
x[...]=2*x
print('修改后的数组为:')
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]]
9.3 使用外部循环
nditer类的构造器拥有flags参数,它可以接受下列值:
参数 | 描述 |
---|---|
c_index | 可以跟踪C顺序的索引 |
f_index | 可以跟踪Fortran顺序的索引 |
multi_index | 每次迭代可以跟踪一种索引类型 |
external_loop | 给出的值是具有多个值的一维数组,而不是零维数组 |
在下面的实例中,迭代器遍历对应于每列,并组合为一维数组。
import numpy as np
a=np.arange(0,60,5).reshape(3,4)
print('原始数组为:')
print(a)
print('------')
print('修改后的数组为:')
for x in np.nditer(a,flags=['external_loop'],order='F'):
print(x,end=',')
输出:
原始数组为:
[[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]]
------
修改后的数组为:
[ 0 20 40],[ 5 25 45],[10 30 50],[15 35 55],
9.4 广播迭代
如果两个数组是可广播的,nditer组合对象能够同时迭代它们。假设数组a的维度为3×4,数组b的维度为1×4,则使用以下迭代器(数组b被广播到a的大小)。
import numpy as np
a=np.arange(0,60,5).reshape(3,4)
print('第一个数组为:')
print(a)
print('------')
b=np.array([1,2,3,4],dtype=int)
print('第二个数组为:')
print(b)
print('------')
print('修改后的数组为:')
for x,y in np.nditer([a,b]):
print('%d:%d' % (x,y),end=',')
输出:
第一个数组为:
[[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]]
------
第二个数组为:
[1 2 3 4]
------
修改后的数组为:
0:1,5:2,10:3,15:4,20:1,25:2,30:3,35:4,40:1,45:2,50:3,55:4,
END