python中一般用列表对一组值来进行存储,存储n个值就需要n个指针和n个值对象,
对于一般的数值计算比较浪费内存和CPU的计算时间。而numpy库则恰恰弥补了这些不足,
能够对数据进行快速处理,numpy提供了两种基本的对象,分别是ndarray和ufunc,ndarray
能够存储同一数据类型的多维数组,ufunc能够数组进行快速计算和处理。
1.数组的创建
首先要先引入numpy库,为了使用的方便,一般简写为np
import numpy as np
(1)利用 np.array(列表,数据类型) 进行创建,数据类型可写,也可以不写
例如:
>>> np.array([1,2,3,4]) array([1, 2, 3, 4]) >>> np.array([[1,2,3],[4,5,6]]) array([[1, 2, 3], [4, 5, 6]]) >>> np.array([[1,2,3],[4,5,6]],dtype=np.float) array([[1., 2., 3.], [4., 5., 6.]])
数据类型可以是整数(python中默认是int32,还有int16,int8等),小数(float),复数(complex)等
(2)利用 reshape(数组维度) 创建一个修改了维度的数组
首先先介绍shape方法,它表示数组的维度,如果shape中只有一个参数,另一个位置没填数字,表示一维数组,例如:( 5 , ) ( ,10)等
第一个参数表示第0轴长度或维度,第二个参数表示第1轴长度或维度,以此类推,可以用它获取数组的维度或者修改数组的维度
>>> a=np.array([[1,2,3],[4,5,6]]) //创建a数组 >>> a.shape //获取a数组的维度 (2, 3) >>> a.shape=3,2 //改变a数组的维度为3,2 >>> a array([[1, 2], [3, 4], [5, 6]]) >>> a.shape=1,-1 //当数组维度中有一个轴为-1时,则该轴的长度需根据其他轴的长度推出 >>> a array([[1, 2, 3, 4, 5, 6]])
下面用 reshape 创建一个修改了维度的数组
>>> a=np.array([1,2,3,4]) >>> b=a.reshape((2,2)) //利用reshape方法创建a数组修改尺寸后的b数组 >>> b array([[1, 2], [3, 4]]) >>> a //a数组并不会改变 array([1, 2, 3, 4]) >>> a[1]=-1 //a,b数组共用同一存储区域,改变a数组中的值时,b数组也跟着变 >>> b array([[ 1, -1], [ 3, 4]])
(3)利用 arange(起始值,终值,步长) 创建数组 ,结果不包含终值
>>> np.arange(0,1,0.1)
array([0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9])
(4)利用 linspace(起始值,终值,数组长度) 创建数组 ,缺省包含终值
>>> np.linspace(0,1,19) array([0. , 0.05555556, 0.11111111, 0.16666667, 0.22222222, 0.27777778, 0.33333333, 0.38888889, 0.44444444, 0.5 , 0.55555556, 0.61111111, 0.66666667, 0.72222222, 0.77777778, 0.83333333, 0.88888889, 0.94444444, 1. ])
(5)利用 logspace(x,y,数组长度) 创建数组,其中起始值为10^x,终值为10^y
注意创建的是等比数列,缺省是包含终值的
>>> np.logspace(0,2,10) array([ 1. , 1.66810054, 2.7825594 , 4.64158883, 7.74263683, 12.91549665, 21.5443469 , 35.93813664, 59.94842503, 100. ])
(6)利用 fromstring(字符串,数据类型) 创建数组
>>> s="abcd" >>> np.fromstring(s,dtype=np.int8) //转换为8bit的整型数字,而1个字符正好是一个字节,就是8bit array([ 97, 98, 99, 100], dtype=int8)
>>> np.fromstring(s,dtype=np.int16) //16bit整型数字,2个字符 array([25185, 25699], dtype=int16) >>> np.fromstring(s,dtype=np.int32) //32bit整型数字,4个字节 array([1684234849])
(7).利用 fromfunction(函数,维度大小) 创建数组
>>> def func(i): ... return i%3 ... >>> np.fromfunction(func,(10,)) //将数组的对应下标代入计算,如代入0,1,2等 array([0., 1., 2., 0., 1., 2., 0., 1., 2., 0.]) >>> def func2(i,j): ... return (i+1)*(j+1) ... >>> np.fromfunction(func2,(9,9)) 将数组的对应下标代入计算,如代入(0,0),(0,1)等 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.]])
计算得出的数组的值,即为根据给定的数组的维度将数组的下标代入函数的所得值
(8)利用 random.rand(n) 创建数组 获取长度为n,0~1大小的元素
>>> np.random.rand(10) array([0.1867282 , 0.37135238, 0.17174666, 0.85489093, 0.4056115 , 0.44384032, 0.87389873, 0.87801261, 0.58510774, 0.1790432 ])
2.数组的获取
(1).使用切片获取
和列表的获取一样,数组可以用切片获取数组的视图,但是和原数组共享同一块数组空间
>>> a=np.arange(10) >>> a array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) >>> a[::-1] array([9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) >>> a[2:6:1] array([2, 3, 4, 5]) >>> a[9:2:-2] array([9, 7, 5, 3]) >>> b=a[2:5] >>> b array([2, 3, 4]) >>> b[1]=100 >>> b array([ 2, 100, 4]) >>> a array([ 0, 1, 2, 100, 4, 5, 6, 7, 8, 9])
(2).使用整数序列获取
可以类似如下方式用整数序列对数组进行获取,但是获取的数组与原数组不共享同一块数据空间
>>> a array([ 0, 1, 2, 100, 4, 5, 6, 7, 8, 9]) >>> a[[2,9,5,3]] //利用整数序列对数组进行获取 array([ 2, 9, 5, 100]) >>> b=a[np.array([5,-3,-2])] //可以用负数下标获取,列表里可以是整数列表,也可以是整数数组 >>> b array([5, 7, 8]) >>> b[1]=-1 >>> b array([ 5, -1, 8]) >>> a array([ 0, 1, 2, 100, 4, 5, 6, 7, 8, 9]) // 7没有变-1说明,获取的数组与原数组不共享同一块数组空间
(3).使用布尔数组获取
使用布尔数组获取其实和利用整数序列获取类似
>>> a=np.arange(10,0,-2) >>> a array([10, 8, 6, 4, 2]) >>> a[[True,False,False,True,False]] //利用布尔数组获取数组,把对应true部分的元素进行获取 array([10, 4]) >>> a[np.array([True,False,False,True,False])]=-1,-1 //布尔下标可以用来修改数组元素 >>> a array([-1, 8, 6, -1, 2])
3.多维数组
多维数组同样可以用切片获取,如图所示a数组为二维数组,有0轴和1轴
例如:a[1,2:4]=array([6,7]) 列表的第一个参数为0轴参数,第二个参数为1轴参数,0轴和1轴相交叉的点即为数组中的点
a[1:3,2:3]=array([[6],[10]])
a[0:3:2,1::2]=array([[2,4],[10,12]])
4.结构数组
可以创建结构体数据类型,并且用于创建数组
>>> import numpy as np >>> student=np.dtype({ //创建名为student的结构体数据类型 ... 'names':['name','class','grade'], //参数列表 ... 'formats':['S32','int','f']}) //参数对应的数据类型列表 >>> a=np.array([("asd",6,89.5),("zxc",3,92.5)],dtype=student) //用student结构体数据类型创建数组 >>> a array([(b'asd', 6, 89.5), (b'zxc', 3, 92.5)], dtype=[('name', 'S32'), ('class', '<i4'), ('grade', '<f4')]) //结构体数据类型 >>> a[0] //可以用类似列表的方式对数组进行获取 (b'asd', 6, 89.5) >>> b=a[0] >>> b["name"]="qwe" >>> a[0] (b'qwe', 6, 89.5) //结构体元素a[0]与数组a共享同一块存储空间 >>> a[0]["name"] //可以对数组中的单个结构体元素的单个参数进行获取 b'qwe' >>> a[:]["class"] //以这种方式获取数组中所有结构体元素的某一参数所组成的列表 array([6, 3])
5.ufunc运算
ufunc能够对数组的每个元素进行操作和处理,而且很多ufunc函数是在C语言级别进行实现的,所以计算速度非常快
(1)numpy自带的ufunc函数
例如:
>>> x=np.arange(0,10,2) >>> y=np.sin(x) //对数组的各个元素进行求正弦值运算,并将计算结果存储在数组中 >>> y array([ 0. , 0.90929743, -0.7568025 , -0.2794155 , 0.98935825])
np.sin()还有另外1个参数,第二个参数是一个数组对象,用于存储计算结果,第一个参数就是需要进行计算操作的数组
>>> x=np.logspace(0,1,5) >>> x array([ 1. , 1.77827941, 3.16227766, 5.62341325, 10. ]) >>> np.sin(x,x) //注意只能用同一数据类型进行存储,比如x原来是整型数组,在计算完正弦值后所得浮点数就不能放到x中,不然会报错 array([ 0.84147098, 0.97855249, -0.02068353, -0.61293676, -0.54402111]) >>> x array([ 0.84147098, 0.97855249, -0.02068353, -0.61293676, -0.54402111])
注意:numpy库中的数值计算函数对整个数组的所有元素进行计算,要比math库中的数值计算函数快很多
但是如果只是对单一数值进行计算,则math库的数值计算函数要优于numpy库
所以要根据具体的情况用不同的方式进行计算
np.add方法可以对2个相同shape的数组进行加法操作
>>> a=np.arange(0,5) //创建a数组 >>> a array([0, 1, 2, 3, 4]) >>> b=np.arange(5,10) //创建b数组 >>> b array([5, 6, 7, 8, 9]) >>> np.add(a,b) //将a,b两数组进行加法操作 array([ 5, 7, 9, 11, 13])
和np.sin一样,np.add 同样有一个额外的参数用来存储计算的结果
>>> b array([5, 6, 7, 8, 9]) >>> np.add(a,b,b) //用b数组存储计算结果 array([ 5, 7, 9, 11, 13]) >>> b array([ 5, 7, 9, 11, 13])
当然还有很多其他的计算函数,就不一一列举了,原理都一样
y = x1 + x2: | add(x1, x2 [, y]) 两数组相加 |
y = x1 - x2: | subtract(x1, x2 [, y]) 两数组相减 |
y = x1 * x2: | multiply (x1, x2 [, y]) 两数组相乘 |
y = x1 / x2: | divide (x1, x2 [, y]), 整数除法 |
y = x1 / x2: | true divide (x1, x2 [, y]), 除法,返回浮点数,精确 |
y = x1 // x2: | floor divide (x1, x2 [, y]), 除法,地板除,返回整数,不精确 |
y = -x: | negative(x [,y]) 取相反数 |
y = x1**x2: | power(x1, x2 [, y]) x1的x2次幂 |
y = x1 % x2: | remainder(x1, x2 [, y]), mod(x1, x2, [, y]) 进行模运算 |
2.自定义函数:
将要进行操作的数组的值代入自定义函数进行计算获取一个结果数组
>>> def test(t): //创建1个自定义的test函数 ... return t**2+np.sin(t) ... >>> x=np.linspace(0,1,20) //创建一个用于数值操作的数组 >>> x array([0. , 0.05263158, 0.10526316, 0.15789474, 0.21052632, 0.26315789, 0.31578947, 0.36842105, 0.42105263, 0.47368421, 0.52631579, 0.57894737, 0.63157895, 0.68421053, 0.73684211, 0.78947368, 0.84210526, 0.89473684, 0.94736842, 1. ]) >>> y=np.array([test(t) for t in x]) //将数组的每个元素的值代入自定义的test函数进行计算 >>> y array([0. , 0.05537737, 0.11614921, 0.18217023, 0.25329595, 0.3293831 , 0.41029 , 0.49587696, 0.58600669, 0.68054466, 0.77935946, 0.8823232 , 0.98931182, 1.10020548, 1.21488884, 1.33325143, 1.45518793, 1.58059846, 1.70938887, 1.84147098])
由于每次都要调用列表的方法,对于多维数组比较麻烦,numpy中提供了frompyfunc函数来解决这一问题
具体用法如下:
>>> testufunc=np.frompyfunc(lambda t:test(t),1,1) //第2个参数表示输入参数的个数,第3个参数表示函数返回值的个数 >>> y=testufunc(x) >>> y array([0.0, 0.05537736644056521, 0.11614920617592142, 0.1821702297841879, 0.25329595370267466, 0.329383100366977, 0.4102899950101256, 0.49587695802287973, 0.5860066917885429, 0.6805446609209846, 0.7793594648528199, 0.882323201741885, 0.9893118226881892, 1.100205475280363, 1.214888835520164, 1.3332514272058, 1.4551879278895505, 1.580598460562359, 1.7093888702575877, 1.8414709848078965], dtype=object)
6.广播
前面已经介绍了两个shape相同的数组间的计算,对于两个不同shape的数组进行计算,则需要进行广播处理
(1)对于2个数组,shape不足的自动前面加1补齐
(2)所得结果数组的shape中每一轴长取2个数组中的更长的那一轴
(3)a,b数组的每一轴的长度需等于结果数组的每一轴的长度或者其长度为1(长度为1可以根据原理4进行拓展成所需轴长度),才能进行计算
(4)当2个数组中shape的某一轴长度为1时,沿着这个轴计算时,都用第一组值进行计算
例如:
>>> a=np.arange(0,5).reshape(-1,1) >>> a array([[0], [1], [2], [3], [4]]) >>> b=np.arange(0,6) >>> b array([0, 1, 2, 3, 4, 5]) >>> a.shape (5, 1) >>> b.shape (6,)
可以看出a的shape为(5,1),b的为(6,)
所以根据原理(1),需在b的shape最前面补1,补成(1,6)
>>> b.shape=1,6
>>> b
array([[0, 1, 2, 3, 4, 5]])
根据原理(2)可知,计算结果数组的shape应为(5,6),根据原理(3),必须先对a,b数组进行拓展才能进行计算
python中提供了repeat函数对数组进行拓展
>>> a=a.repeat(6,axis=1) //将a数组1轴的shape拓展为6 >>> a array([[0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1], [2, 2, 2, 2, 2, 2], [3, 3, 3, 3, 3, 3], [4, 4, 4, 4, 4, 4]]) >>> b=b.repeat(5,axis=0) //将b数组0轴的shape拓展为5 >>> b array([[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]])
接着就可以对数组a,b进行计算(其实最初创建的数组满足原理(3)就可以直接进行计算,拓展操作由计算机内部完成)
>>> c=a+b >>> c array([[0, 1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7], [3, 4, 5, 6, 7, 8], [4, 5, 6, 7, 8, 9]]) >>> c.shape (5, 6)
7.ufunc方法
(1)np.add.reduce(数组参数) 可以将数组内部的所有元素进行相加,返回值是1个和
一维数组
>>> np.add.reduce([1,2,3])
6
多维数组
>>> np.add.reduce([[1,2,3],[4,5,6]],axis=1) //将第1轴的元素进行求和,返回一个结果数组
array([ 6, 15])
(2)np.add.accumulate(数组参数) 和reduce使用方法类似,但是保存中间结果
一维数组
>>> np.add.accumulate([1,2,3])
array([1, 3, 6], dtype=int32)
多维数组
>>> np.add.accumulate([[1,2,3],[4,5,6]],axis=1) array([[ 1, 3, 6], [ 4, 9, 15]], dtype=int32)
(3).np.add.reduceat(数组,indices列表) 举个例子理解一下
>>> a=np.arange(0,5) //创建a数组 >>> np.add.reduceat(a,indices=[0,1,0,2,0,3]) //调用reduceat方法 array([0, 1, 1, 2, 3, 7], dtype=int32)
主要解释下indices列表,可以发现,返回的结果数组的长度和列表的长度相等
除了最后1个元素,其他元素的计算方法
if indices[i] < indices[i+1]: result[i] = np.reduce(a[indices[i]:indices[i+1]]) else: result[i] = a[indices[i]]
最后一个元素的计算方法
np.reduce(a[indices[-1]:])
(4)outer方法
>>> np.multiply.outer([1,2,3,4,5],[6,7,8]) //a,b两数组进行乘积运算 array([[ 6, 7, 8], [12, 14, 16], [18, 21, 24], [24, 28, 32], [30, 35, 40]])
8.矩阵运算
numpy库中提供了matrix类,用于创建矩阵对象,矩阵也可进行相应的加减乘除运算
>>> a=np.matrix([[1,2,3],[2,6,6],[5,8,9]]) //创建a矩阵 >>> a matrix([[1, 2, 3], [2, 6, 6], [5, 8, 9]]) >>> b=np.matrix([[3,2,1],[5,3,2],[6,6,9]]) //创建b矩阵 >>> b matrix([[3, 2, 1], [5, 3, 2], [6, 6, 9]]) >>> a*a**-1 //一个矩阵和它的逆矩阵乘积为单位矩阵 matrix([[ 1.00000000e+00, -2.77555756e-17, -5.55111512e-17], [ 0.00000000e+00, 1.00000000e+00, -1.11022302e-16], [ 4.44089210e-16, -3.05311332e-16, 1.00000000e+00]]) >>> a+b //矩阵相加 matrix([[ 4, 4, 4], [ 7, 9, 8], [11, 14, 18]]) >>> a-b //矩阵相减 matrix([[-2, 0, 2], [-3, 3, 4], [-1, 2, 0]]) >>> a/b //矩阵相除 matrix([[0.33333333, 1. , 3. ], [0.4 , 2. , 3. ], [0.83333333, 1.33333333, 1. ]]) >>> a*b //矩阵相乘 matrix([[ 31, 26, 32], [ 72, 58, 68], [109, 88, 102]])
注:其中部分参考http://old.sebug.net/paper/books/scipydoc/numpy_intro.html#id3