NumPy应用场景
- 与SciPy(Scientific Python)和Matplotlib一起使用,可代替Matlab
- SciPy:开源Python算法库和数学工具包,包含最优化、线性代数、积分、插值、快速傅里叶变换、信号处理和图像处理、常微分方程求解和其他科学与工程中常用的计算模块。
- Matplotlib:利用通用的图形用户界面工具包,如 Tkinter, wxPython, Qt 或 GTK+ 向应用程序嵌入式绘图提供了应用程序接口(API)
NumPy比python原生数组计算更高效的原因
- 内存:NumPy在内存空间中连续存储数据,而python列表每个元素是分散的
- 向量化运算:NumPy内置了并行运算功能
- 底层代码:NumPy底层用C编写,内部解除了GIL(全局解释锁)
目录
NumPy 最重要的一个特点是其 N 维数组对象 ndarray,它是一系列同类型数据的集合,以 0 下标为开始进行集合中元素的索引。
ndarray 内部由以下内容组成
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:\n',a,'\n')
#多于一个维度
b = np.array([[1,2],[3,4]])
print('b:\n',b,'\n')
#最小维度
c = np.array([1,2,3,4,5], ndmin = 2)
print('c:\n',c,'\n')
# dtype参数
d = np.array([1,2,3], dtype = complex)
print('d:\n',d)
输出结果:
a:
[1 2 3]
b:
[[1 2]
[3 4]]
c:
[[1 2 3 4 5]]
d:
[1.+0.j 2.+0.j 3.+0.j]
numpy的数值类型是dtype对象的实例,并对应唯一的字符,包括np.bool_, np.int32, np.float32等。
数据类型对象(numpy.dtype 类的实例)用来描述与数组对应的内存区域是如何使用,它描述了数据的以下几个方面:
字节顺序是通过对数据类型预先设定 < 或 > 来决定的。 < 意味着小端法(最小值存储在最小的地址,即低位组放在最前面)。> 意味着大端法(最重要的字节存储在最小的地址,即高位组放在最前面)
numpy.dtype(object, align, copy)
import numpy as np
# 创建结构化数据类型
dt = np.dtype([('age', np.int8)])
print(dt)
# 将数据类型应用于ndarray对象
a = np.array([(10,),(20,),(30,)], dtype = dt)
print(a)
# 类型字段名可以用于存取实际的age列
print(a['age'])
输出结果:
[('age', 'i1')]
[(10,) (20,) (30,)]
[10 20 30]
import numpy as np
student = np.dtype([('name','S20'),('age','i1'),('marks','f4')])
print(student)
a = np.array([('Jack',21,98),('Rose',19,100),('@lbert',25,150)], dtype = student)
print(a)
输出结果:
[('name', 'S20'), ('age', 'i1'), ('marks', ')]
[(b'Jack', 21, 98.) (b'Rose', 19, 100.) (b'@lbert', 25, 150.)]
字符 | 对应类型 |
---|---|
b | boolean |
i | integer |
u | 无符号整型 |
f | float |
c | complex |
m | timedelta |
M | datetime |
O | (python)object |
S,a | (byte-)字符串 |
U | Unicode |
V | 原始数据void |
NumPy 数组的维数称为秩(rank),每一个线性的数组称为是一个轴(axis),也就是维度(dimensions)。
比如说,二维数组相当于是两个一维数组,其中第一个一维数组中每个元素又是一个一维数组。所以一维数组就是 NumPy 中的轴(axis),第一个轴相当于是底层数组,第二个轴是底层数组里的数组。而轴的数量——秩,就是数组的维数。很多时候可以声明 axis。axis=0,表示沿着第 0 轴进行操作,即对每一列进行操作;axis=1,表示沿着第1轴进行操作,即对每一行进行操作。
attribute | description |
---|---|
ndarray.ndim | 秩,即轴的数量或维度的数量 |
ndarray.shape | 数组的维度 |
ndarray.size | 数组元素的总个数 |
ndarray.dtype | ndarray对象的元素类型 |
ndarray.itemsize | ndarray对象中每个元素的大小,以字节为单位 |
ndarray.flags | ndarray对象的内存信息 |
ndarray.real | ndarray元素的实部 |
ndarray.imag | ndarray元素的虚部 |
ndarray.data | 包含实际数组元素的缓冲区 |
import numpy as np
x = np.empty([3,2], dtype = int)
print(x)
输出结果:
[[0 0]
[0 0]
[0 0]]
import numpy as np
# 默认为浮点数
x = np.zeros(5)
print(x)
# 设置类型未整数
y = np.zeros((5,), dtype = np.int)
print(y)
# 自定义类型
z = np.zeros((2,2), dtype = [('x', 'i4'),('y','i4')])
print(z)
输出结果:
[0. 0. 0. 0. 0.]
[0 0 0 0 0]
[[(0, 0) (0, 0)]
[(0, 0) (0, 0)]]
import numpy as np
# 将列表转换为ndarray
x = [1,2,3]
a = np.asarray(x)
print(a)
# 将元组转换为ndarray
b = np.asarray(x)
print(b)
# 设置dtype参数
c = np.asarray(x, dtype = float)
print(c)
输出结果:
[1 2 3]
[1 2 3]
[1. 2. 3.]
import numpy as np
s = b'Hello World'
a = np.frombuffer(s, dtype = 'S1')
print(a)
输出结果:
[b'H' b'e' b'l' b'l' b'o' b' ' b'W' b'o' b'r' b'l' b'd']
import numpy as np
# 使用range函数创建列表对象
list = range(5)
it = iter(list)
#使用迭代器创建ndarray
x = np.fromiter(it, dtype=float)
print(x)
输出结果:
[0. 1. 2. 3. 4.]
numpy.arrange(start, stop, step, dtype)
import numpy as np
x = np.arange(start=10, stop=20, step=2, dtype=float)
print(x)
输出结果:
[10. 12. 14. 16. 18.]
np.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)
参数 | 说明 |
---|---|
num | 样本数量,default 50 |
endpoint | 是否包含终点值,default True |
retstep | 是否显示间距,default False |
import numpy as np
# 设置不包含终点值
a = np.linspace(10, 20, 5, endpoint = False)
print(a)
# 显示间距
b = np.linspace(1, 10, 10, retstep=True)
print(b)
c = np.linspace(1,10,10)
print(c)
print(c.reshape([10,1]))
输出结果:
[10. 12. 14. 16. 18.]
(array([ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10.]), 1.0)
[ 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]
[[ 1.]
[ 2.]
[ 3.]
[ 4.]
[ 5.]
[ 6.]
[ 7.]
[ 8.]
[ 9.]
[10.]]
numpy.logspace(start, stop, num, endpoint=True, base=10.0, dtype=None)
参数 | 说明 |
---|---|
start | 序列的起始值为base**start |
stop | 序列的终止值为base**stop |
base | 对数log的底数 |
import numpy as np
a = np.logspace(start=0, stop=9, num=5, base=3)
print(a)
输出结果:
[1.00000000e+00 1.18446661e+01 1.40296115e+02 1.66176064e+03
1.96830000e+04]
import numpy as np
a = np.arange(10)
print(a)
# 通过内置slice函数切割
s = slice(2,7,2) #从索引2开始到索引7结束,间隔为2
print(a[s])
# 通过冒号分隔切片参数start:stop:step切片
print(a[2:7:2])
# 切割多维数组
b = np.array([[1,2,3],[3,4,5],[4,5,6]])
print(b)
print(b[1:]) #选择第二行及之后所有行
print(b[1,1:]) #选择第二行中第二列及之后的所有数
输出结果:
[0 1 2 3 4 5 6 7 8 9]
# 通过内置slice函数切割
[2 4 6]
# 通过冒号分隔切片参数start:stop:step切片
[2 4 6]
# 切割多维数组
[[1 2 3]
[3 4 5]
[4 5 6]]
#选择第二行及之后所有行
[[3 4 5]
[4 5 6]]
#选择第二行中第二列及之后的所有数
[4 5]
注意:使用[]进行数组索引是是从后往前索引的,即从中括号最外层向内进行索引,以下示例说明了这个问题。
import numpy as np
a = np.arange(8).reshape(2,2,2)
print ('原数组:')
print (a)
print ('获取数组中一个值:')
print(np.where(a==6))
print(a[1,1,0]) # 索引为[1,1,0],坐标为(0,0,1)
print ('\n')
输出结果:
原数组:
[[[0 1]
[2 3]]
[[4 5]
[6 7]]]
获取数组中一个值:
(array([1], dtype=int64), array([1], dtype=int64), array([0], dtype=int64))
6
以下实例获取数组中(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)
##这里没太看懂
m = np.array([[ 0, 1, 2],[ 3, 4, 5],[ 6, 7, 8],[ 9, 10, 11]])
print ('我们的数组是:' )
print (m)
print ('\n')
rows = np.array([[0,0],[3,3]])
cols = np.array([[0,2],[0,2]])
n = m[rows,cols]
print ('这个数组的四个角元素是:')
print (n)
输出结果:
[1 4 5]
我们的数组是:
[[ 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 ('\n') # 现在我们会打印出大于 5 的元素
print ('大于 5 的元素是:')
print (x[x > 5])
#使用取补运算符~
a = np.array([np.nan, 1,2,np.nan,3,4,5])
print (a[~np.isnan(a)])
输出结果:
我们的数组是:
[[ 0 1 2]
[ 3 4 5]
[ 6 7 8]
[ 9 10 11]]
大于 5 的元素是:
[ 6 7 8 9 10 11]
[1. 2. 3. 4. 5.]
花式索引指的是利用整数数组进行索引。
花式索引根据索引数组的值作为目标数组的某个轴的下标来取值。对于使用一维整型数组作为索引,如果目标是一维数组,那么索引的结果就是对应位置的元素;如果目标是二维数组,那么就是对应下标的行。
花式索引跟切片不一样,它总是将数据复制到新数组中。
import numpy as np
x=np.arange(32).reshape((8,4))
print (x[np.ix_([1,5,7,2],[0,3,1,2])])
输出结果:
[[ 4 7 5 6]
[20 23 21 22]
[28 31 29 30]
[ 8 11 9 10]]
注意:x[np.ix_([1,5,7,2],[0,3,1,2])]这句话会输出一个4*4的矩阵,其中的元素分别是:
x[1,0] x[1,3] x[1,1] x[1,2]
x[5,0] x[5,3] x[5,1] x[5,2]
x[7,0] x[7,3] x[7,1] x[7,2]
x[2,0] x[2,3] x[2,1] x[2,2]
(Broadcast)是 numpy 对不同形状(shape)的数组进行数值计算的方式, 对数组的算术运算通常在相应的元素上进行。
如果两个数组 a 和 b 形状相同,即满足 a.shape == b.shape,那么 a*b 的结果就是 a 与 b 数组对应位相乘。这要求维数相同,且各维度的长度相同。
当运算中的数组形状不同时,将会自动触发broadcast机制。
import numpy as np
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]]
等效运算:
import numpy as np
a = np.array([[ 0, 0, 0], [10,10,10], [20,20,20], [30,30,30]])
b = np.array([1,2,3])
bb = np.tile(b, (4, 1)) # 重复 b 的各个维度
print(a + bb)
Rules for broadcast
- 规则1:如果两个数组的维度数不相同,那么小维度数组的形状会在最左边补1
- 规则2:如果两个数组的形状在任何一个维度上都不匹配,那么数组的形状会沿着维度为1的维度扩展以匹配另外一个数组的形状
- 规则3:如果两个数组的形状在任何一个维度上都不匹配并且没有任何一个维度等于1,那么会引发异常
import numpy as np
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,
以上实例不是使用标准 C 或者 Fortran 顺序,选择的顺序是和数组内存布局一致的,这样做是为了提升访问的效率,默认是行序优先(row-major order,或者说是 C-order)。 这反映了默认情况下只需访问每个元素,而无需考虑其特定顺序。
我们可以通过迭代上述数组的转置来看到这一点,并与以 C 顺序访问数组转置的 copy 方式做对比,如下实例:
import numpy as np
a = np.arange(6).reshape(2,3)
print(a)
print("使用默认方式:")
for x in np.nditer(a):
print(x, end=",")
print("\n转置:\n",a.T)
print('转置后迭代访问顺序与默认相同:')
for x in np.nditer(a.T):
print(x, end=",")
print("\n使用以C顺序访问数组转置的copy方式:")
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]]
转置后迭代访问顺序与默认相同:
0,1,2,3,4,5,
使用以C顺序访问数组转置的copy方式:
0,3,1,4,2,5,
import numpy as np
a = np.arange(0,60,5)
a = a.reshape(3,4)
print ('原始数组是:')
print (a)
print ('\n以 C 风格顺序排序:')
for x in np.nditer(a, order = 'C'):
print (x, end=", " )
print ('\n以 F 风格顺序排序:')
for x in np.nditer(a, order = 'F'):
print (x, end=", " )
输出结果:
原始数组是:
[[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]]
以 C 风格顺序排序:
0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55,
以 F 风格顺序排序:
0, 20, 40, 5, 25, 45, 10, 30, 50, 15, 35, 55,
nditer 对象有另一个可选参数 op_flags。 默认情况下,nditer 将视待迭代遍历的数组为只读对象(read-only),为了在遍历数组的同时,实现对数组元素值得修改,必须指定 read-write 或者 write-only 的模式。
import numpy as np
a = np.arange(0,60,5)
a = a.reshape(3,4)
print(a)
for x in np.nditer(a, op_flags=['readwrite']):
x[...]=2*x # 必须使用x[...]而不是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]]
参数 | 说明 |
---|---|
c_index | 可以跟踪C顺序的索引 |
f_index | 可以跟踪Fortran顺序的索引 |
multi-index | 每次迭代可以跟踪一种索引类型 |
external_loop | 给出的值是具有多个值的一维数组,而不是一个一个的数 |
import numpy as np
a = np.arange(0,60,5)
a = a.reshape(3,4)
print(a)
for x in np.nditer(a, flags=['external_loop'], order='F'):
print(x)
输出结果:
[[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]]
[ 0 20 40]
[ 5 25 45]
[10 30 50]
[15 35 55]
如果两个数组是可广播的,nditer 组合对象能够同时迭代它们。 假设数组 a 的维度为 3X4,数组 b 的维度为 1X4 ,则使用以下迭代器(数组 b 被广播到 a 的大小)。
import numpy as np
a = np.arange(0,60,5)
a = a.reshape(3,4)
print(a)
b = np.array([1,2,3,4], dtype = int)
print(b)
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,
expression | description |
---|---|
reshape(arr, newshape, order=‘C’) | 可以通过order参数指定顺序 |
flat | ndarray.flat是一个数组元素迭代器 |
flatten(order=‘C’) | order:‘C’ – 按行,‘F’ – 按列,‘A’ – 原顺序,‘K’ – 元素在内存中的出现顺序 |
numpy.ravel(a, order=‘C’) | 返回的是数组视图(view,有点类似 C/C++引用reference的意味),修改会影响原始数组。 |
另一种常见的修改数组形状的操作是为已有的数组建立新的空白轴,可以通过简单地在一个切片中使用np.newaxis达成,例如:
import numpy as np
a = np.array([1,2,3])
b = a.reshape((1,3))
c = a[:, np.newaxis]
d = a[np.newaxis, :]
print(a)
print(b)
print(c)
print(d)
输出结果:
[1 2 3]
[[1 2 3]]
# a[:, np.newaxis] 在最内层新建轴
[[1]
[2]
[3]]
# a[np.newaxis, :] 在最外层新建轴
[[1 2 3]]
expression | description |
---|---|
transpose(arr, axes) | 整数列表,对应维度,通常所有维度都会对换 |
ndarray.T | =self.transpose() |
rollaxis(arr, axis, start=0) | 向后滚动指定的轴,start默认为零,表示完整的滚动。会滚动到特定位置 |
swapaxes | 对换数组的两个轴 |
import numpy as np
# 创建了三维的 ndarray
a = np.arange(8).reshape(2,2,2)
print ('原数组:')
print (a)
print ('获取数组中一个值:')
print(np.where(a==6))
print(a[1,1,0]) # 为 6
print ('\n') # 将轴 2 滚动到轴 0(宽度到深度)
print ('调用 rollaxis 函数:')
b = np.rollaxis(a,2,0)
print (b)
# 查看元素 a[1,1,0],即 6 的坐标,变成 [0, 1, 1]
# 最后一个 0 移动到最前面
print(np.where(b==6))
print ('\n')
# 将轴 2 滚动到轴 1:(宽度到高度)
print ('调用 rollaxis 函数:')
c = np.rollaxis(a,2,1)
print (c)
# 查看元素 a[1,1,0],即 6 的坐标,变成 [1, 0, 1]
# 最后的 0 和 它前面的 1 对换位置
print(np.where(c==6))
print ('\n')
输出结果:
原数组:
[[[0 1]
[2 3]]
[[4 5]
[6 7]]]
获取数组中一个值:
(array([1], dtype=int64), array([1], dtype=int64), array([0], dtype=int64))
6
调用 rollaxis 函数:
[[[0 2]
[4 6]]
[[1 3]
[5 7]]]
(array([0], dtype=int64), array([1], dtype=int64), array([1], dtype=int64))
调用 rollaxis 函数:
[[[0 2]
[1 3]]
[[4 6]
[5 7]]]
(array([1], dtype=int64), array([0], dtype=int64), array([1], dtype=int64))
expression | description |
---|---|
broadcast(x,y) | 对y广播x,拥有 iterator 属性,基于自身组件的迭代器元组 |
numpy.broadcast_to(array, shape, subok) | 将数组广播到新形状。它在原始数组上返回只读视图。 |
numpy.expand_dims(arr, axis=0) | axis:新轴插入的位置(before) |
numpy.squeeze(arr, axis=0) | axis:整数或整数元组,用于选择形状中一维条目的子集 |
expression | description |
---|---|
numpy.concatenate((a1, a2, …), axis=0) | 用于沿指定轴连接相同形状的两个或多个数组 |
numpy.stack(arrays, axis) | axis:返回数组中的轴,输入数组沿着它来堆叠 |
numpy.hstack | numpy.stack 函数的变体,它通过水平堆叠来生成数组 |
import numpy as np
a = np.array([
[1,2],
[3,4]
])
b = np.array([
[5,6],
[7,8]
])
c = np.concatenate((a,b), axis=1)
d = np.hstack((a,b))
print(c==d)
e = np.concatenate((a,b))
print(e)
print(',e.shape, '>\n')
f = np.stack((a,b), axis=0)
print(f)
print(',f.shape,'>\n')
g = np.stack((a,b), axis=1)
print(g)
print(',g.shape,'>')
输出结果:
# c = np.concatenate((a,b), axis=1)
# d = np.hstack((a,b))
[[ True True True True]
[ True True True True]]
# e = np.concatenate((a,b))
[[1 2]
[3 4]
[5 6]
[7 8]]
<shape of e: (4, 2) >
# f = np.stack((a,b), axis=0)
[[[1 2]
[3 4]]
[[5 6]
[7 8]]]
<shape of f: (2, 2, 2) >
# g = np.stack((a,b), axis=1)
[[[1 2]
[5 6]]
[[3 4]
[7 8]]]
<shape of g: (2, 2, 2) >
以上结果可以简单理解为:
expression | description |
---|---|
numpy.split(ary, indices_or_sections, axis=0) | 将一个数组分割为多个子数组;indices_or_sections:如果是一个整数,就用该数平均切分,如果是一个数组,为沿轴切分的位置(左开右闭) |
hsplit | 将一个数组水平分割为多个子数组(按列) |
vsplit | 将一个数组垂直分割为多个子数组(按行) |
expression | description |
---|---|
numpy.resize(arr, shape) | 回指定大小的新数组。如果新数组大小大于原始大小,则包含原始数组中的元素的副本。 |
numpy.append(arr, values, axis=None) | 在数组的末尾添加值 |
numpy.insert(arr, obj, values, axis) | 在给定索引之前,沿给定轴在输入数组中插入值;如果未提供轴,则输入数组会被展开 |
Numpy.delete(arr, obj, axis) | 返回从输入数组中删除指定子数组的新数组。 与 insert() 函数的情况一样,如果未提供轴参数,则输入数组将展开。 |
numpy.unique(arr, return_index, return_inverse, return_counts) | 用于去除数组中的重复元素 |
import numpy as np
a = np.array([[1,2,3],[4,5,6]])
print ('第一个数组:')
print (a)
print ('\n')
print ('向数组添加元素:')
print (np.append(a, [7,8,9]))
print ('\n')
print ('沿轴 0 添加元素:')
print (np.append(a, [[7,8,9]],axis = 0))
print ('\n')
print ('沿轴 1 添加元素:')
print (np.append(a, [[5,5],[7,8]],axis = 1))
输出结果:
第一个数组:
[[1 2 3]
[4 5 6]]
向数组添加元素:
[1 2 3 4 5 6 7 8 9]
沿轴 0 添加元素:
[[1 2 3]
[4 5 6]
[7 8 9]]
沿轴 1 添加元素:
[[1 2 3 5 5]
[4 5 6 7 8]]
(略)
待补充
expression | description |
---|---|
np.exp(x) | e x e^x ex |
np.exp2(x) | 2 x 2^x 2x |
np.power(x, y) | x y x^y xy |
np.log(x) | ln x \ln{x} lnx |
np.log10(x) | log 10 x \log_{10}{x} log10x |
np.log2(x) | log 2 x \log_{2}{x} log2x |
np.expm1(x) | e x − 1 e^x-1 ex−1 |
np.log1p(x) | ln ( 1 + x ) \ln{(1 + x)} ln(1+x) |
np.logaddexp(a,b) | log ( e a + e b ) \log{(e^a+e^b)} log(ea+eb) |
python运算符对应表:
Python运算符 | NumPy通用函数 | 描述 |
---|---|---|
+ | np.add | 加法运算 |
- | np.subtract | 减法运算 |
- | np.negative | 负数运算 |
* | np.multiply | 乘法运算 |
/ | np.divide | 除法运算 |
// | np.floor_divide | 向下整除运算 |
** | np.power | 指数运算 |
% | np.mod | 模 |
abs() | np.absolute/np.abs | 绝对值 |
expression | description |
---|---|
numpy.amin(arr, axis=None) | 计算数组中的元素沿指定轴的最小值 |
numpy.amax(arr, axis=None) | 计算数组中的元素沿指定轴的最大值 |
numpy.ptp() | 计算数组中元素最大值与最小值的差(最大值 - 最小值) |
numpy.percentile(arr, q, axis=None) | q: 要计算的百分位数,在 0 ~ 100 之间 |
numpy.median(arr, axis) | 中位数 |
numpy.mean() | 均值 |
numpy.average(a, axis=None, weights=None, returned=False) | 根据在另一个数组中给出的各自的权重计算数组中元素的加权平均值 |
numpy.std() | 标准差 |
numpy.var() | 样本方差 |
除了上述常用函数,NumPy还提供了很多通用函数,包括双曲三角函数、比特位运算、比较运算符、弧度转化为角度的运算、取整和求余运算等。还有一个更加专用的通用函数来源,就是子模块scipy.special,例如Gamma函数、高斯积分等等。
NumPy提供了多种排序函数,这些排序函数实现不同的排序算法,每个排序算法的特征在于执行速度、最坏情况性能、所需的工作空间和算法稳定性。
返回输入数组的排序副本。
numpy.sort(a, axis, kind, order)
- axis: 如果没有,数组会被展开,沿着最后的轴排序
- kind: 默认为’quicksort’(快速排序)
- order: 如果数组包含字段,则是要排序的字段
import numpy as np
a = np.random.randn(3,3,3).round(2)
print(a)
print(np.sort(a)) # 按行排序(最里面一层)
print(np.sort(a, axis=0)) # 按深度排序(最外面一层)
print(np.sort(a, axis=1)) # 按中间层排序
用于对多个序列进行排序,排序时优先照顾靠后的列,相当于按照多个维度进行排序,返回索引序列。
import numpy as np
nm = ('raju','anil','ravi','amar')
dv = ('f.y.', 's.y.', 's.y.', 'f.y.')
ind = np.lexsort((dv,nm))
print ('调用 lexsort() 函数:')
print (ind)
print ('使用这个索引来获取排序后的数据:')
print ([nm[i] + ", " + dv[i] for i in ind]) # 小技巧
输出结果:
调用 lexsort() 函数:
[3 1 0 2]
使用这个索引来获取排序后的数据:
['amar, f.y.', 'anil, s.y.', 'raju, f.y.', 'ravi, s.y.']
按第一个轴排序(最外面一层),等价于np.sort(a, axis=0)
对复数按照先实部后虚部的顺序进行排序。
指定一个数,对数组进行分区。
import numpy as np
arr = np.array([46,57,23,39,1,10,0,120])
print(arr)
## partition的规则是先分区后排序
print(np.partition(arr, 2)) #表示比29小的数排前面,比29大的数排后面
输出结果:
[ 46 57 23 39 1 10 0 120]
[ 0 1 10 39 57 23 46 120]
返回序列值
沿指定轴返回最大值和最小值的索引。
返回数组值从小到大的索引值。
import numpy as np
a = np.random.randn(3,3,3).round(2)
print(a)
print(np.argsort(a)) # 按行排序(最里面一层)
print(np.argsort(a, axis=0)) # 按深度排序(最外面一层)
print(np.argsort(a, axis=1)) # 按中间层排序
输出结果:
[[[ 0.75 -0.7 -0.34]
[ 1.18 -0.1 1.14]
[-0.6 -1.18 -1.15]]
[[ 0.67 -0.5 0.11]
[ 1.04 -0.86 -0.07]
[ 0.71 -0.57 -1.26]]
[[ 1.57 -0.55 -0.56]
[-0.08 -0.19 -0.34]
[ 0.05 0.01 -0.01]]]
[[[1 2 0]
[1 2 0]
[1 2 0]]
[[1 2 0]
[1 2 0]
[2 1 0]]
[[2 1 0]
[2 1 0]
[2 1 0]]]
[[[1 0 2]
[2 1 2]
[0 0 1]]
[[0 2 0]
[1 2 1]
[2 1 0]]
[[2 1 1]
[0 0 0]
[1 2 2]]]
[[[2 2 2]
[0 0 0]
[1 1 1]]
[[0 1 2]
[2 2 1]
[1 0 0]]
[[1 0 0]
[2 1 1]
[0 2 2]]]
可以通过关键字kind指定算法沿着指定轴对数组进行分区,返回的是一个索引序列。
返回数组中非零元素的索引。
返回数组中满足给定条件的元素的索引。
import numpy as np
a = np.random.randn(3,3,3).round(2)
print(a)
m = a.flatten().mean()
print(m)
print(a[np.where(a>m)]) # 获取大于均值的元素(返回列表)
输出结果:
[[[ 0.96 -0.39 -0.54]
[-0.36 -0.07 -0.61]
[-0.82 1.04 -0.24]]
[[-0.38 1.49 0.6 ]
[ 0.57 -0.45 1.26]
[-0.64 0.5 -1.3 ]]
[[-1.5 -0.7 -0.66]
[ 0.73 -0.46 0.94]
[-0.43 -2.01 -1.79]]]
-0.19481481481481483
[ 0.96 -0.07 1.04 1.49 0.6 0.57 1.26 0.5 0.73 0.94]
根据某个条件从数组中抽取元素。
import numpy as np
a = (100*np.random.randn(3,3,3).round(2))
print(a)
condition = np.mod(a,3)==1 # 满足模3余1
print(condition)
print(np.extract(condition,a)) # 获取满足条件的元素
输出结果:
[[[ -73. -112. 148.]
[ 44. -57. 9.]
[ 161. -53. -93.]]
[[ -61. -31. 88.]
[-193. 82. -16.]
[ 147. 13. 80.]]
[[ 18. -5. 32.]
[-283. -40. -20.]
[ 114. 1. 39.]]]
[[[False False True]
[False False False]
[False True False]]
[[False False True]
[False True False]
[False True False]]
[[False True False]
[False False True]
[False True False]]]
[148. -53. 88. 82. 13. -5. -20. 1.]
(略)
副本是一个数据的完整的拷贝,如果我们对副本进行修改,它不会影响到原始数据,物理内存不在同一位置。
视图是数据的一个别称或引用,通过该别称或引用亦便可访问、操作原有数据,但原有数据不会产生拷贝。如果我们对视图进行修改,它会影响到原始数据,物理内存在同一位置。
赋值不会创建数组对象的副本,它会使用原始数组的相同id()来访问它,因此,被赋值对象的任何改变都会同时影响原始对象。
ndarray.view()方法会创建一个新的数组对象,更改新的数组形状不会影响到原始数据的形状。
import numpy as np
a = (100*np.random.randn(1,3,4).round(2))
# 视图对象与原数组存储位置不同
print(id(a))
print(a[0,0,0])
b = a.view()
print(id(b))
# 修改视图对象的形状不会影响到原数组
b.shape = (2,2,3)
print(b.shape)
print(a.shape)
# 修改内容会影响到原始数据
b[0,0,0] += 1
print(b[0,0,0])
print(b[0,0,0]==a[0,0,0])
输出结果:
# 视图对象与原数组存储位置不同
1958816723472
-68.0
1958816723552
# 修改视图对象的形状不会影响到原数组
(2, 2, 3)
(1, 3, 4)
# 修改内容会影响到原始数据
-67.0
True
切片器原理也是创建视图,修改视图将影响到原始数组。
ndarray.copy()创建一个副本。对副本数据进行修改不会影响到原始数据,它们物理内存不在同一位置。
NumPy中包含了一个矩阵库numpy.matlib,该模块中的函数返回的是一个矩阵,而不是ndarray对象。
这个库快要废掉了,建议不要用。
ndarray.T
返回一个随机数填充的矩阵。
numpy.matlib.empty(shape, dtype, order)
- shape: 整数或整数元组
- order: C(行序优先)或F(列序优先)
返回一个零矩阵。
返回一个以1填充的矩阵。
返回一个广义的对角矩阵。
numpy.matlib.eye(n, M,k, dtype)
- n: 行数
- M: 列数,默认为n
- k:对角线索引
import numpy as np
import numpy.matlib
a = np.matlib.eye(n = 3, M = 4, k = 1)
print(a)
输出结果:
[[0. 1. 0. 0.]
[0. 0. 1. 0.]
[0. 0. 0. 1.]]
返回给定大小的单位矩阵。
NumPy提供了线性代数函数库linalg,包含了线性代数所需的所有功能
简单记一下,dot()计算二维矩阵的矩阵乘积。
numpy.dot(a, b, out=None)
- numpy.dot() 对于两个一维的数组,计算的是这两个数组对应下标元素的乘积和(数学上称之为内积);对于二维数组,计算的是两个数组的矩阵乘积;对于多维数组,它的通用计算公式如下,即结果数组中的每个元素都是:数组a的最后一维上的所有元素与数组b的倒数第二维上的所有元素的乘积和:
dot(a, b)[i,j,k,m] = sum(a[i,j,:] * b[k,:,m])
计算两个向量的内积。如果第一个参数是复数,那么它的共轭复数会用于计算。如果参数是多维数组,将自动展开计算。
numpy.matmul 函数返回两个数组的矩阵乘积。虽然它返回二维数组的正常乘积,但如果任一参数的维数大于2,则将其视为存在于最后两个索引的矩阵的栈,并进行相应广播。
另一方面,如果任一参数是一维数组,则通过在其维度上附加 1 来将其提升为矩阵,并在乘法之后被去除。
对于二维数组,它就是矩阵乘法。
计算矩阵行列式。
给出了矩阵形式的线性方程的解。
计算逆矩阵(inverse matrix)。
import numpy as np
a = np.array([
[1,1,1],
[0,2,5],
[2,5,-1]
])
b = np.array([6,-4,27])
print(a)
print(b)
# 解法1:
x = np.linalg.solve(a,b)
print(x)
# 解法2:
## 求逆矩阵
ainv = np.linalg.inv(a)
print(ainv)
## 逆矩阵*向量b
y = np.dot(ainv,b)
print(y)
print(x==y)
输出结果:
[[ 1 1 1]
[ 0 2 5]
[ 2 5 -1]]
[ 6 -4 27]
[ 5. 3. -2.]
[[ 1.28571429 -0.28571429 -0.14285714]
[-0.47619048 0.14285714 0.23809524]
[ 0.19047619 0.14285714 -0.0952381 ]]
[ 5. 3. -2.]
[ True False False]
Numpy 可以读写磁盘上的文本数据或二进制数据。
NumPy 为 ndarray 对象引入了一个简单的文件格式:npy,npy 文件用于存储重建 ndarray 所需的数据、图形、dtype 和其他信息。
常用的 IO 函数有:
numpy.save(file, arr, allow_pickle=True, fix_imports=True)
- allow_pickle: 可选,布尔值,允许使用 Python pickles 保存对象数组,Python 中的 pickle 用于在保存到磁盘文件或从磁盘文件读取之前,对对象进行序列化和反序列化。
- fix_imports: 可选,为了方便 Pyhton2 中读取 Python3 保存的数据
将多个数组保存到以 npz 为扩展名的文件中。
numpy.savez(file, *args, **kwds)
- file:要保存的文件,扩展名为 .npz,如果文件路径末尾没有扩展名 .npz,该扩展名会被自动加上。
- args: 要保存的数组,可以使用关键字参数为数组起一个名字,非关键字参数传递的数组会自动起名为 arr_0, arr_1, … 。
- kwds: 要保存的数组使用关键字名称。
以简单的文本文件格式存储数据,对应的使用 loadtxt() 函数来获取数据。
np.loadtxt(FILENAME, dtype=int, delimiter=’ ')
np.savetxt(FILENAME, a, fmt="%d", delimiter=",")
- delimiter:可以指定各种分隔符、针对特定列的转换器函数、需要跳过的行数等
Matplotlib 是 Python 的绘图库。 它可与 NumPy 一起使用,提供了一种有效的 MatLab 开源替代方案。 它也可以和图形工具包一起使用,如 PyQt 和 wxPython。
import numpy as np
from matplotlib import pyplot as plt
# 基本操作
x = np.arange(1,11)
y = x**2+5
plt.title("Matplotlib demo")
plt.xlabel("x axis caption")
plt.ylabel("y axis caption")
plt.plot(x,y)
plt.show()
输出结果:
import numpy as np
from matplotlib import pyplot as plt
x = np.arange(1,11)
y = x**2+5
# 获取字体列表
f = sorted([f.name for f in matplotlib.font_manager.fontManager.ttflist])
# 设置中文字体
plt.rcParams['font.family']=['STFangsong']
plt.title("绘图测试")
plt.xlabel("x轴")
plt.ylabel("y轴")
plt.plot(x,y)
plt.show()
import numpy as np
from matplotlib import pyplot as plt
import matplotlib
x = np.arange(1,11)
y = x**2+5
# fname 为 你下载的字体库路径,注意 SourceHanSansSC-Bold.otf 字体的路径
zhfont1 = matplotlib.font_manager.FontProperties(fname="SourceHanSansSC-Bold.otf")
x = np.arange(1,11)
y = 2 * x + 5
plt.title("菜鸟教程 - 测试", fontproperties=zhfont1)
# fontproperties 设置中文显示,fontsize 设置字体大小
plt.xlabel("x 轴", fontproperties=zhfont1)
plt.ylabel("y 轴", fontproperties=zhfont1)
plt.plot(x,y)
plt.show()
作为线性图的替代,可以通过向 plot() 函数添加格式字符串来显示离散值。
import numpy as np
from matplotlib import pyplot as plt
import matplotlib
x = np.arange(1,11)
y = x**2+5
plt.title("Matplotlib demo")
plt.xlabel("x axis caption")
plt.ylabel("y axis caption")
plt.plot(x,y,"ob") # 蓝色圆点
plt.show()
还可以设置品红色水平线标记:)
plt.plot(x,y,"_m") # 品红色水平线标记
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(-np.pi, np.pi, 0.01)
y = np.sin(x)
plt.title("sine wave")
plt.plot(x,y)
plt.show()
在同一张图中绘制不同的图形。
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(-np.pi, np.pi, 0.01)
y1 = np.sin(x)
y2 = np.cos(x)
# 建立subplot网格,高为2,宽为1
plt.subplot(2,1,1) # 激活第一个网格
# 绘制第一个图象
plt.plot(x, y1)
plt.title("Sine Wave")
# 绘制第二个图象
plt.subplot(2,1,2) # 激活第二个网格
plt.plot(x, y2)
plt.title("Cosine Wave")
plt.show()
利用numpy.array(y1,y2).T生成对应shape的数组,并将其整个作为对象放入y轴。
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(-np.pi, np.pi, 0.01)
y1 = np.sin(x)
y2 = np.cos(x)
plt.plot(x,np.array([y1,y2]).T)
plt.show()
或者使用以下语句,分两次将曲线添加至绘图区域中:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(-np.pi, np.pi, 0.01)
y1 = np.sin(x)
y2 = np.cos(x)
plt.plot(x,y1,color='g')
plt.plot(x,y2,color='b')
plt.show()
from matplotlib import pyplot as plt
x1 = [5,8,10]
y1 = [12,16,6]
x2 = [6,7,9]
y2 = [6,8,7]
plt.bar(x1, y1, align = 'center')
plt.bar(x2, y2, color = 'g', align = 'center')
plt.title('Bar Graph')
plt.ylabel('Population (in million)')
plt.xlabel('Month')
plt.show()
numpy.histogram()函数是数据的频率分布的图形表示。水平尺寸相等的矩形对应于类间隔,称为bin,变量height对应于频率。
numpy.histogram()将输入数组和bin作为两个参数。bin数组中的连续元素用作每个bin的边界。
import numpy as np
from matplotlib import pyplot as plt
a = np.random.rand(100).round(1)*10
print(a)
b = np.linspace(start=0,stop=10,num=6)
print(b)
# 查看numpy.histogram的内容
h = np.histogram(a, bins = b)
print(h)
# 绘制直方图
plt.hist(a, bins = b)
plt.title("Histogram Test")
plt.show()
输出结果:
[ 0. 2. 4. 6. 8. 10.]
(array([12, 20, 27, 18, 23], dtype=int64), array([ 0., 2., 4., 6., 8., 10.]))