numpy快速处理数据
《python编程基础及应用》 陈波
一、多维数组
补充知识:python的名字绑定机制会使得内存中除了保存真正的数据
之外,还要保存
同样数量的对象引用
,会导致存储空间的浪费
- numpy中的数组内部元素需要
保持一致
- ndarray 的内部数据是连续组织的
import numpy as np
a = np.array([[1,2,3,4],[4,5,6,7]]) # array 可以将元组、列表或者嵌套元组、嵌套列表转为多维数组
b = np.array((1,2,3,4),dtype=np.float32) # dtype=np.float32 是将该数组的元素的数据类型设置为float32,32代表是32位 4字节
print("a = \n",a)
print("a.shape=",a.shape) # a.shape = (2,4) 代表的是 2行4列,数据类型是元组类型,第一个元素是0轴 长度为2,第二个元素是1轴 长度为4
print("a.type=",type(a)) # type 是返回该数组的类型
print("a.dtype=",a.dtype) # dtype 可以返回该数组的元素的数据类型
a =
[[1 2 3 4]
[4 5 6 7]]
a.shape= (2, 4)
a.type= <class 'numpy.ndarray'>
a.dtype= int32
import numpy as np
a = np.array([[1,2,3,4],[5,6,7,8]])
b = a.reshape(4,2) # 将a的形状改为4行2列,但是a和b是共享内存的(存储位置相同,可以理解为名字绑定问题)
b[0][1] = 9
print("a=\n",a)
print("b=\n",b) # 最后是a和b 都发生了改变
c = a.astype(np.float32) # 通过astype将数组元素的数据类型进行转换,生成了新的数组
c[0][1] = 2
print("a=\n",a)
print("a=\n",b)
print("c=\n",c)
a=
[[1 9 3 4]
[5 6 7 8]]
b=
[[1 9]
[3 4]
[5 6]
[7 8]]
[[1 9 3 4]
[5 6 7 8]]
[[1 9]
[3 4]
[5 6]
[7 8]]
[[1. 2. 3. 4.]
[5. 6. 7. 8.]]
二、数组的快速生成
(一)、等差数列
- 语法:arange(start,end,步长) 和 range的语法一样,不包含终值
- 语法:linspace(start,end,个数)
- linspace默认是包含end,如果endpoint=0是不包含的end(终止值)
- 注意:linspace中第三个参数表示的是生成元素个数,间接实现步长的功能
import numpy as np
a = np.arange(0,1,0.1)
b = np.linspace(0,1,10,endpoint=0) # endpoint=0 代表的是不包含终值
c = np.linspace(0,1,10) # 默认包含终值
print("a=",a)
print("不包含终值:b=",b)
print("包含终值:c=",c)
a= [0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9]
b= [0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9]
c= [0. 0.11111111 0.22222222 0.33333333 0.44444444 0.55555556
0.66666667 0.77777778 0.88888889 1. ]
(二)、等比数列
- 语法:logspace(起始值,终值,个数)
- 注意:
logspace
默认是10为基数
,可以通过参数base
进行修改 logspace
和linspace
一样,默认都是将endpoint=True
包含终值
import numpy as np
a = np.logspace(0,2,5,endpoint=0)
b = np.logspace(0,2,5,base=2) # eg:2的0次方;2的1次方
print("以10为底:",a)
print("以2为底:",b)
以10为底: [ 1. 2.51188643 6.30957344 15.84893192 39.81071706]
以2为底: [1. 1.41421356 2. 2.82842712 4. ]
(三)、数组生成函数
zeros()
生成元素全部为0empty()
生成指定形状的数组且不对数组进行初始化,但是里面的元素值不确定ones()
全部为1
-full()
将所有元素初始化为指定值eye()
和identity()
生成主对角为1的 eg:eye(3)diag()
指定对角线的数据
import numpy as np
print(np.zeros((2,2),np.float32)) # 生成2行2列的浮点型的数组
print(np.empty(2,np.int32))
print(np.ones((1,2)))
print(np.full(3,2)) # (3,2) 3代表是形状;2代表的是值,用2来填充
print(np.eye(2))
print(np.diag([1,2,3]))
# 这些函数的第一个参数都是形状,如果是一个,则生成一个一维数组;如果是多个整数的元组,则生成对应的多维数组
[[0. 0.]
[0. 0.]]
[ 0 1072693248]
[[1. 1.]]
[2 2 2]
[[1. 0.]
[0. 1.]]
[[1 0 0]
[0 2 0]
[0 0 3]]
(四)、fromfunction()
案列:生成一个长度为31的一维数组,每一个数组元素代表星期,eg:0代表是星期天
import numpy as np
def weekday(i):
return (i+6)%7 # 1号为星期六
print(np.fromfunction(weekday,(31,))) # float64
print(np.fromfunction(weekday,(31,)).astype(np.int)) # float64转为int
[6. 0. 1. 2. 3. 4. 5. 6. 0. 1. 2. 3. 4. 5. 6. 0. 1. 2. 3. 4. 5. 6. 0. 1.
2. 3. 4. 5. 6. 0. 1.]
[6 0 1 2 3 4 5 6 0 1 2 3 4 5 6 0 1 2 3 4 5 6 0 1 2 3 4 5 6 0 1]
fromfunction(参数1,参数2)
: 参数1
是函数名
;参数2
是数组的形状
,数据类型为元组
,默认的数组元素的类型为float64
上述例子中weekday
的参数是数组元素的下标为参数
,(31,)生成一维数组。
下面是测试:函数名的实参值是不是数组下标
import numpy as np
def i(i):
return i
print(np.fromfunction(i,(31,)))
[ 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.]
案例2:99乘法表
生成一个9行9列的二维数组
import numpy as np
def multi(i,j):
return (i+1)*(j+1)
print(np.fromfunction(multi,(9,9)).astype(np.int))
# i,j的参数分别是对应元素的行和列的下标
[[ 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]]
三、一维数组存取
1、整数下标及切片——共享内存
import numpy as np
a = np.arange(10)
print("a=\n",a)
print("a[2]= ",a[2])
print("a[1:3]=",a[1:3])
print("a[-1::-1]=",a[-1::-1])
c = a[0:3] # 切片0到3的数组给c
a[:3] = 3,2,1
print("修改后的a",a)
print("c=",c)
# 注意:和列表的操作形式一样,但是列表进行切片操作的时候,解释器会复制元素创建型新的列表,而numpy进行数组切片的时候和原数组是共享内存的(原数组或新数组进行修改,二者都会修改)
a=
[0 1 2 3 4 5 6 7 8 9]
a[2]= 2
a[1:3]= [1 2]
a[-1::-1]= [9 8 7 6 5 4 3 2 1 0]
修改后的a [3 2 1 3 4 5 6 7 8 9]
c= [3 2 1]
- 注意:索引是取值,切片保留结构
- 注意:和列表的操作形式一样,但是
列表进行切片操作的时候,解释器会复制元素创建型新的列表
,而numpy进行数组切片的时候和原数组是共享内存
的(原数组或新数组进行修改,二者都会修改),切片所得的数组作为视图
。见下述例子
import numpy as np
a = np.arange(10)
c = a[:5]
a[2] = 88
print("c=",c)
print("a=",a)
# 注意:需要保持独立性,可以使用copy
c= [ 0 1 88 3 4]
a= [ 0 1 88 3 4 5 6 7 8 9]
2、整数列表
作为下标
通过给数组指定一个整数列表来选择指定下标的元素
- 好处:新数组
不
与原数组共享存储空间
import numpy as np
a = np.arange(1,13,2)
print("a=\n",a)
x = a[[1,3,5]] # 1,3,5分别是指a的下标
print("x=",x)
x[0]=13
print(x[[1,2]]) # 获取x下标为1和2的元素
x[[1,2]] = 14,15
print("x=",x)
a1 = a[[3,1,-1,-2]]
print("a1=",a1)
a=
[ 1 3 5 7 9 11]
x= [ 3 7 11]
[ 7 11]
x= [13 14 15]
a1= [ 7 3 11 9]
注意:a[[3,1,-1,-2]]是获取a中下标为3,1,-1,-2的元素
3、 整数数组
作为下标
import numpy as np
a = np.arange(10) # 【0,1,2,3,】
print(a)
idx = np.array([[1,3,4,7],[3,3,-3,8]]) # 2行4列的数组
print("idx={}".format(idx))
x = a[idx] # idx中的元素作为了a的下标进行索引
print("x=\n",x)
# idx的形状大小,x也会根据idx的形状大小
[0 1 2 3 4 5 6 7 8 9]
idx=[[ 1 3 4 7]
[ 3 3 -3 8]]
x=
[[1 3 4 7]
[3 3 7 8]]
4、布尔列表或数组作为下标
import numpy as np
a = np.arange(5)
idex1 =[True,False,False,True,False]
print("a=",a)
print(a[idex1]) # 将True对应的下标作为索引进行取值
a= [0 1 2 3 4]
[True, False, False, True, False]
[0 3]
四、多维元素存取
1、整数下标
及切片
import numpy as np
a = [[ i+j for i in range(5)]for j in range(6)] # 快速生成5行6列的嵌套列表
arr = np.array(a)
print("arr=\n",arr)
b = arr[1:5,1:3] # 两个切片结果为二维数组
print("b=",b)
b[1][1] = 6
print("arr=",arr)
print("b=",b)
# 请注意观察arr和b,b发生了修改,arr也发生了修改,说明切片会原数组和新数组有共享内存
arr=
[[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]
[5 6 7 8 9]]
b= [[2 3]
[3 4]
[4 5]
[5 6]]
arr= [[0 1 2 3 4]
[1 2 3 4 5]
[2 3 6 5 6]
[3 4 5 6 7]
[4 5 6 7 8]
[5 6 7 8 9]]
b= [[2 3]
[3 6]
[4 5]
[5 6]]
- 二维数组的索引: a[行索引,列索引]
- a[:,:] 结果是二维数组
- a[,:] 结果是一维数组
(1)、三种方式访问同一种元素
# 三种方式访问同一个元素
print(arr[1][2])
print(arr[1,2])
idex = (1,2)
print(arr[idex])
3
3
3
(2)、如何获取对应元素在python中标准数据结果 -item()
利用item()获取元素的标准结果
import numpy as np
arr = np.arange(6).reshape(2,3).astype(np.int)
print(arr[1][1],type(arr[1,1]))
print(arr.item(1,1),type(arr.item(1,1))) # item(元素下标),确定数组的元素的数据类型
4 <class 'numpy.int32'>
4 <class 'int'>
(3)、创建切片下标
补充知识:多维数组中用逗号分隔的下标可以视为一个“元组”
- slice(起始值,终值,步长) 如果参数忽略,需要用
None
进行填充 - slice [slaɪs] 切片
import numpy as np
a = np.arange(15).reshape(3,5)
print("a= \n",a)
idx = slice(0,None,1),slice(1,4,2) #数据类型为元组 a[0::1,1:4:2]
print("idx=",idx,"数据类型:",type(idx))
b =a[idx]
c = a[0::1,1:4:2]
print(b)
print(c)
a=
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]]
idx= (slice(0, None, 1), slice(1, 4, 2)) 数据类型: <class 'tuple'>
[[ 1 3]
[ 6 8]
[11 13]]
[[ 1 3]
[ 6 8]
[11 13]]
补充知识:np.s_
是一个特殊对象,生成切片下标对象 eg:np.s_[::3,2::2]
等于 slice(None,None,3),slice(2,None,2)
等于数组名[::3,2::2]
import numpy as np
a = np.arange(10).reshape(5,2)
idx = np.s_[1::,0::]
print("idx的数据类型为:",type(idx)) #<class 'tuple'> 元组
b = a[idx]
b[1][1] = 666
print(a)
print(b)
# 注意:该方法会与原数组和新数组有共享内存
idx的数据类型为: <class 'tuple'>
[[ 0 1]
[ 2 3]
[ 4 666]
[ 6 7]
[ 8 9]]
[[ 2 3]
[ 4 666]
[ 6 7]
[ 8 9]]
2、整数列表、元组、数组、布尔数组
import numpy as np
a = [[x+y for x in range(5)] for y in range(7)]
a = np.array(a).astype(np.int)
print("元组:a[(1,2,1,3),(0,0,2,1)=",a[(1,2,1,3),(0,0,2,1)]) # 通过元组的对应位置来获取元素eg:[1,0];[2,0];[1,2],[3,1] [1 2 3 4]
print("列表:a[4:,[0,2,4]]=",a[4:,[0,2,4]]) # 获取4、5行中0、2、4列的元素
select = np.array([0,1,0,1,1,1,0],dtype=np.bool) # boolean index did not match indexed array along dimension 0; dimension is 7 but corresponding boolean dimension is 6
print("布尔:a[select,1]=",a[select,1]) # 布尔数组的长度要和数组列长度一致
元组:a[(1,2,1,3),(0,0,2,1)= [1 2 3 4]
列表:a[4:,[0,2,4]]= [[ 4 6 8]
[ 5 7 9]
[ 6 8 10]]
布尔:a[select,1]= [2 4 5 6]
五、内存结构
了解数组的内存存储结构,便于理解切片和整数数组进行访问原数组与新数组内存的关系。
- 案列:生成一个3行3列的数据为float32(4字节)的数组,使用数据类型(dtype)、维数(ndim)、形状(shape)、步幅(strides)
import numpy as np
a = np.array([[1,2,3],[4,5,6],[7,8,9]],dtype=np.float32)
print("a=\n",a)
print("a.dtype=",a.dtype) # dtype是数据类型展示
print("type(a.dtype)=",type(a.dtype))
print("a.ndim=",a.ndim) # ndim代表为维度,2
print("a.shape=",a.shape)
print("a.data=",a.data) # <memory at 0x0000017F31211480> 数组的内存位置
print("a.strides=",a.strides)# (12,4)
"""
strides 作用是记录每一个轴相邻两个元素的地址差,返回的数据类型为元组,(12,4) 12代表是0轴的相邻两个元素地址差。eg:x行和x+1行,
且列相同的元素之间的地址差 。float32 是4字节,因此一个元素占了4字节,3个元素占3*4(12字节),这是12的由来;
4 代表的是1轴相邻元素的地址差,eg: x列和x+1列,且行相同之间元素的地址差。 一个元素是4字节,应该差了4
"""
a=
[[1. 2. 3.]
[4. 5. 6.]
[7. 8. 9.]]
a.dtype= float32
type(a.dtype)= <class 'numpy.dtype'>
a.ndim= 2
a.shape= (3, 3)
a.data= <memory at 0x0000017F31211480>
a.strides= (12, 4)
'\nstrides 作用是记录每一个轴相邻两个元素的地址差,返回的数据类型为元组,(12,4) 12代表是0轴的相邻两个元素地址差。eg:x行和x+1行,\n且列相同的元素之间的地址差 。float32 是4字节,因此一个元素占了4字节,3个元素占3*4(12字节),这是12的由来;\n4 代表的是1轴相邻元素的地址差,eg: x列和x+1列,且行相同之间元素的地址差。 一个元素是4字节,应该差了4\n'
注意:上面的地址计算公式也是c语言的地址计算公式
元素地址 = 首地址+轴0下标*步幅+轴1下标*轴1的步幅
- 案列:切片时,为什么原数组和新数组会共享内存
import numpy as np
a = np.array([[1,2,3],[4,5,6],[7,8,9]],dtype=np.float32)
b = a[::2,::2]
print("a=\n",a)
print("b=\n",b)
print("a.strides=",a.strides) #(12,4)
print("b.strides=",b.strides) # (24,8)
print("a.data=",a.data)
print("b.data=",b.data)
a=
[[1. 2. 3.]
[4. 5. 6.]
[7. 8. 9.]]
b=
[[1. 3.]
[7. 9.]]
a.strides= (12, 4)
b.strides= (24, 8)
a.data= <memory at 0x000001C1DE4F0480>
b.data= <memory at 0x000001C1DE4F0480>
上述案列分析:a形状是3行3列
,b形状是2行2列
。a.strides=(12,4) b.strides=(24,8)
。观察b中元素1和7,a中1和7的位置中相隔一行,正好是12的两倍 24,因此借助strides可以计算出数据的地址位置。注意:布尔类型、数组等
进行访问时,strides就无法计算位置,只有复制元素进行操作
六、ufunc函数
ufunc 是universal function的缩写,大多数的ufunc函数时都是通过C语言进行编写的。因为在对多维进行计算的时候需要进行循环,c语言的循环比python的循环效率要高。
1、三角函数
下述代码我们以sin为列,`其他的三角函数(cos、tan、arctan)相似`
# 生产1~10pi 的1000个等差数列,并计算出对应的sin(),在通过matplotlib进行画图
import numpy as np
from matplotlib import pyplot as plt
x = np.linspace(0,10*np.pi,1000)
y = np.sin(x) # 会生成和x形状一样的数组
print("x.shape=",x.shape,"y.shape=",y.shape)
# 展示10个
print("x[::100]=",x[::100])
print("y[::100]=",y[::100])
plt.plot(x,y)
plt.show()
x.shape= (1000,) y.shape= (1000,)
x[::100]= [ 0. 3.14473739 6.28947478 9.43421217 12.57894956 15.72368695
18.86842435 22.01316174 25.15789913 28.30263652]
y[::100]= [ 0. -0.00314473 0.00628943 -0.00943407 0.01257862 -0.01572304
0.0188673 -0.02201138 0.02515525 -0.02829886]
sin()函数中还有一个参数是用来指定数据输出保存在那个一个数组中,是通过out
import numpy as np
x = np.linspace(0,10,10)
y = np.zeros(10)
t = np.sin(x,out=y) # sin()依然也会将数组赋值给t
print("id(x)=",id(x),"id(y)=",id(y))
print("y=",y)
print("t=",t)
# 修改其中一个数组中值,发现是共享内存的
y[1] = 10
print("y=",y)
print("t=",t)
id(x)= 1932215179104 id(y)= 1932215354592
y= [ 0. 0.8961922 0.79522006 -0.19056796 -0.96431712 -0.66510151
0.37415123 0.99709789 0.51060568 -0.54402111]
t= [ 0. 0.8961922 0.79522006 -0.19056796 -0.96431712 -0.66510151
0.37415123 0.99709789 0.51060568 -0.54402111]
y= [ 0. 10. 0.79522006 -0.19056796 -0.96431712 -0.66510151
0.37415123 0.99709789 0.51060568 -0.54402111]
t= [ 0. 10. 0.79522006 -0.19056796 -0.96431712 -0.66510151
0.37415123 0.99709789 0.51060568 -0.54402111]
2、四则运算
import numpy as np
a = np.array([1,3,5],dtype=np.float32)
b = np.array([2,4,6],dtype=np.int)
c1 = np.add(a,b)
c2 = a+b
print("c1=",c1)
print("c2=",c2)
# 注意:由于a是float类型的数据,而b是int类型的数据,因此结果会转换为float
c1= [ 3. 7. 11.]
c2= [ 3. 7. 11.]
3、比较运算与布尔运算
- 比较运算
== 、<、>、!=
等比较符也适用于数组
import numpy as np
a = np.array([1,2,3])
b = np.array([3,2,1])
print("a<b=",a<b) # 注意是两个数组中对应下标的元素进行比较
print("a<b=",np.less(a,b)) # 但是建议还是直接使用运算符
a<b= [ True False False]
a<b= [ True False False]
- 布尔运算
与(and)、或(or)、非(not)、异或(xor)
,数组不能直接用and等进行运算,需要使用logical_or()、logical_and()、logical_not()、logical_xor()
import numpy as np
a = np.array([1,2,3])
b = np.array([3,2,1])
print(a>b)
print(a==b)
print("a>b or a==b:",np.logical_or(a>b,a == b)) # a>b or a==b
print("np.all(a>b):",np.all(a>b)) # 只有全部a都大于b的时候,才是True
print("np.any(a>b):",np.any(a>b)) # 当其中只要有一个是a>b的时候,是True
[False False True]
[False True False]
a>b or a==b: [False True True]
4、自定义构建ufunc函数
当标准的ufunc函数不能满足我们使用的时候,我们可自定义ufunc函数。自定义ufunc函数一样可以作用域数组每一个元素。自定义ufunc函可用c语言、
python(缺点:执行效率低)、c和python交叉
import numpy as np
import math
from matplotlib import pyplot as plt
def signalcomp(x,freq):
y = math.cos(x)
y += 0.2*math.cos(freq*x)
retur
x = np.linspace(0,5*np.pi,1000)
ufunc1 = np.frompyfunc(signalcomp,2,1) # 构建自定义ufunc函数,第二个参数的2表示可以输入2个参数,第三个参数的1表示的是有1个结果返回
y = ufunc1(x,10).astype(np.float32) # 自定ufunc函数最后的结果是返回的object,因此我们需要对它进行数组类型转换
plt.plot(x,y)
plt.show()
7、广播
数组形状相同可以进行运算操作,那么不同形状的数组如何进行操作,通过广播。
import numpy as np
a = np.arange(0,50,10).reshape(-1,1) # 5行1列的二维数组(通过确定列来确定行)
b = np.arange(0,4) # 生成长度为4的一维数组
c = a+b
print("a.shape:",a.shape,"b.shape:",b.shape)
print("a=\n",a)
print("b=\n",b)
print("c.shape:",c.shape)
print(" c=\n",c)
"""
c=a+b
1、满足上面广播规则第1条,将b数组转为二维数组(1,4) 1行4列的
2、满足广播规则第2条,输入数组:a是5行1列;b是1行4列 结果输出:为5行4列
3、满足广播规则第4条,c[3][2] = a[3][0]+b[0][2]
"""
a.shape: (5, 1) b.shape: (4,)
a=
[[ 0]
[10]
[20]
[30]
[40]]
b=
[0 1 2 3]
c.shape: (5, 4)
c=
[[ 0 1 2 3]
[10 11 12 13]
[20 21 22 23]
[30 31 32 33]
[40 41 42 43]]
'\nc=a+b\n1、满足上面广播规则第1条,将b数组转为二维数组(1,4) 1行4列的\n2、满足广播规则第2条,输入数组:a是5行1列;b是1行4列 结果输出:为5行4列\n'
(1)、微实践–绘制二元函数曲面
补充知识:np.ogrid() 函数生成符合广播机制的数组
import numpy as np
x,y = np.ogrid[0:3:4j,0:4:5j]
print("x=\n",x)
print("y=\n",y)
print("x.shape=",x.shape) # x是4行1列的数组
print("y.shape=",y.shape) # y是1行5列的数组
x=
[[0.]
[1.]
[2.]
[3.]]
y=
[[0. 1. 2. 3. 4.]]
x.shape= (4, 1)
y.shape= (1, 5)
ogrid()是一个特殊函数,是通过切片的下标来生成数组
(用于广播运算的数组),注意:O:3:4j
类似于np.linsapce(0,3,4)生成0~3的长度为4的数组
,而4j中j是语法格式。eg:x,y = np.ogrid[0:3:4j,0:4:5j] 生成x是4行1列(4,1),y是1行5列的数组(1,5)
案例一:将x=[-2,+2],y=[-2,+2]的函数值矩阵绘制为平面图
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import cm
y,x = np.ogrid[-2:2:200j,-2:2:200j] # y 形状(200,1) x形状(1,200)
z = x*np.exp(-x**2-y**2)
extend1 = [np.min(x),np.max(x),np.min(y),np.max(y)] #x和y的界线
plt.imshow(z,cmap=cm.gray,extent=extend1) # 将z作为图像显示。cmap是指定颜色映射对象,该颜色映射对象负责把z中的元素值转换为像素点的颜色
plt.colorbar() # 通过颜色条来对应z中值与颜色的关系
plt.show()
案例二:将x=[-2,+2],y=[-2,+2]的函数值矩阵绘制为3d图
import numpy as np
import mpl_toolkits.mplot3d
from matplotlib import pyplot as plt
from matplotlib import cm
x,y = np.mgrid[-2:2:20j,-2:2:20j] #mgrid和ogrid是相似的,只是mgrid将形状扩充成为矩阵(20,1)->(20,20)
z = x*np.exp(-x**2--y**2)
fig = plt.figure(figsize=(8,6))
ax = fig.gca(projection='3d')
ax.plot_surface(x,y,z,cmap=cm.ocean) # ax是子图,由于ax.plot_surface()要求是x,y,z三个数组形状相同
plt.show()
八、函数库
1、随机数
from numpy import random as nr
r1 = nr.rand(3,3) # 生成0~1的随机数,3,3表示3行3列
r2 = nr.randn(3,3) # 标准正态分布的随机数 ,3行3列
r3 = nr.randint(0,10,(3,3)) # 生成3行3列,0~9(不包含10)的随机整数
print(r1)
print(r2)
print(r3)
[[0.42866666 0.01237853 0.84190471]
[0.78209189 0.69903899 0.30133983]
[0.69286253 0.0074816 0.43684253]]
[[-0.37057477 -0.29598364 -0.32416453]
[-1.14480703 0.19834707 0.3658034 ]
[-0.63920883 -0.15876545 0.93713387]]
[[5 8 1]
[4 0 8]
[4 6 5]]
[0 0]
其他随机数表
normal()
正态分布随机数poisson()
泊松分布随机数shuffle()
随机打乱顺序
-seed()
设置随机数种子uniform()
均匀分布随机数
-permulation()
随机排列choice()
随机抽取样本
python或者numpy中随机数,都是伪随机数,即随机数是以种子为基础迭代计算。从相同的随机数出发可以获取相同的随机数序列。
微实践——人群身高的正态分布
from numpy import random as nr
import numpy as np
from matplotlib import pyplot as plt
heights = nr.normal(170,30,(10000,)).astype(int) #生成标准值为170,方差为30,10000个样本的随机数组
stats = np.zeros((10000,)) # 生成一个 10000的一维数组
print(stats.shape,stats.ndim)
for i in range(10000):
stats[heights[i]]+=1 # stats以身高为下标,统计heights中有多少人,将人数赋值个对应下标的元素,即人数就是stats的元素值
plt.plot(stats[:300])
plt.show()
[199 131 190 188 133 185 192 175 223 155]
(10000,) 1
2、和、均值与方差
import numpy as np
from numpy import random as nr
nr.seed(2022) # 设置随机种子,可以使多次运行的结果相同
a = nr.randint(0,10,size=(3,5))
print("a=\n",a)
print("np.sum(a)=",np.sum(a)) # 是数组中的全部元素进行统计
print("np.sum(a,axis=1)=",np.sum(a,axis=1)) # 相同行进行统计
print("np.sum(a,axis=0)=",np.sum(a,axis=0)) # 相同列进行统计
a=
[[0 1 1 0 7]
[8 2 8 0 5]
[9 1 3 8 0]]
np.sum(a)= 53
np.sum(a,axis=1)= [ 9 23 21]
np.sum(a,axis=0)= [17 4 12 8 12]
平均函数 mean()
与加权平均函数average()
import numpy.random as nr
import numpy as np
nr.seed(2022) #相同的随机种子,后面的随机序列的数组相同
a = nr.randint(0,10,(3,5))
print("a=\n",a)
print("np.mean(a)=",np.mean(a))
print("np.mean(a,axis=1)=",np.mean(a,axis=1)) # 相同的行算平均数
a=
[[0 1 1 0 7]
[8 2 8 0 5]
[9 1 3 8 0]]
np.mean(a)= 3.533333333333333
np.mean(a,axis=1)= [1.8 4.6 4.2]
# 加权平均数
import numpy as np
score = np.array([66,77,88])
weights = np.array([0.3,0.5,0.2])
print("np.average(score,weights=weights)=",np.average(score,weights=weights)) # weight 是权数
np.average(score,weights=weights)= 75.9
补充知识:
- sum() 求和
- average() 求加权平均数
- var() 求方差
- mean() 求平均数
- std() 求标准差
- product() 连乘积
3、比较与排序
比较函数与排序函数
- max/min() 最大值、最小值
- minimum、maximum() 二元取最小值、最大值
- argmin、argmax() 最小值、最大值的下标
- ptp() 最大值-最小值的结果
- sort() 排序
- argsort() 排序后的下标
- lexsort() 多列排序
- partition() 快速计算前k项
- argpartition() 快速计算前k项的下标
- percentile() 百分数
- median() 中位数
- searchsorted() 折半查找
# sort的案例
import numpy as np
from numpy import random as nr
nr.seed(2022) # 设置相同的随机数种子
a = nr.randint(0,10,size=(3,5))
print("a=\n",a)
print("np.sort(a)=\n",np.sort(a)) # sort 进行排序,axis默认是-1,一般是最大轴 eg:二维数 中轴1是最大的
print("np.sort(a,axis=None)=\n",np.sort(a,axis=None)) # 如果axis为None会先将数组转为一维数组,在进行排序
print("np.sort(a,axis=1)=\n",np.sort(a,axis=1)) # axis =1 是按照行进行排序,如果是axis=0是按照列进行排序
print("np.argsort(a,axis=1)=\n",np.argsort(a,axis=1)) # argsort 是获取按行进行排序后数据的下标
a=
[[0 1 1 0 7]
[8 2 8 0 5]
[9 1 3 8 0]]
np.sort(a)=
[[0 0 1 1 7]
[0 2 5 8 8]
[0 1 3 8 9]]
np.sort(a,axis=None)=
[0 0 0 0 1 1 1 2 3 5 7 8 8 8 9]
np.sort(a,axis=1)=
[[0 0 1 1 7]
[0 2 5 8 8]
[0 1 3 8 9]]
np.argsort(a,axis=1)=
[[0 3 1 2 4]
[3 1 4 0 2]
[4 1 2 3 0]]
# maximum、minimum
import numpy as np
a = np.array([2,4,6,8])
b = np.array([1,3,5,7])
print("np.maximum(a,b)=",np.maximum(a,b)) # 比较a、b对应下标的元素的大小,大的则保存新的数组中
print("a[None,:]=",a[None,:]) # a.reshape(1,-1) 生成1行4列的数组
print("b[:,None]=\n",b[:,None]) # b.reshape(-1,1) 生成5行1列的数组
print("np.maximum(a[None,:],b[:,None])=\n",np.maximum(a[None,:],b[:,None]))
np.maximum(a,b)= [2 4 6 8]
a[None,:]= [[2 4 6 8]]
b[:,None]=
[[1]
[3]
[5]
[7]]
np.maximum(a[None,:],b[:,None])=
[[2 4 6 8]
[3 4 6 8]
[5 5 6 8]
[7 7 7 8]]
np.maximum(a[None,:],b[:,None])
需要将a和b广播机制成为4行4列的元素,下面分别是a和b广播机制后的
-
a 广播机制后的数组
- [[2 4 6 8]
- [2 4 6 8]
- [2 4 6 8]
- [2 4 6 8]]
-
b广播机制
- [[1 1 1 1]
- [3 3 3 3]
- [5 5 5 5]
- [7 7 7 7]]
# searchsorted()折半查找法,确定插入位置
import numpy as np
a = np.array([0,2,4,9,10]) # 有序数组
b = np.array([0,1,2,2,4,4,5,8])
print(np.searchsorted(a,b)) # searchsorted会将b在a中进查找 eg: b[6] 属于的a[2]~~[3]之间所有返回下标3。 b[7] 在a[2]~~~[3]之间,下标为3
[0 1 1 1 2 2 3 3]
4、乘积
补充知识:
- dot() 矩阵乘积 (行*列)
- inner() 内积
- outter() 外积
- tensordot() 张量乘积
import numpy as np
from numpy import random as nr
nr.seed(2022)
a = nr.randint(0,5,(2,3)) # 2行3列
b = nr.randint(0,5,(3,2)) # 3行2列
print("a=\n",a)
print("b=\n",b)
c = np.dot(a,b) # a*b (2,3)*(3,2) 构成了(2,2)
print("c=\n",c)
d = np.dot(b,a) # b*a (3,2)*(2,3) 构成了(3,3)
print(d)
a=
[[4 0 1]
[1 0 0]]
b=
[[2 0]
[0 1]
[1 3]]
c=
[[9 3]
[2 0]]
[[8 0 2]
[1 0 0]
[7 0 1]]
5、数组的连接
- (1)concatenate 默认参数axis=0代表是竖直连接,axis=1代表是横向连接
- (2)hstack 横向连接
- (3)vstack 竖向连接
分割:
- (1)、split 默认参数axis=0是竖直方向,按行进行分割
- (2)、hsplit 是水平分割,按列进行分割
- (3)、vsplit 是竖直分割,按行进行分割
import numpy as np
arr = np.arange(0,12).reshape(3,4) # 3行 4列
arr1 = np.arange(2,14).reshape(3,4)
print(np.concatenate((arr,arr1),axis=1)) # 行不变,列增加
print(np.concatenate((arr,arr1))) # 列不变,行增加
print(np.hstack((arr1,arr))) # 行不变,列增加
print(np.vstack((arr1,arr))) # 列不变,行增加
[[ 0 1 2 3 2 3 4 5]
[ 4 5 6 7 6 7 8 9]
[ 8 9 10 11 10 11 12 13]]
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]
[ 2 3 4 5]
[ 6 7 8 9]
[10 11 12 13]]
[[ 2 3 4 5 0 1 2 3]
[ 6 7 8 9 4 5 6 7]
[10 11 12 13 8 9 10 11]]
[[ 2 3 4 5]
[ 6 7 8 9]
[10 11 12 13]
[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
(6)、tolist 将数组转换为列表
import numpy as np
arr = np.arange(12).reshape(3,4)
print(arr.tolist(),type(arr.tolist()))
[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]] <class 'list'>
九、创建矩阵和计算
(一)、创建矩阵 :mat()、matrix()、bmat()函数
- 1、使用字符串来创建矩阵(MATLAB 风格的)
- 以空格进行分割列,以分号进行分割
- eg: numpy.mat(“1 2 3;4 5 6;7 8 9”)
- 2、使用嵌套序列创建矩阵
- eg: numpy.mat([[1,2,3,],[4,5,6]])
- 3、使用数组创建矩阵
- eg:numpy.mat(np.arange(12).reshape(3,4))
- 4、使用matrix()创建矩阵
- 5、bmat() 将小矩阵拼接成大矩阵
import numpy as np
# 使用字符串来创建矩阵
str = '1 2 3;4 5 6;7 8 9'
a = np.mat(str)
a[1,1] = 1
print("查看修改后的a和str\n",a,"\n",str) # a矩阵发生了变化,但是str没有发生变化
# 使用嵌套序列创建矩阵
a1 = np.mat([[2,4,6,8],[1.0,3,5,7.0]])
print("嵌套序列创建矩阵:\n",a1)
# 使用数组创建矩阵
arr = np.arange(9).reshape(3,3)
a2 = np.mat(arr)
print("数组创建矩阵:\n",a2)
查看修改后的a和str
[[1 2 3]
[4 1 6]
[7 8 9]]
1 2 3;4 5 6;7 8 9
嵌套序列创建矩阵:
[[2. 4. 6. 8.]
[1. 3. 5. 7.]]
数组创建矩阵:
[[0 1 2]
[3 4 5]
[6 7 8]]
十、文件读写操作
(一)、读写文本文件
- loadtxt() 进行读操作
- savetxt()进行写操作
1、将一维和二维数组写入txt或者csv文件中
格式:numpy.savetxt(fname,array,fmt=“%.18e”,delimiter=None,newline=‘\n’,header=‘’,footer=‘’,comments=‘#’,encoding=None)
- fname:文件名,可以为.gz和.bz2
- array: 存入文件的数组
- fmt:写入文件的格式
- delimiter:分隔符,默认是空格
- newline:换行符
- header:在文件开头写入的字符串
- footer:在文件末尾写入的字符串
- comments:字符串标记注释符,默认为#
import numpy as np
arr = np.arange(12).reshape(3,4)
# fmt 默认是%.18(字符串),分隔符是空格
np.savetxt("test1.txt",arr)
# 写入文件的为十进制整数
np.savetxt("test2.txt",arr,fmt="%d",delimiter=',')
#加上注释
np.savetxt("test3.txt",arr,fmt="%d",delimiter=',',header="练习在开头插入字符串啦",footer="和开头的字符串一样呀")
# 修改comments注释符
np.savetxt("test4.csv",arr,fmt="%d",delimiter=",",header="注意观察开头的符号是什么,还是不是#开头的啦",)
2、读取Txt文件和CSV文件
使用函数loadtxt(),该函数格式:numpy.loadtxt(fname,dtype=<type “float”>,comments=“#”,delimiter=None,converters=None,skiprows=0,usecols=None,unpack=False,ndmin=0,encoding=“bytes”)
- fname:文件、字符串或产生器
- dtype:数据类型
- delimiter:分割符
- usecols:选取数据列表
import numpy as np
arr = np.zeros((3,5),dtype=np.int32)
print(arr)
[[0 0 0 0 0]
[0 0 0 0 0]
[0 0 0 0 0]]
import numpy as np
arr = np.arange(16).reshape(4,4)
# print(arr)
# 切片
print(arr[1,:])
#元组来进行切片
print(arr[(1,1,1,1),(0,1,2,3)])
# 数据进行切片
print(arr[[1,1,1,1],[0,1,2,3]])
print(arr[1:3,1:3])
[4 5 6 7]
[4 5 6 7]
[4 5 6 7]
[[ 5 6]
[ 9 10]]
import matplotlib.pyplot as plt
plt.plot([1,2,3,4])
plt.show()
import matplotlib.pyplot as plt
plt.plot([1,2,3,4],[1,4,9,16],'rv')
plt.axis([0,5,0,18]) # 前面两个是 x轴 起点和终点 ,后面两个是y轴的起点和终点
plt.show()
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0,10,100)
y = np.cos(x)
plt.plot(x,y)
plt.axis([0,10,-1,1])
plt.show()