介绍
NumPy(Numerical Python) 是 Python 语言的一个扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。
数组对象Ndarray
是一系列 同类型数据 的集合,以 0 下标为开始 进行集合中元素的索引,是用于存放同类型元素的 多维数组
创建数组
创建一个 ndarray 只需调用 NumPy 的 array 函数即可:
numpy.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0)
参数说明,object为数组或嵌套数列,dtype为数据类型(可选),copy为对象是否需要复制(可选),order为创建数组的方向(C为行方向,F为列方向,默认为任意方向),ndmin指定生成数组的最小维度
例子代码:
import numpy as np
a=np.array([1,2,3])
b=np.array([[1,2],[3,4]])
c=np.array([1,2,3,4,5],ndmin=2)
d=np.array([1,2,3],dtype=complex)
print(a,"\n\n",b,"\n\n",c,"\n\n",d)
输出结果:
[1 2 3]
[[1 2]
[3 4]]
[[1 2 3 4 5]]
[1.+0.j 2.+0.j 3.+0.j]
数组属性
-
NumPy 数组的 维数 称为秩(rank),一维数组的秩为 1,二维数组的秩为 2,以此类推。
-
在 NumPy中,每一个线性的数组称为是一个轴(axis),也就是 维度(dimensions)。比如说,二维数组相当于是两个一维数组,其中第一个一维数组中每个元素又是一个一维数组。所以一维数组就是 NumPy 中的轴(axis),第一个轴相当于是底层数组,第二个轴是底层数组里的数组。而轴的数量——秩,就是数组的维数。
-
很多时候可以声明 axis。axis=0,表示沿着第 0 轴进行操作,即对每一列进行操作;axis=1,表示沿着第1轴进行操作,即对每一行进行操作。
-
注意区分维数与维度的不同
例子代码:
import numpy as np
a=np.arange(24)
print(a,"\n",a.ndim,"\n") #ndarray.ndim返回数组的维数,等于秩
b=a.reshape(2,3,4) #reshape用来调整数组大小,b为3维了
print(b,"\n",b.ndim,"\n")
c=np.array([[10,4,5],[6,3,8]])
print(c,"\n",c.shape) #ndarray表示数组的维度,返回一个元组
输出结果:
[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23]
1
[[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
[[12 13 14 15]
[16 17 18 19]
[20 21 22 23]]]
3
[[10 4 5]
[ 6 3 8]]
(2, 3)
属性补充:
- ndarray.size 数组元素的总个数,相当于 .shape 中 n*m 的值
- ndarray.dtype ndarray 对象的元素类型
创建未初始化或者0-1填充的数组
- numpy.empty(shape, dtype = float, order = ‘C’),创建未初始化数组
- numpy.zeros(shape, dtype = float, order = ‘C’),创建以0填充数组
- numpy.ones(shape, dtype = None, order = ‘C’),创建以1填充数组
参数说明:
参数 | 描述 |
---|---|
shape | 数组形状 |
dtype | 数据类型,可选 |
order | ‘C’ 用于 C 的行数组,或者 ‘F’ 用于 FORTRAN 的列数组 |
例子代码:
a=np.empty([3,2],dtype=int)
b=np.empty([3,2],dtype=float)
print(a,"\n\n",b,"\n\n")
c=np.zeros(5) #默认为浮点数
d=np.zeros(5,dtype=int) #dtype可以自定义类型
print(c,"\n\n",d,"\n\n")
e=np.ones(5)#默认为浮点数
f=np.ones([2,4],dtype=int)
print(e,"\n\n",f,"\n\n")
输出结果:
a:[[1 0]
[2 0]
[3 0]]
b: [[1. 0.]
[2. 0.]
[3. 0.]]
c:[0. 0. 0. 0. 0.]
d:[0 0 0 0 0]
e:[1. 1. 1. 1. 1.]
f:[[1 1 1 1]
[1 1 1 1]]
根据其它数组创建数组
numpy.asarray(a, dtype = None, order = None)
a可以是任意形式的参数,如列表,元组,列表的元组,元组的列表,多维数组
例子代码:
a=[1,2,3]
b=np.asarray(a)
print(a,"\n\n",b,"\n\n")#将列表a转化成为了数组b
c=(1,2,3)
d=np.asarray(c)
print(c,"\n\n",d,"\n\n")#将元组c转化成为了数组d
e=[(1,2,3),(4,5)]
f=np.asarray(e)
print(e,"\n\n",f)
输出结果:
a:[1, 2, 3]
b:[1 2 3]
c:(1, 2, 3)
d:[1 2 3]
e:[(1, 2, 3), (4, 5)]
f:[(1, 2, 3) (4, 5)]
从数组范围创建数组
- numpy.arange(start, stop, step, dtype)
- step:设定步长
- np.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)
- num: 要生成的等步长的样本数量,默认为50,
- endpoint 该值为 ture 时,数列中中包含stop值,反之不包含,默认是True。
- retstep 如果为 True 时,生成的数组中会显示间距,反之不显示。
例子代码:
a=np.arange(5)
b=np.arange(5,dtype=float)
c=np.arange(10,20,2)
print(a,b,c)
d=np.linspace(1,10,5)
e=np.linspace(1,10,5,endpoint=False)
f=np.linspace(1,10,5,endpoint=False,retstep=True)
print(d,e,f)
输出结果:
a:[0 1 2 3 4]
b:[0. 1. 2. 3. 4.]
c:[10 12 14 16 18]
d:[ 1. 3.25 5.5 7.75 10. ]
e:[1. 2.8 4.6 6.4 8.2]
f:(array([1. , 2.8, 4.6, 6.4, 8.2]), 1.8)
切片和索引
ndarray对象的内容可以通过索引或切片来访问和修改,与 Python 中 list 的切片操作一样。
- ndarray 数组可以基于 0 - n 的下标进行索引,切片对象可以通过内置的 slice 函数,并设置 start, stop 及 step 参数进行,从原数组中切割出一个新数组。如下:
- 通过 冒号 分隔切片参数 start:stop:step 来进行切片操作
- 冒号 : 的解释:如果只放置一个参数,如 [2],将返回与该索引相对应的单个元素。如果为 [2:],表示从该索引开始以后的所有项都将被提取。如果使用了两个参数,如 [2:7],那么则提取两个索引(不包括停止索引)之间的项。
- 切片还可以包括 省略号 …
例子代码:
a=np.arange(10)
b=slice(2,6,2) #<class 'slice'>
c=a[b] #<class 'numpy.ndarray'>
print(a,b,c)
e=np.arange(10)
f=e[2:6:2]
g=e[2:]
print(e,f,g)
h=np.array([[1,2],[4,6,7],[10]])
i=h[1:]
print(h,i)
j=np.array([[23,4,3,6,8,8,5],[23,4,1,5],[3,2,5,1]])
k1=j[...,2] #每个轴的数据个数不一致时,无效
k2=j[2,...] #每个轴的数据个数不一致时,无效
l=np.array([[23,4,3,6],[23,4,1,5],[3,2,5,1]])
m1=l[...,2] #第二列元素
m2=l[2,...] #第二行元素
n=l[2,1:]
print(k1,k2,m1,m2,n)
o=l[2][1]#或者o=l[2,1],效果一样
print(o)
输出结果:
a:[0 1 2 3 4 5 6 7 8 9]
b:slice(2, 6, 2)
c:[2 4]
e:[0 1 2 3 4 5 6 7 8 9]
f:[2 4]
g:[2 3 4 5 6 7 8 9]
h:[list([1, 2]) list([4, 6, 7]) list([10])]
i:[list([4, 6, 7]) list([10])]
k1:[3, 2, 5, 1]
k2:[3, 2, 5, 1]
m1:[3 1 5]
m2:[3 2 5 1]
n:[2 5 1]
o:2
高级索引
- 通过整数数组索引
- 可以借助切片 : 或 … 与索引数组组合。
例子代码:
a=np.array([[1,2],[4,6]])
b=a[[0,1],[0,1]] #获取数组中(0,0),(1,1)和(2,0)位置处的元素。
print(b)
c = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]])
rows = np.array([[0, 0], [3, 3]])
cols = np.array([[0, 2], [0, 2]])
d = c[rows, cols] #获取了 4X3 数组中的四个角的元素。 行索引是 [0,0] 和 [3,3],而列索引是 [0,2] 和 [0,2]
print('这个数组的四个角元素是:')
print(d)
e=np.array([[1,4,6],[2,6,3],[3,4,6]])
"""注意如果每行个数不等时,数组里面数据类型会发生变化,变成了列表),如下:"""
#e=np.array([[1,4,6],[2,6,3],[3,4,6,9]]) type(e):如下:
#array([list([1, 4, 6]), list([2, 6, 3]), list([3, 4, 6, 9])], dtype=object)
f=e[1:10,1:10]
g=e[1:10,[2]]
h=e[1:10,[1,2]]
i=e[...,1:]
print(f,g,h,i)
输出结果:
b:[1 6]
这个数组的四个角元素是:
d:[[ 0 2]
[ 9 11]]
f:[[6 3]
[4 6]]
g:[[3]
[6]]
h:[[6 3]
[4 6]]
i:[[4 6]
[6 3]
[4 6]]
广播(Broadcast)
广播(Broadcast)是 numpy 对不同形状(shape)的数组进行数值计算 的方式, 对数组的算术运算通常在相应的元素上进行
- a.shape=b.shape形状相同时:
例子代码:
a=np.array([[12,3,4,5],[3,2,45,5]])
b=np.array([[2,3,4,1],[1,3,5,3]])
print(a*b) #一一对应相乘
#输出结果如下:
[[ 24 9 16 5]
[ 3 6 225 15]]
- 形状不同时,自动触发广播机制
例子代码:
a = np.array([[ 0, 0, 0],
[10,10,10],
[20,20,20],
[30,30,30]])
b = np.array([1,2,3])
print(a + b)
#输出结果如下:
[[ 1 2 3]
[11 12 13]
[21 22 23]
[31 32 33]]
- 如何通过广播与数组兼容?如下:
例子代码:
a = np.array([[ 0, 0, 0],
[10,10,10],
[20,20,20],
[30,30,30]])
b = np.array([1,2,3])
b_broadcast=np.tile(b,(4,1))
print(b_broadcast)
print(a + b_broadcast)
"""np.tile()介绍"""
#就是将原矩阵横向、纵向地复制。tile 是瓷砖的意思,顾名思义,这个函数就是把数组像瓷砖一样铺展开来。
c=np.tile(b,[3,4]) #用(3,4)也行
print(c)
输出结果:
[[1 2 3]
[1 2 3]
[1 2 3]
[1 2 3]]
[[ 1 2 3]
[11 12 13]
[21 22 23]
[31 32 33]]
[[1 2 3 1 2 3 1 2 3 1 2 3]
[1 2 3 1 2 3 1 2 3 1 2 3]
[1 2 3 1 2 3 1 2 3 1 2 3]]
迭代数组
NumPy 迭代器对象 numpy.nditer 提供了一种灵活访问一个或者多个数组元素的方式。
遍历数组-例子代码:
a=np.arange(6).reshape(2,3)
"""[[0 1 2]
[3 4 5]]"""
for b in np.nditer(a):
print(b,end=",")
# 输出结果为:0,1,2,3,4,5,
for b in np.nditer(a.T):
print(b,end=",")
# 输出结果为:0,1,2,3,4,5,
"""可以看出a 和 a.T 的遍历顺序是一样的,也就是他们在内存中的存储顺序也是一样的
且遍历顺序默认是行序优先(row-major order,或者说是 C-order)
"""
x=a.T.copy(order='C')
"""[[0 3]
[1 4]
[2 5]]"""
for b in np.nditer(x):
print(b,end=",")
# 输出结果为:0,3,1,4,2,5,
"""a.T.copy(order='C')的存储方式跟上面两者不一样了,导致结果不一样"""
""" 可以通过显式设置,来强制 nditer 对象使用某种顺序:"""
for c in np.nditer(x,order='F'):
print(c,end=",")
#输出结果为:0,1,2,3,4,5,
修改数组-例子代码:
a=np.arange(5)
for x in np.nditer(a,op_flags=['readwrite']):
x[...]=x*2
print(a)
#输出结果为[0 2 4 6 8]
也可以使用 numpy.ndarray.flat 数组迭代器来进行迭代
例子代码:
a=np.arange(6).reshape(3,2)
for x in a.flat:
print(x,end=",")
#输出结果为:0,1,2,3,4,5,
"""如果不是用迭代器,效果如下"""
for x in a:
print(x)
"""[0 1]
[2 3]
[4 5]"""
数组操作
数组展开
- 语法:ndarray.flatten(order=‘C’),修改不影响原数组
- 语法:numpy.ravel(a, order=‘C’),修改会影响原数组
a=np.arange(9).reshape(3,3)
b=a.flatten()
print(b) # [0 1 2 3 4 5 6 7 8]
b[1]=10
print(a)
"""[[0 1 2]
[3 4 5]
[6 7 8]]"""
c=a.ravel()
print(c) #[0 1 2 3 4 5 6 7 8]
c[1]=10
print(a)
"""[[ 0 10 2]
[ 3 4 5]
[ 6 7 8]]"""
轴交换(维度交换)
- numpy.rollaxis(arr, axis, start),向后滚动特定的轴到一个特定位置
- arr:数组
- axis:要向后滚动的轴,其它轴的相对位置不会改变
- start:默认为零,表示完整的滚动。会滚动到特定位置。
- numpy.swapaxes(arr, axis1, axis2),用于交换数组的两个轴
- arr:输入的数组
- axis1:对应第一个轴的整数
- axis2:对应第二个轴的整数
例子代码:
a=np.array([[[12,23],[20,4]],[[82,9],[2,54]]])
b=np.rollaxis(a,2) #将2轴滚动到0轴后面
"""[[[12 20]
[82 2]]
[[23 4]
[ 9 54]]"""
c=np.rollaxis(a,2,1) # 将2轴滚动到1轴后面
"""[[[12 20]
[23 4]]
[[82 2]
[ 9 54]]]"""
d=np.swapaxes(a,2,0) #交换2轴和0轴
"""[[[12 82]
[20 2]]
[[23 9]
[ 4 54]]]"""
print(b,"\n\n",c,"\n\n",d)
针对b=np.rollaxis(a,2)输出结果,进行分析:
12(000)->(000)12 | 23(001)->(010)20 |
---|---|
20(010)->(100)82 | 4(011)->(110)2 |
82(100)->(001)23 | 9(101)->(011)4 |
2(110)->(101)9 | 54(111)->(111)54 |
注:上表类似(100)这样的,第一个数字代表2轴,第二个数字代表1轴,第三个数字代表0轴,其它的轴顺序改变是同样的道理,类比即可。
连接数组
- numpy.concatenate((a1, a2, …), axis) 用于沿指定轴连接相同形状的两个或多个数组
- numpy.stack(arrays, axis),用于沿新轴连接数组序列
- hstack 水平堆叠序列中的数组(列方向)
- vstack 竖直堆叠序列中的数组(行方向)
例子代码:
a1 = np.array([[1, 2], [3, 4]])
a2 = np.array([[5, 6], [7, 8]])
b = np.concatenate((a1, a2), axis=0) # 使用下面的[]号也行
c = np.concatenate([a1, a2], axis=1)
print(b, "\n\n", c)
d = np.stack((a1, a2), axis=0)
e = np.stack((a1, a2), axis=1)
print(d, "\n\n", e)
f = np.hstack((a1, a2))
g = np.vstack((a1, a2))
print(f, "\n\n", g)
输出结果:
b:[[1 2]
[3 4]
[5 6]
[7 8]]
c:[[1 2 5 6]
[3 4 7 8]]
d:[[[1 2] #特别留意d和a,e和c的不同,叠加的可有三层括号"[]",连接与叠加是不同的
[3 4]]
[[5 6]
[7 8]]]
e: [[[1 2]
[5 6]]
[[3 4]
[7 8]]]
f:[[1 2 5 6]
[3 4 7 8]]
g:[[1 2]
[3 4]
[5 6]
[7 8]]
np.concatenate((a1, a2), axis=0)结果分析:
1(0 0) | 2(0 1) |
---|---|
3 (1 0) | 4(1 1) |
5 (0 0) | 6(0 1) |
7 (1 0) | 8(1 1) |
0轴都是0的串起来 | 0轴都是1的串起来 |
np.concatenate([a1, a2], axis=1)结果分析:
1(0 0 ) | 2(0 1) | 5 (0 0) | 6(0 1) | 1轴都是0的串起来 |
---|---|---|---|---|
3 (1 0) | 4(1 1 1) | 7 (1 0) | 8(1 1) | 1轴都是1的串起来 |
分割数组
- numpy.split(ary, indices_or_sections, axis),沿特定的轴将数组分割为子数组
- numpy.hsplit,用于水平分割数组,通过指定要返回的相同形状的数组数量来拆分原数组。
- numpy.vsplit ,沿着垂直轴分割,其分割方式与hsplit用法相同。
例子代码:
a = np.array([1, 2, 3, 4, 5, 65, 6, 9, 34])
b = np.split(a, 3) # a必需要能够平均分为3份
#[array([1, 2, 3]), array([ 4, 5, 65]), array([ 6, 9, 34])]
c = np.split(a, [4, 7]) # 在一维数组中表明的位置分割
#[array([1, 2, 3, 4]), array([ 5, 65, 6]), array([ 9, 34])]
print(b, "\n\n", c)
d = np.array([[1, 2, 4, 5, 6, 2, 6, 4, 2], [2, 3, 5, 6, 7, 4, 3, 2, 8]])
e = np.hsplit(d, 3)
"""
[array([[1, 2, 4],
[2, 3, 5]]), array([[5, 6, 2],
[6, 7, 4]]), array([[6, 4, 2],
[3, 2, 8]])] """
f = np.floor(10 * np.random.random((2, 6)))
""" [[5. 0. 3. 1. 0. 5.]
[3. 0. 9. 3. 5. 1.]] """
g = np.vsplit(f, 2)
#[array([[5., 0., 3., 1., 0., 5.]]), array([[3., 0., 9., 3., 5., 1.]])]
print(e,"\n\n",f, "\n\n",g)
数组元素添加与删除
- numpy.resize(arr, shape) ,返回指定大小的新数组。如果新数组大小大于原始大小,则包含原始数组中的元素的副本。
- numpy.append(arr, values, axis=None) ,在数组的末尾添加值。 追加操作会分配整个数组,并把原来的数组复制到新数组中。 此外,*输入数组的维度必须匹配否则将生成ValueError。append 函数返回的始终是一个一维数组。
- numpy.insert(arr, obj, values, axis) ,在给定索引之前,沿给定轴在输入数组中插入值。如果值的类型转换为要插入,则它与输入数组不同。 插入没有原地的,函数会返回一个新数组。 此外,如果未提供轴,则输入数组会被展开。
- Numpy.delete(arr, obj, axis) 返回从输入数组中删除指定子数组的新数组。 与 insert() 函数的情况一样,如果未提供轴参数,则输入数组将展开。
- numpy.unique(arr, return_index, return_inverse, return_counts),用于去除数组中的重复元素。
例子代码:
a=np.array([[1,2,3],[4,5,6]])
b=np.resize(a,(3,2))#
c=np.resize(a,(3,3))#数组中元素不够了,会从第一行开始再继续选,因此会有重复值
d=np.resize(a,(3,1)) #选够3个元素来组成维度为(3,1)的数组,多余的弃掉
print(b,"\n\n",c,"\n\n",d)
"""
[[1 2]
[3 4]
[5 6]]
[[1 2 3]
[4 5 6]
[1 2 3]]
[[1]
[2]
[3]]
"""
e=np.append(a,[7,8,9])
f=np.append(a,[[7,8,9]],axis=0) #沿0轴添加元素
g=np.append(a,[[7,8,9],[10,11,12]],axis=1) #沿1轴添加元素
print(e,"\n\n",f,"\n\n",g)
"""
[1 2 3 4 5 6 7 8 9]
[[1 2 3]
[4 5 6]
[7 8 9]]
[[ 1 2 3 7 8 9]
[ 4 5 6 10 11 12]]
"""
h=np.array([[1,2,],[3,4,],[5,6]])
i=np.insert(h,3,[7,8]) #未传递 Axis 参数。 在插入之前输入数组会被展开。
#传递了 Axis 参数。 会广播值数组来配输入数组。如下:
j=np.insert(h,1,[13],axis=0) #沿0轴广播
k=np.insert(h,1,[13],axis=1) #沿1轴广播
print(i,"\n\n",j,"\n\n",k)
"""
[1 2 3 7 8 4 5 6]
[[ 1 2]
[13 13]
[ 3 4]
[ 5 6]]
[[ 1 13 2]
[ 3 13 4]
[ 5 13 6]]
"""
l=np.arange(12).reshape(3,4)
m=np.delete(l,5) #未传递 Axis 参数。 在插入之前输入数组会被展开。
n=np.delete(l,1,axis=1) #删除第二列
"""
[ 0 1 2 3 4 6 7 8 9 10 11]
[[ 0 2 3]
[ 4 6 7]
[ 8 10 11]]
"""
o=np.array([1,2,4,5,3,2,4,52,2,2])
p=np.unique(o)
q=np.unique(o,return_index=True) #新在旧的位置
r=np.unique(o,return_inverse=True) #旧在新的位置
s=np.unique(o,return_counts=True) #出现次数
print(q,"\n\n",r,"\n\n",s)
"""
(array([ 1, 2, 3, 4, 5, 52]), array([0, 1, 4, 2, 3, 7], dtype=int64))
(array([ 1, 2, 3, 4, 5, 52]), array([0, 1, 3, 4, 2, 1, 3, 5, 1, 1], dtype=int64))
(array([ 1, 2, 3, 4, 5, 52]), array([1, 4, 1, 2, 1, 1], dtype=int64))
"""