class="burk">
import numpy as np
%matplotlib inline div><i class="fa fa-lightbulb-o ">i>
%matplotlib inline 使matplotlib图表在notebook中直接显示
定义数组
a=np.array([1,2,3,4]) #llist文件可以转换为怒骂
b=np.array((5,6,7))
c=np.array([[1,2,3],[1,2,4],[4,6,7]])#此处维数一定要相等,不然不会成为一个矩阵
print(a)
print(b)
print(c)
[1 2 3 4]
[5 6 7]
[[1 2 3]
[1 2 4]
[4 6 7]]
a.shape
(4,)
b.shape
(3,)
c.shape
(3, 3)
- 如何更改数组维数
c.reshape(9,1)
array([[1],
[2],
[3],
[1],
[2],
[4],
[4],
[6],
[7]])
c.reshape(1,9)
array([[1, 2, 3, 1, 2, 4, 4, 6, 7]])
reshape并不会单独创建一个数组,而是在原有数组的基础上共享存储空间,修改reshape数组的值,会使得原有的数组数值也发生改变
更改类型
使用astype()函数改变数组的数据类型
c.dtype
dtype('int32')
c.astype(np.float)
array([[1., 2., 3.],
[1., 2., 4.],
[4., 6., 7.]])
自动生成数组
- 使用arange()通过指定开始值、终止值和步长来生成一个等差数列的一维数组,但是得到的结果不包括终值
a=np.arange(0,1,0.1)
print(a)
[0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9]
- 使用linspace()通过指定开始值、终止值和元素个数来生成一个等差数列的一维数组,可以通过endpoint参数来指定是否包含终值,默认值为TRUE
np.linspace(0,1,10)
array([0. , 0.11111111, 0.22222222, 0.33333333, 0.44444444,
0.55555556, 0.66666667, 0.77777778, 0.88888889, 1. ])
np.linspace(0,1,10,endpoint=False)
array([0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9])
- 使用logspace()通过指定开始值、终止值和元素个数来生成一个以10为底数列的一维数组,通过base参数可以改变底数
np.logspace(0,2,5)
array([ 1. , 3.16227766, 10. , 31.6227766 ,
100. ])
np.logspace(0,2,5,base=2,endpoint=False)
array([1. , 1.31950791, 1.74110113, 2.29739671, 3.03143313])
- ones(),zeros(),empty()函数可以创建一个元素为1,0,空的数组,第一个参数可以指定数组的形状,第二个参数可以指定数组元素的类型
np.ones(4,np.int)
array([1, 1, 1, 1])
np.ones((4,4),np.int)
array([[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]])
- 使用函数来基于下标创建数组
def func(i):
x=i % 4 + 1
return x
np.fromfunction(func,(10,))#此处应该注意,如果函数只有一个输入,那么数组就只能是一维的
array([1., 2., 3., 4., 1., 2., 3., 4., 1., 2.])
def func2(i,j):
return (i+1)*(j+1)
np.fromfunction(func2,(9,9))#下标是从0开始计数的
array([[ 1., 2., 3., 4., 5., 6., 7., 8., 9.],
[ 2., 4., 6., 8., 10., 12., 14., 16., 18.],
[ 3., 6., 9., 12., 15., 18., 21., 24., 27.],
[ 4., 8., 12., 16., 20., 24., 28., 32., 36.],
[ 5., 10., 15., 20., 25., 30., 35., 40., 45.],
[ 6., 12., 18., 24., 30., 36., 42., 48., 54.],
[ 7., 14., 21., 28., 35., 42., 49., 56., 63.],
[ 8., 16., 24., 32., 40., 48., 56., 64., 72.],
[ 9., 18., 27., 36., 45., 54., 63., 72., 81.]])
需要注意的是,这种方法创建的数组,函数有多少个参数,就只能产生多少维的数组
存取元素
一维数组的存取
a=np.arange(10)
a[4]#取一个
2.792526803190927
a[0:5]#按列表取值
array([0, 1, 2, 3, 4])
a[:6:2]#按固定步长取值
array([0, 2, 4])
a[a>5]
array([6, 7, 8, 9])
- 取值的时候也可对相应的位置赋值,因此上面取值的操作也可以用来进行赋值,修改数组元素
- 此外,通过此存取元素来赋值给另外一个对象,将产生一个新的内存空间,因此此时对新对象进行修改并不会对原数组产生影响
多维数组的存取
c=np.fromfunction(func2,(9,9))
print(c,c.shape)
[[ 1. 2. 3. 4. 5. 6. 7. 8. 9.]
[ 2. 4. 6. 8. 10. 12. 14. 16. 18.]
[ 3. 6. 9. 12. 15. 18. 21. 24. 27.]
[ 4. 8. 12. 16. 20. 24. 28. 32. 36.]
[ 5. 10. 15. 20. 25. 30. 35. 40. 45.]
[ 6. 12. 18. 24. 30. 36. 42. 48. 54.]
[ 7. 14. 21. 28. 35. 42. 49. 56. 63.]
[ 8. 16. 24. 32. 40. 48. 56. 64. 72.]
[ 9. 18. 27. 36. 45. 54. 63. 72. 81.]] (9, 9)
c[(0,1,2,3),(1,2,3,4)]#通过两个列表来取,这样的取法列表对应元素会组合成下标
array([ 2., 6., 12., 20.])
c[6::,[0,2,5]]
array([[ 7., 21., 42.],
[ 8., 24., 48.],
[ 9., 27., 54.]])
mask=np.array([1,0,0,1,0,1,0,1,0],dtype=np.bool)#布尔列表来取值
c[mask,2]
array([ 3., 12., 18., 24.])
高级操作
结构数组
自定义数组类型
persontype=np.dtype({
'names':['name','weight','age'], #定义列
'formats':['S30','f','i']},align=True) # 定义列类型
a=np.array([('zhang',80.0,18),('wang',70.5,25)],dtype=persontype )
print(a[0])
print(a[0][1])
print(a[0]['weight'])
(b'zhang', 80., 18)
80.0
80.0
需要注意的是,a[0]与a共享内存,此时修改a[0]也会对a的元素造成改变
a[0]['name']='li'
a
array([(b'li', 80. , 18), (b'wang', 70.5, 25)],
dtype={'names':['name','weight','age'], 'formats':['S30','
创建共享内存数组
- 使用view()
a=np.array([[0,1],[2,3],[4,5]],dtype=np.float32)
b=a.view(np.uint32)
c=a.view(np.uint8)
print(a)
print(b)
print(c)
[[0. 1.]
[2. 3.]
[4. 5.]]
[[ 0 1065353216]
[1073741824 1077936128]
[1082130432 1084227584]]
[[ 0 0 0 0 0 0 128 63]
[ 0 0 0 64 0 0 64 64]
[ 0 0 128 64 0 0 160 64]]
c[0,4]=32
print(a)
print(c)
[[0. 1.0000038]
[2. 3. ]
[4. 5. ]]
[[ 0 0 0 0 32 0 128 63]
[ 0 0 0 64 0 0 64 64]
[ 0 0 128 64 0 0 160 64]]
- 使用as_stride()
from numpy.lib.stride_tricks import as_strided #导入as_strided函数
a=np.arange(6)
b=as_strided(a,shape=(4,3),strides=(4,4))
(4,)
b
# print(b.strides)
array([[0, 1, 2],
[1, 2, 3],
[2, 3, 4],
[3, 4, 5]])
a[2]=20
print(a)
[ 0 1 20 3 4 5]
b
array([[ 0, 1, 20],
[ 1, 20, 3],
[20, 3, 4],
[ 3, 4, 5]])
使用as_strided能够创建一个以某个数组为基础的,自定义形状的数组,strides参数指定了数组的stride属性
ufunc函数
更改numpy类型为标准型——item()函数
a=np.linspace(0,2*np.pi,10)
b=np.sin(a)
b=b.reshape(5,2)
print(b[4,1],type(b.item(4,1)),type(b[4,1]))#此处将numpy数据类型更改为了标准python数据类型
-2.4492935982947064e-16
四则运算函数
- 加法
a=np.arange(0,5)
b=np.arange(4,9)
np.add(a,b)
array([ 4, 6, 8, 10, 12])
np.add(a,b,a)
array([ 4, 6, 8, 10, 12])
- 其他运算函数
自定义ufunc函数
过 NumPy 提供的标准 uflinc 函数,可以组合出复杂的表达式,在 C 语言级別对数组的每个元素进行计算。但有吋这种表达式不易编写,而对每个元素进行计算的程序却很容易用Python实现,这时可以用 frompyfunc(),将计算单个元素的函数转换成ufunc()函数,这样就可以方便地用所产生的ufunc()函数对数组进行计算了
def triangle_wave(x, c, c0, he):
x = x - int(x) # 三角波的周期为 1 ,因此只取 x 坐标的小数部分进行计算
if x >= c: r = 0.0
elif x < c0: r = x / c0 * he
else: r = (c-x) / (c-c0) * he
return r
triangle_ufunci = np.frompyfunc(triangle_wave, 4, 1)
x=np.linspace(0,2,100)
y2 = triangle_ufunci(x,0.6 ,0.4 ,1.0)
基本步骤:
- 定义python标准函数
- 使用frompyfunc(),将python标准函数转换为ufunc,其中frompyfunc()内的参数是python标准函数的输入变量个数和输出变量个数
- 将实例化的ufunc指定参数和输入
注意事项:
y2返回的类型并不是标准的numpy数据类型,因此需要astype()转换为标准的numpy数据类型
广播
当使用 uftinc 函数对两个数组进行计算时, ullinc 函数会对这两个数组的对应元素进行计算,因此它要求这两个数组的形状相同。如果形状不同,会进行如下广播(broadcasting )处理:
1. 让所有输入数姐都向其中维数最多的数绀看齐, shape 属性中不足的部分都通过在前面加
1补齐。
2. 输出数组的 shape 属性是输入数组的 shape 屈性的各个轴上的最大值。
3. 如果输入数组的某个轴的 L <:度 为 1或与输出数组的对应轴的长度相同,这个数组能够用
来计算,否则出错。
4. 当输入数组的某个轴的长度为1时,沿着此轴运算时都用此轴上的第一组值。
ogrid
**Ogrid 是一个很有趣的对象,它像多维数组一样,用切片元组作为下标,返回的是一组可以
用来广播计算的数组。其切片下标有两种形式:**
- 开始值:结束值:步长,和 np.amnge (开始值,结朿值,步长)类似。
- **幵始值:结朿值:长度 j ,当第三个参数为虚数时,它表示所返冋的数组的长度,和
np.linspace (开始值,结朿值,长度)类似。**
x, y = np.ogrid[:1:4j, :1:3j]
x,y
(array([[0. ],
[0.33333333],
[0.66666667],
[1. ]]), array([[0. , 0.5, 1. ]]))
注意:ogrid不是函数!!!
根据Python的语法,只有在中括号中才能使用用冒号隔开的切片语法,如果ogrid是函数的话,那么这些切片必须使用slice函数创建,这显然会增加代码的长度。
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(figsize=(16,9))
ax = fig.add_subplot(111, projection='3d')
x,y=np.ogrid[-2:2:20j,-2:2:20j]
z=x*np.exp(-x**2-y**2)
ax.plot_surface(x,y,z,rstride=4,cstride=2,cmap=plt.cm.Blues_r)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
plt.show()
mgrid
mgrid用法和ogrid很像,但是他所返回的是进行广播之后的数组
a,b=np.mgrid[0:5,0:5]
a
array([[0, 0, 0, 0, 0],
[1, 1, 1, 1, 1],
[2, 2, 2, 2, 2],
[3, 3, 3, 3, 3],
[4, 4, 4, 4, 4]])
b
array([[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4]])
ufunc方法
- None方法
a=np.arange(4)
a[None,:]
array([[0, 1, 2, 3]])
a[:,None]
array([[0],
[1],
[2],
[3]])
这种方法同reshape方法中的(-1,1)类似
ix_()方法
x=np.arange(5)
y=np.arange(5)
gx,gy=np.ix_(x,y)
gx
array([[0],
[1],
[2],
[3],
[4]])
gy
array([[0, 1, 2, 3, 4]])
gx+gy
array([[0, 1, 2, 3, 4],
[1, 2, 3, 4, 5],
[2, 3, 4, 5, 6],
[3, 4, 5, 6, 7],
[4, 5, 6, 7, 8]])
reduce方法
r1=np.add.reduce([1,2,3])
r2=np.add.reduce([[1,2,3],[4,5,6]],axis=1)
r1,r2
(6, array([ 6, 15]))
accumulate方法
r1=np.add.accumulate([1,2,3])
r2=np.add.accumulate([[1,2,3],[4,5,6]],axis=1)
r1,r2
(array([1, 3, 6], dtype=int32), array([[ 1, 3, 6],
[ 4, 9, 15]], dtype=int32))
reduceat()方法
reduceat() 方法计算多组reduce() 的结果,通过indices参数指定一系列的起始和终止位置。它的计算有些特别,让我们通过例子详细解释一下:
a = np.array([1 , 2, 3, 4])
result = np.add.reduceat(a, indices=[0, 1, 0, 2, 0, 3, 0])
result
array([ 1, 2, 3, 3, 6, 4, 10], dtype=int32)
对于 indices参数中的每个元素都会计算出一个值,因此最终的计算结果和 indices参数的长度相同。结果数组result中除最后一个元素之外,都按照如下计算得出:
if indices[i] < indices[i+1]:
result[i] = .reduce(a[indices[i]:indices[i+1]])
else:
result[i] = a[indices[i]]
而最后一个元素如下计算:
.reduce(a[indices[-1]:])
因此在上面的例子中,数组 insult 的每个元素按照如下计算得出:
1 : a[0] -> 1
2 : a[l] -> 2
3 : a[0] + a[l] -> 1 + 2
3 : a[2] -> 3
6 : a[0] + a[l] + a[2] -> l + 2 + 3 = 6
4 : a[3] -> 4
a[0] + a[l] + a[21 + a[4l - > 1 + 2 + 3 + 4 = 1 0
庞大的函数库
随机数
import numpy as np
from numpy import random as nr
np.set_printoptions(precision=2) # 为了节街篇幅,只显示小数点后两位数字
r1 = nr.rand(4, 3)
r2 = nr.randn(4, 3)
n3 = nr.randint(0, 10, (4, 3))
print(r1,'\n',r2,'\n',n3)
[[0.95 0.1 0.55]
[0.82 0.47 0.58]
[0.99 0.9 0.43]
[0.57 0.69 0.97]]
[[-1.57 -0.15 -0.64]
[-0.77 0.72 -0.07]
[ 0.05 0.47 -0.51]
[-0.11 -0.89 -1.38]]
[[6 7 5]
[3 0 4]
[5 7 9]
[3 8 8]]
随机相关函数
random 模块提供了许多产生符合特定随机分布的随机数的函数,它们的最后一个参数size都用于指定输出数组的形状,而其他参数都是分布函数的参数。例如
- normal():正态分布,前两个参数分别为期望值和标准差。
- uniform():均匀分布,前两个参数分别为区间的起始值和终值。
- poisson():泊松分布,第一个参数指定A系数,它表示单位时间(或单位而积)内随机事件的平均发生率。由于泊松分布是一个离散分布,因此它输出的数组是一个整数数组
r1 = nr.normal(100, 10, (4,3))
r2 = nr.uniform(10, 20, (4,3))
r3 = nr.poisson(2.0, (4, 3))
rl,r2,r3
(array([[0.98, 0.17, 0.76],
[0.67, 0.65, 0.74],
[0.62, 0.84, 0.11],
[0.66, 0.72, 0.57]]), array([[15.01, 17.26, 13.55],
[13.64, 19.82, 16.09],
[13.78, 18.79, 19.44],
[12.53, 17.87, 15.52]]), array([[2, 3, 1],
[2, 3, 1],
[0, 0, 3],
[4, 1, 4]]))
permutation()可以用于产生一个乱序数组,当参数为整数n时,它返回[0, n )这n个整数的随机排列;当参数为一个序列吋,它返冋一个随机排列之后的序列:
a = np.array([1, 10, 20, 30, 40])
print (nr.permutation(10))
print (nr.permutation(a))
[7 0 5 3 6 8 4 1 2 9]
[20 10 1 40 30]
permutation()返回一个新数组,而 shuffle()则直接将参数数组的顺序打乱
choice()从指定的样木中随机进行抽取:
- size 参数用于指定输出数组的形状。
- replace 参数为True时,可进行重复抽取,而为 False时,则进行不重复抽取,默认值为 True 。
- p 参数指定每个元素对应的抽収概率,如果不指定,所有的元素被抽取到的概率相同。
a = np.arange(10, 25, dtype=float)
c1 =nr.choice(a,size=(4,3))
c2 = nr.choice(a,size=(4, 3), replace=False)
c3 = nr.choice(a, size=(4, 3),p=a / np.sum(a))
c1,c2,c3
(array([[23., 19., 13.],
[15., 12., 14.],
[14., 14., 23.],
[23., 24., 24.]]), array([[19., 11., 21.],
[12., 10., 20.],
[23., 17., 16.],
[14., 22., 24.]]), array([[13., 15., 17.],
[21., 16., 16.],
[16., 23., 21.],
[12., 15., 15.]]))
为了保证每次运行时能重现相同的随机数,可以通过seed()函数指定随机数的种子
求和,平均数、方差
求和sum
sum()计算数组元素之和,也可以对列表、元组等与数组类似的序列进行求和。当数组是多维时,它计算数组中所有元素的和。如果指定axis参数,则求和运算沿着指定的轴进行==当 axis 参数是一个轴的序列时,对指定的所有轴进行求和运算。例如下面的程序对一个形
状为(2,3,4)的三维数组的第0 和第2 轴求和,得到的结果为一个形状为(3,)的数组。由于数组的
所有元素都为1 , 因此求和的结果都是8:==
有时我们希望能够保持原数组的维数,这时可以设置 keepdims 参数为 True:
np.random.seed(42)
a=np.random.randint(0,10,(4,5))
print(a)
print(np.sum(a,axis=0))
print(np.sum(a,axis=1))
[[6 3 7 4 6]
[9 2 6 7 4]
[3 7 7 2 5]
[4 1 7 5 1]]
[22 13 27 18 16]
[26 28 24 18]
如下面的程序对一个形
状为(2,3,4)的三维数组的第0 和第2 轴求和,得到的结果为一个形状为(3,)的数组。由于数组的
所有元素都为1 , 因此求和的结果都是8:==
有时我们希望能够保持原数组的维数,这时可以设置 keepdims 参数为 True:
np.sum(np.ones((2,3,4)),axis=(0,2))
array([8., 8., 8.])
np.sum(a,1,keepdims=True)
array([[26],
[28],
[24],
[18]])
均值mean
mean()求数组的平均值,它的参数与 sum()相同。和sum()不同的是:对于整数数组它使double双精度浮点数进行计算,而对于其他类型的数组,则使用和数组元素类型相同的累加变量进行计算:
np.mean(a,axis=1)
array([5.2, 5.6, 4.8, 3.6])
average也可以用来对数组进行平均值计算,但是它没有out参数和dtype参数,但是有一个指定每个元素权重的weights参数,用于计算加强平均数
score=np.array([83,96,87])
weight=np.array([20,30,50])
np.average(score,weights=weight)
88.9
标准差和方差
当 ddof 参数为0时,计算偏样本方差;当 ddof为1时,计算无偏样本方差,默认值为0。
首先产生-•个标准差为2.0、方差为4.0的正态分布的随机数组。我们可以认为总体样本的方差为4.0。假设从总体样本中随机抽取10个样本,我们分別计算这10个样本的两种方差,里我们用一个二维数组重复上述操作10000次,然后计算所有这些方差的期望值:
np.set_printoptions(precision=4)
a=nr.normal(0,2.0,(10000,10))
print(np.var(a,axis=0,ddof=0))
print(np.var(a,axis=0,ddof=1))
[3.9997 3.9564 4.022 4.1211 3.9718 3.9189 3.9056 4.0568 4.014 4.1131]
[4.0001 3.9568 4.0224 4.1215 3.9722 3.9193 3.906 4.0572 4.0144 4.1135]
大小与排序
max 和min
用 min()和max()可以汁算数组的最小值和最大值,它们都有 axis 、 out、keepdims 等参数
argmax 和 argmin
用 argmax()和argmin()可以求最大值和最小值的下标。如果指定axis参数,则返回平坦化之后的数组下标,例如下面的程序找到a中最大值的下标,有多个最值时得到第一个最值的下标:
a=np.array([1,3,5,7])
b=np.array([2,4,6,5])
np.maximum(a,b)
array([2, 4, 6, 7])
np.random.seed(42)
a=np.random.normal(0,2.0,(10,10))
print(a)
np.argmax(a)
[[ 0.9934 -0.2765 1.2954 3.0461 -0.4683 -0.4683 3.1584 1.5349 -0.9389
1.0851]
[-0.9268 -0.9315 0.4839 -3.8266 -3.4498 -1.1246 -2.0257 0.6285 -1.816
-2.8246]
[ 2.9313 -0.4516 0.1351 -2.8495 -1.0888 0.2218 -2.302 0.7514 -1.2013
-0.5834]
[-1.2034 3.7046 -0.027 -2.1154 1.6451 -2.4417 0.4177 -3.9193 -2.6564
0.3937]
[ 1.4769 0.3427 -0.2313 -0.6022 -2.957 -1.4397 -0.9213 2.1142 0.6872
-3.5261]
[ 0.6482 -0.7702 -1.3538 1.2234 2.062 1.8626 -1.6784 -0.6184 0.6625
1.9511]
[-0.9583 -0.3713 -2.2127 -2.3924 1.6251 2.7125 -0.144 2.0071 0.7233
-1.2902]
[ 0.7228 3.0761 -0.0717 3.1293 -5.2395 1.6438 0.1741 -0.598 0.1835
-3.9751]
[-0.4393 0.7142 2.9558 -1.0365 -1.617 -1.0035 1.8308 0.6575 -1.0595
1.0265]
[ 0.1942 1.9373 -1.4041 -0.6553 -0.7842 -2.927 0.5922 0.5221 0.0102
-0.4692]]
31
a.ravel()[31]
3.7045563690178756
np.unravel_index(31,a.shape)
(3, 1)
a[3,1]
3.7045563690178756
sort排序
数组的 sort()方法对数组进行排序,它会改变数组的内备而 sort ()函数则返冋一个新数组,
不改变原始数组。它们的 axis 默认值都为-1,即沿着数组的最终轴进行排序。 sort()函数的 axis
参数可以设置为None,此时它将得到平识化之后进行排序的新数组。在下面的例子中,np.sort(a)对a中每行的数值进行排序,而np.sort(a,axis=0)对数组a每列上的数值进行排序
np.sort(a)
array([[-0.9389, -0.4683, -0.4683, -0.2765, 0.9934, 1.0851, 1.2954,
1.5349, 3.0461, 3.1584],
[-3.8266, -3.4498, -2.8246, -2.0257, -1.816 , -1.1246, -0.9315,
-0.9268, 0.4839, 0.6285],
[-2.8495, -2.302 , -1.2013, -1.0888, -0.5834, -0.4516, 0.1351,
0.2218, 0.7514, 2.9313],
[-3.9193, -2.6564, -2.4417, -2.1154, -1.2034, -0.027 , 0.3937,
0.4177, 1.6451, 3.7046],
[-3.5261, -2.957 , -1.4397, -0.9213, -0.6022, -0.2313, 0.3427,
0.6872, 1.4769, 2.1142],
[-1.6784, -1.3538, -0.7702, -0.6184, 0.6482, 0.6625, 1.2234,
1.8626, 1.9511, 2.062 ],
[-2.3924, -2.2127, -1.2902, -0.9583, -0.3713, -0.144 , 0.7233,
1.6251, 2.0071, 2.7125],
[-5.2395, -3.9751, -0.598 , -0.0717, 0.1741, 0.1835, 0.7228,
1.6438, 3.0761, 3.1293],
[-1.617 , -1.0595, -1.0365, -1.0035, -0.4393, 0.6575, 0.7142,
1.0265, 1.8308, 2.9558],
[-2.927 , -1.4041, -0.7842, -0.6553, -0.4692, 0.0102, 0.1942,
0.5221, 0.5922, 1.9373]])
中位数
用 median() 可以获得数组的中值,即对数组进行排序之后,位于数组中间位置的值。当长度是偶数时,则得到正中间两个数的平均值。它也可以指定 axis 和 out 参数
np.median(a,axis=1)
array([ 1.0393, -1.4703, -0.5175, -0.6152, -0.4168, 0.6553, -0.2577,
0.1788, 0.1091, -0.2295])
百分位数
percentile() 用于计算百分位数,即将数值从小到大排列,计算处于 p % 位置上的值。下面的
程序计兑标准正态分布随机数的绝对值在68.3%、95.4%以及99.7%处的百分位数,它们应该约
等于1倍、2倍和3倍的标准差
r=np.random.randn(100000)
np.percentile(r,[68.3,95.4,99.7])
array([0.477 , 1.6882, 2.7339])
统计函数
unique
返回其参数数组中所有不同的值,并且按照从小到大的顺序排列。它有两个可选
参数:
- return_index:True表示同时返回原始数组中的下标。
- return_inverse : True 表示返回重建原始数组用的下标数组
np.random.seed(42)
a=np.random.randint(0,8,10)
print(a)
np.unique(a)
[6 3 4 6 2 7 4 4 6 1]
array([1, 2, 3, 4, 6, 7])
bincount
bincount() 对整数数组中各个元素所出现的次数进行统计,它要求数组中的所有元素都是非
负的。其返回数组中第 i 个元素的值表示整数 i 出现的次数。==通 过 weights 参数可以指定每个数所对应的权值。当 指 定 weights 参数时, bincount ( x ,
weights = w )返回数组x 中的每个整数所对应的 w 中的权值之和。 jjj 文字解释比较难以理解,下
面我们看一个实例:==
np.bincount(a)
array([0, 1, 1, 1, 3, 0, 3, 1], dtype=int64)
histogram
histogram ()对一维数组进行直方图统计。其参数列表如下:
histogram(a,bins=10, range=None,weights=None,density=False)
其中 a 是保存待统计数据的数组, bins 指定统计的区间个数,即对统计范围的等分数。range是一个长度为 2的元组,表示统计范围的最小值和最大值,默认值为范围决定,即 (a.min(), a .max())。当density 参数为 False时,函数返回a中的数掘在每个区间的个数,参数为 True 则返回每个区间的概率密度。weights 参数和 bincount()的类似。
histogram ()返回两个一维数组 —— hist和bin_edges,第一个数组是每个区间的统计结果,
第二个数组的长度为 len ( hist )+ 1 , 每两个相邻的数值构成一个统计区间。下而我们看一个例子
a=np.random.rand(100)
np.histogram(a,bins=5,range=(0,1))
(array([28, 18, 17, 19, 18], dtype=int64),
array([0. , 0.2, 0.4, 0.6, 0.8, 1. ]))
分段函数
where函数
在Numpy中, where ()函数可以看作判断表达式的数组版本:
x = where(conditionj y, z)
其中 condition 、 y 和 z 都楚数组,它的返回值是一个形状与 condition 相同的数组。当 condition
中的某个元素为true 时, x 中对应下标的值从数组 y 获取,否则从数组 z 获取:
import numpy as np
x=np.arange(10)
np.where(x<5,9-x,x)
array([9, 8, 7, 6, 5, 5, 6, 7, 8, 9])
select()
随着分段函数的分段数量的增加,需要嵌套更多层 where()。这样不便于程序的编写和阅读。
可以用 select()解决这个问题,它的调用形式如下:
select(condlist, choicelist, default=0)
其中 condlist 是一个长度为M 的布尔数组列表, choicelist 是一个长度为M的存储候选值的
数组列表,所有数组的长度都为 M 。如果列表元素不是数组而是单个数值,那么它相当于元素
值都相同、长度为 M 的数组
def triangle_wave2(x, c0, hc):
x = x - x.astype(np.int)
return np.select([x >= c,x < c0 , True ],
[0 , x/c0*hc, (c-x)/(c-c0)*hc])
piecewise
计算时还会产生许多保留中间结果的数组,因此如果输入的数组 X 很大,将会发生大量内存分配和释放。为了解决这个问题, NumPy 提供了piecewise()专门用于计算分段函数,它的调叫参数如下
piecewise(X, condlist, funclist)
参数x是一个保存自变量值的数组, condlist是一个长度为M的布尔数组列表,其中的每个布尔数组的长度都和数组x相同。funclist是一个长度为 M 或M+1的闲数列表,这些函数的输入和输出都是数组。
def triangle_wave3(x, c, c0, hc):
x = x - x.astype(np.int)
return np.piecewise(x,
[x >= c, x < c0],
[0, # x>=c
lambda x: /c0 * hc, # x
lambda x: (c - x) / (c - c0) * he]) # else
操纵多维数组
1. concatenate ()是连接多个数组 的最基本函数,其他函数都是它的快捷版本。它的第一个参数是包含多个数组的序列,它将沿着axis参数指定的轴(默认为第0轴)连接数组。所有这些数组的形状除了第 axis 轴之外都相同。
2. vstack()沿着第0轴连接数组,当被连接的数组是长度为N的一维数组时,将其形状改为(1,N )
3. hstack()沿着第1轴连接数组。当所有数组都是一维时,沿着第0 轴连接数组,因此结果数组仍然为一维的。
4. column_stack()和hstack()类似,沿着第1轴连接数组,但是当数组为一维时,将其形状改为(N,1),经常用于按列连接多个一维数组。
5. 此外, c_[ ]对象也可以用于按列连接数组
a=np.arange(3)
b=np.arange(10,13)
np.vstack((a,b))
array([[ 0, 1, 2],
[10, 11, 12]])
np.hstack((a,b))
array([ 0, 1, 2, 10, 11, 12])
np.c_[a,b,a+b]
array([[ 0, 10, 10],
[ 1, 11, 12],
[ 2, 12, 14]])
split 和array_split
两者用法基本相同,是将一个数组沿着指定轴分成多个数组,可以直接指定切分轴上的切分点下标。
np.random.seed(42)
a=np.random.randint(0,10,12)
idx=np.nonzero(np.diff(a)<0)[0]+1
print(a)
np.split(a,idx)
[6 3 7 4 6 9 2 6 7 4 3 7]
[array([6]),
array([3, 7]),
array([4, 6, 9]),
array([2, 6, 7]),
array([4]),
array([3, 7])]
当第二个参数为整数时,表示分组个数。split只能平均分组,而array_split()能尽量平均分组
np.split(a,6)
[array([6, 3]),
array([7, 4]),
array([6, 9]),
array([2, 6]),
array([7, 4]),
array([3, 7])]
np.array_split(a,5)
[array([6, 3, 7]),
array([4, 6, 9]),
array([2, 6]),
array([7, 4]),
array([3, 7])]
transpose 和swapaxes()
transpose() 和 swapaxes() 用于修改轴的顺序,它们得到的是原数组的视图。transpose()通过其
第二个参数 axes 指定轴的顺序 , 默认时表示将整个形状翻转。而swapaxes()通过两个整数指定调换顺序的轴。
a = np.random.randint(0, 10, (2, 3, 4, 5))
print (u"原数组形状",a.shape)
print (u"transpose :", np.transpose(a, (1,2, 0,3)).shape)
print (u"swapaxes:",np.swapaxes(a,1, 2).shape)
原数组形状 (2, 3, 4, 5)
transpose : (3, 4, 2, 5)
swapaxes: (2, 4, 3, 5)
多项式函数
由于多项式函数只包含加法和乘法运算,因此它很容易计算,可用于计算其他数学函数的近似值。多项式函数的应用非常广泛,例如在嵌入式系统中经常会用它计算正弦、余弦等函数。在NumPy中,多项式函数的系数可以用一维数组表示,例如可以用下而的数组表示,其中 a[0l是最高次的系数,a[-1]是常数项,注意 x2 x 2 的系数为0。
a=np.arange(0,5)
p=np.poly1d(a)
print(type(p))
多项式的加减乘除
对poly1对象进行加减乘除运算相对于对对应的多项式函数进行计算
p+[-2,1]
poly1d([1, 2, 1, 5])
p*p
poly1d([ 1, 4, 10, 20, 25, 24, 16])
p/[1,-1]
(poly1d([1., 3., 6.]), poly1d([10.]))
多项式的积分和微分
多项式对象的deriv()和integ()方法分别计算多项式函数的微分和积分
p.deriv()
poly1d([3, 4, 3])
p.integ()
poly1d([0.25 , 0.66666667, 1.5 , 4. , 0. ])
多项式的求解
多项式函数的根可以用root函数求解
np.roots(p)
array([-1.65062919+0.j , -0.1746854 +1.54686889j,
-0.1746854 -1.54686889j])
根据根求解析式
poly函数可以根据根求出多项式解析式
r=np.roots(p)
np.poly(r)
array([1., 2., 3., 4.])
多项式拟合
polyfit可以对一组数据进行多项式拟合,找到与这组数据的误差平方和最小的多项式系数
np.set_printoptions(suppress=True,precision=4)
x=np.linspace(-np.pi/2,np.pi/2,1000)
y=np.sin(x)
for deg in [3,5,7]:
a=np.polyfit(x,y,deg)
error=np.abs(np.polyval(a,x)-y)
print('degree{}:{}'.format(deg,a))
print("max error of order %d:"%deg,np.max(error))
degree3:[-0.145 0. 0.9887 0. ]
max error of order 3: 0.008946993767070865
degree5:[ 0.0076 0. -0.1658 -0. 0.9998 0. ]
max error of order 5: 0.00015740861416935203
degree7:[-0.0002 -0. 0.0083 0. -0.1667 -0. 1. 0. ]
max error of order 7: 1.5268255784128826e-06
多项式函数类
numpy.plunomial模块中还提供了更丰富的多项式函数类,例如Polynmial、Chebyshev、Legendre等,他们与前面介绍的numpy.poly1d相反,多项式各项的系数按照幂从小到大的顺序排列
from numpy.polynomial import Polynomial,Chebyshev
p=Polynomial([1,-12,0,1])
p(2.0)
-15.0
Polynomial还提供了众多方法对多项式进行操作,例如deriv()计算导函数
p.deriv()
Polynomial([-12., 0., 3.], domain=[-1., 1.], window=[-1., 1.])
各种乘积运算
dot()
矩阵的乘积可以用dot来进行计算,对于二维数组,它计算的是矩阵乘积,对于一维数组,它计算的是矩阵内积。当需要将一维数组作为矢量或者行矢量进行矩阵运算时,需要先将一维数组转化为二维数组
a=np.arange(12).reshape(4,3)
b=np.arange(12,24).reshape(4,3)
c=np.arange(12,24).reshape(3,4)
a,b,c
(array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11]]), array([[12, 13, 14],
[15, 16, 17],
[18, 19, 20],
[21, 22, 23]]), array([[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]))
print(np.dot(a,c))
[[ 56 59 62 65]
[200 212 224 236]
[344 365 386 407]
[488 518 548 578]]
inner()
对于两个一维数组,inner和dot一样,计算两个数组对应下标元素的乘积和,而对于多维数组,她计算的结果数组中的每个元素都是:数组a和b的最后轴的内积,因此数组a和数组b的最后轴长度得相同
np.inner(a,b)
array([[ 41, 50, 59, 68],
[158, 194, 230, 266],
[275, 338, 401, 464],
[392, 482, 572, 662]])
outer()
outer()函数只对一维数组进行计算,如果传入的是多维数组,则先将此数组展平为一维数组之后再进行计算。它计算列向量和行向量的矩阵乘积
a=np.array([1,2,3])
b=np.arange(5,9)
np.outer(a,b)
array([[ 5, 6, 7, 8],
[10, 12, 14, 16],
[15, 18, 21, 24]])
tensordot()
tensordot()是将两个多维数组a和b指定轴上的对应元素相乘并求和,它是最一般化的求和运算
a=np.random.rand(3,4)
b=np.random.rand(4,5)
np.tensordot(a,b,axes=[[1],[0]])
array([[0.9105, 0.6407, 1.8103, 1.2693, 0.9586],
[1.179 , 0.4149, 1.5286, 1.0736, 1.1756],
[1.4748, 0.7004, 2.1111, 1.7298, 1.4944]])
广义ufunc方法
gufunc是对ufunc的推广,将对单个矩阵的运算通过广播运用到整个数组上。numpy中linalg中提供的函数大都为广义ufunc函数。
求逆
a=np.random.rand(3,3)
print(a)
print(np.linalg.inv(a))
[[0.9092 0.3139 0.6911]
[0.2716 0.1906 0.1846]
[0.3421 0.43 0.8309]]
[[ 1.3995 0.6432 -1.3068]
[-2.8794 9.1946 0.3516]
[ 0.9137 -5.0224 1.5595]]
计算行列式的值
np.linalg.det(a)
0.05645271922626623
求解线性方程
使用solve函数可以求解线性方程组问题
实用技巧
动态数组
numpy的数组对象不能像列表一样动态的改变其大小,在做数据采集的时候,需要不断的向数组中添加数据时很不方便。而python标准库中的array数组提供了动态分配内存的功能,而且它和numpy数组一样直接将数值的二进制数据保存在一块内存中,因此我们可以先用array数组手机数据,再通过np.frombuffer()将array数组的内存数据直接转换为numpy数组
import numpy as np
from array import array
a=array('d',[1,3,4,2])
na=np.frombuffer(a,dtype=np.float)
print(a)
print(na)
na[1]=20
print(a)
array('d', [1.0, 3.0, 4.0, 2.0])
[1. 3. 4. 2.]
array('d', [1.0, 20.0, 4.0, 2.0])
array数组只支持一维数组,如果我们需要采集多个通道的数据,可以将这些数据一次添加进数组array数组,然后通过reshape方法将np.frombuffer()所创建的numpy数组改为二维数组
import math
buf=array('d')
for i in range(50):
buf.append(math.sin(i*0.1))
buf.append(math.cos(i*0.01))
data=np.frombuffer(buf,dtype=np.float).reshape(-1,2)
print(data)
[[ 0. 1. ]
[ 0.0998 1. ]
[ 0.1987 0.9998]
[ 0.2955 0.9996]
[ 0.3894 0.9992]
[ 0.4794 0.9988]
[ 0.5646 0.9982]
[ 0.6442 0.9976]
[ 0.7174 0.9968]
[ 0.7833 0.996 ]
[ 0.8415 0.995 ]
[ 0.8912 0.994 ]
[ 0.932 0.9928]
[ 0.9636 0.9916]
[ 0.9854 0.9902]
[ 0.9975 0.9888]
[ 0.9996 0.9872]
[ 0.9917 0.9856]
[ 0.9738 0.9838]
[ 0.9463 0.982 ]
[ 0.9093 0.9801]
[ 0.8632 0.978 ]
[ 0.8085 0.9759]
[ 0.7457 0.9737]
[ 0.6755 0.9713]
[ 0.5985 0.9689]
[ 0.5155 0.9664]
[ 0.4274 0.9638]
[ 0.335 0.9611]
[ 0.2392 0.9582]
[ 0.1411 0.9553]
[ 0.0416 0.9523]
[-0.0584 0.9492]
[-0.1577 0.946 ]
[-0.2555 0.9428]
[-0.3508 0.9394]
[-0.4425 0.9359]
[-0.5298 0.9323]
[-0.6119 0.9287]
[-0.6878 0.9249]
[-0.7568 0.9211]
[-0.8183 0.9171]
[-0.8716 0.9131]
[-0.9162 0.909 ]
[-0.9516 0.9048]
[-0.9775 0.9004]
[-0.9937 0.8961]
[-0.9999 0.8916]
[-0.9962 0.887 ]
[-0.9825 0.8823]]
当动态调整array数组的大小超过原内存大小的时候,内存地址会变更,因此需要重新调用np.frombuffer()以创建一个新的nparray数组对象来访问其中的数据。当每个通道的数据类型不一样的时候,就不能使用array.array对象了,这时可以使用bytearray收集数据。bytearray是字节数组,因此需要通过struct模块将python的数值转换成字节表示,如果数据来自二进制文件或者硬件,那么很可能得到的已经是字节数据了,这个步骤可以省略。
import struct
buf=bytearray()
for i in range(5):
buf+=struct.pack('=hdd',i,math.sin(i*0.1),math.cos(i*0.01))
dtype=np.dtype({'names':['id','sin','cos'],"formats":['h','d','d']})
data=np.frombuffer(buf,dtype=dtype)
print(data)
[(0, 0. , 1. ) (1, 0.0998, 1. ) (2, 0.1987, 0.9998)
(3, 0.2955, 0.9996) (4, 0.3894, 0.9992)]
data['id']
array([0, 1, 2, 3, 4], dtype=int16)
与结构数组共享内存
从结构数组中获取某个字段时,得到的是原数组的视图,但是如果获取多个字段,将会得到一个全新的数组,不与原数组共享内存
persontype=np.dtype({
'names':['name','age','weight','height'],
'formats':['S30','i','f','f']},align=True
)
a=np.array([("Zhang",32,72.5,167.0),
("Wangle",24,65.2,170.0)],dtype=persontype)
print(a['age'].base is a)
print(a[['age','height']].base is None)
True
True
为了创建结构数组的多字段视图,可以使用下面的fields_view()函数。它通过原数组的的type属性创建视图数组的dtype对象。然后通过ndarray()创建视图数组
def fields_view(arr,fields):
dtype2=np.dtype({name:arr.dtype.fields[name] for name in fields})
return np.ndarray(arr.shape,dtype2,arr,0,arr.strides)
v= fields_view(a,['age','weight'])
print(v.base is a)
v['age']+=10
print(a)
True
[(b'Zhang', 42, 72.5, 167.) (b'Wangle', 34, 65.2, 170.)]