Numpy 是广泛应用于学术,工业的python数值计算库,其底层源码由C,Fortran写成。
由于python语言灵活,简洁,而且在数值计算中有numpy,scipy,sympy这类数值计算库的依托,使得快速开发
数值算法十分简便。所以python在数值计算中应用十分广泛,而numpy更是python数值计算中的基石。
本文主要介绍array操作和Numpy常用函数,这是数值计算的基础。
python数值计算领域,numpy是其他数值计算库的基础。
安装其他函数库的时候,经常看到安装条件是已安装numpy。
而在numpy中,ndarray正是numpy的基础。
In [1]: import numpy as np In [2]: a = np.zeros(3) #生成一个三维零向量 In [3]: a Out[3]: array([ 0., 0., 0.]) In [4]: type(a) Out[4]: numpy.ndarraynumpy的arrays有点像python的list,但是又有一些不同:
1.array中所有元素必须为同一类型
2.而这数据类型必须是Numpy提供的数据类型(dtypes)之一
numpy提供的最重要数据类型有:
1.float64 64位浮点数
2.float32 32位浮点数
3.int64 64位整数
4.int32 32位整数
5.bool 8位 True 或者 False
还有其他一些数据类型包括:无符号整数,复数
可以测试一下自己的numpy默认的数据类型是什么
In [7]: a = np.zeros(3) In [8]: type(a[0]) Out[8]: numpy.float64 #64位浮点数当然,如果你要想要整数值组成的零向量也可以,
这时候需要改变默认参数的dtype=int
In [9]: a = np.zeros(3, dtype=int) In [10]: type(a[0]) Out[10]: numpy.int32
进行如下命令:
In [11]: z = np.zeros(10)这时候z既不是行向量也不是列向量。可以叫它没有维度的‘flat’array(with no dimension )
z的维度(dimension )被记录在shape属性中,也就是z.shape ,它是一个tuple
In [12]: z.shape Out[12]: (10,) # 元组中只有一个元素的时候要加逗号。这时候,z.shape中只有一个元素,仅仅表示z的长度而已,你可千万别多想。
如果使z具有维度的话,那么就先从改变z.shape做起吧。
要创建两行两列的零阵,这样做也太麻烦了,直接穿递元组(2,2)到np.zeros()就可以了。
z = np.zeros((2, 2))
我们知道用np.zeros()就可以创建零元素组成的数组。同样,我们可以创建全部由1组成的数组。
z = np.ones((2, 2))#2行2列数组,数组元素都为1我们还可以创建空数组 np.empty(),以便以后传入参数进去。
In [18]: z = np.empty(3) In [19]: z Out[19]: array([ 8.90030222e-307, 4.94944794e+173, 4.04144187e-262])np.empty(3)在内存中连续开辟出可以存放3个float64元素的地址。得到的z,其中的元素都是随机的,没有意义。
要创建某个区间的连续多个数值组成的数组,可以用np.linspace(a,b,num)
代表在区间[a,b]上去num个均匀分隔这个区间的点。
In [20]: z = np.linspace(2, 4, 5) # From 2 to 4, with 5 elements
array([ 2. , 2.5, 3. , 3.5, 4. ])
创建单位矩阵可以使用np.identity(),np.eye()
In [21]: z = np.identity(2) In [22]: z Out[22]: array([[ 1., 0.], [ 0., 1.]])另外,array可以利用np.array()直接通过python的list直接创建。
In [23]: z = np.array([10, 20]) # ndarray from Python list In [24]: z Out[24]: array([10, 20]) In [25]: type(z) Out[25]: numpy.ndarray In [26]: z = np.array((10, 20), dtype=float) # Here 'float' is equivalent to 'np.float64' In [27]: z Out[27]: array([ 10., 20.]) In [28]: z = np.array([[1, 2], [3, 4]]) # 2D array from a list of lists In [29]: z Out[29]: array([[1, 2], [3, 4]])
而np.array()是创建一个新的np.narray对象。
>>> from StringIO import StringIO # StringIO behaves like a file object >>> c = StringIO("0 1\n2 3") >>> np.loadtxt(c) array([[ 0., 1.], [ 2., 3.]])同样,还可以载入字符串数据
>>> d = StringIO("M 21 72\nF 35 58") >>> np.loadtxt(d, dtype={'names': ('gender', 'age', 'weight'), ... 'formats': ('S1', 'i4', 'f4')}) #'name' 表示数据各列的名称。'format'表式格式。 array([('M', 21, 72.0), ('F', 35, 58.0)], dtype=[('gender', '|S1'), ('age', '<i4'), ('weight', '<f4')])更加高级的使用形式,如载入csv文件:
>>> c = StringIO("1,0,2\n3,0,4") >>> x, y = np.loadtxt(c, delimiter=',', usecols=(0, 2), unpack=True) >>> x array([ 1., 3.]) >>> y array([ 2., 4.])delimiter 表示分隔符为逗号,usecols表示载入文件中的哪列数据。本文中是第0,2列。unpack参数
表示的是分裂,用x引用第0列,用y引用第2列。unpack的默认值为False,如果要使用x,y = np.loadtxt(something)
一定不要忘记修改unpack的默认值。
使用更高级的np.genfromtxt()载入文本数据。genfromtxt可以处理缺失值。
>>> s = StringIO("1,1.3,abcde") >>> data = np.genfromtxt(s, dtype=[('myint','i8'),('myfloat','f8'), ... ('mystring','S5')], delimiter=",") >>> data array((1, 1.3, 'abcde'), dtype=[('myint', '<i8'), ('myfloat', '<f8'), ('mystring', '|S5')])
>>> s.seek(0) # needed for StringIO example only >>> data = np.genfromtxt(s, dtype=None, ... names = ['myint','myfloat','mystring'], delimiter=",") >>> data array((1, 1.3, 'abcde'), dtype=[('myint', '<i8'), ('myfloat', '<f8'), ('mystring', '|S5')])
>>> s.seek(0) >>> data = np.genfromtxt(s, dtype="i8,f8,S5", ... names=['myint','myfloat','mystring'], delimiter=",") >>> data array((1, 1.3, 'abcde'), dtype=[('myint', '<i8'), ('myfloat', '<f8'), ('mystring', '|S5')])使用固定宽度分割每行数据,delimiter=[1,3,5]各列固定宽度分别为1,3,5
>>> s = StringIO("11.3abcde") >>> data = np.genfromtxt(s, dtype=None, names=['intvar','fltvar','strvar'], ... delimiter=[1,3,5]) >>> data array((1, 1.3, 'abcde'), dtype=[('intvar', '<i8'), ('fltvar', '<f8'), ('strvar', '|S5')])
对于1维数组来讲,索引与python中序列的索引没有区别。
In [30]: z = np.linspace(1, 2, 5) In [31]: z Out[31]: array([ 1. , 1.25, 1.5 , 1.75, 2. ]) In [32]: z[0] Out[32]: 1.0 In [33]: z[0:2] # Slice numbering is left closed, right open Out[33]: array([ 1. , 1.25]) In [34]: z[-1] Out[34]: 2.0
In [35]: z = np.array([[1, 2], [3, 4]]) In [36]: z Out[36]: array([[1, 2], [3, 4]]) In [37]: z[0, 0] Out[37]: 1 In [38]: z[0, 1] Out[38]: 2切片功能则是矩阵索引与python切片的结合。
In [39]: z[0,:] #第0行 Out[39]: array([1, 2]) In [40]: z[:,1] #第1列 Out[40]: array([2, 4])用numpy数组索引:
In [41]: z = np.linspace(2, 4, 5) In [42]: z Out[42]: array([ 2. , 2.5, 3. , 3.5, 4. ]) In [43]: indices = np.array((0, 2, 3)) In [44]: z[indices] Out[44]: array([ 2. , 3. , 3.5])这仅仅是第一种形式,indices包含的仅仅是所需元素的位置。
indices还可以为仅仅指明每个元素是否可留,留下来为True,不需要的为False,这是另一种方法:
In [45]: z Out[45]: array([ 2. , 2.5, 3. , 3.5, 4. ]) In [46]: d = np.array([0, 1, 1, 0, 0], dtype=bool) #注意datype是bool,1代表True,0代表False In [47]: d Out[47]: array([False, True, True, False, False], dtype=bool) In [48]: z[d] Out[48]: array([ 2.5, 3. ])索引全部使用z[:]
In [49]: z = np.empty(3) In [50]: z Out[50]: array([ -1.25236750e-041, 0.00000000e+000, 5.45693855e-313]) In [51]: z[:] = 42 In [52]: z Out[52]: array([ 42., 42., 42.])
以下所有方法都被高度优化。
In [53]: A = np.array((4, 3, 2, 1)) In [54]: A Out[54]: array([4, 3, 2, 1]) In [55]: A.sort() # 升序排序,无返回值 In [56]: A Out[56]: array([1, 2, 3, 4]) In [57]: A.sum() # 求和 Out[57]: 10 In [58]: A.mean() # 平均值 Out[58]: 2.5 In [59]: A.max() # 最大值 Out[59]: 4 In [60]: A.argmax() # 最大值所在位置 Out[60]: 3 In [61]: A.cumsum() # 累积和 Out[61]: array([ 1, 3, 6, 10]) In [62]: A.cumprod() # 累积积 Out[62]: array([ 1, 2, 6, 24]) In [63]: A.var() # 方差 Out[63]: 1.25 In [64]: A.std() # 标准差 Out[64]: 1.1180339887498949 In [65]: A.shape = (2, 2) In [66]: A.T # 转置 与 A.transpose() 作用相同 Out[66]: array([[1, 3], [2, 4]])
In [67]: z = np.linspace(2, 4, 5) In [68]: z Out[68]: array([ 2. , 2.5, 3. , 3.5, 4. ]) In [69]: z.searchsorted(2.2) Out[69]: 1 In [70]: z.searchsorted(2.5) Out[70]: 1 In [71]: z.searchsorted(2.6) Out[71]: 2当然,上文所介绍的array方法,还可以直接作用于python的基本序列结构:
In [72]: a = np.array((4, 3, 2, 1)) In [73]: np.sum(a) Out[73]: 10 In [74]: np.mean(a) Out[74]: 2.5
代数运算:+,-,*,/,**
这些运算的对象都是array中的每个元素,与向量运算一样
In [75]: a = np.array([1, 2, 3, 4]) In [76]: b = np.array([5, 6, 7, 8]) In [77]: a + b #每个元素相加 Out[77]: array([ 6, 8, 10, 12]) In [78]: a * b #每个元素相乘,这可不是向量的内积运算! Out[78]: array([ 5, 12, 21, 32])array与标量运算。
In [79]: a + 10 Out[79]: array([11, 12, 13, 14])
In [81]: a = np.array([1, 2, 3, 4]) In [82]: a * 10 Out[82]: array([10, 20, 30, 40])多维数组也是如此
In [86]: A = np.ones((2, 2)) In [87]: B = np.ones((2, 2)) In [88]: A + B Out[88]: array([[ 2., 2.], [ 2., 2.]]) In [89]: A + 10 Out[89]: array([[ 11., 11.], [ 11., 11.]]) In [90]: A * B Out[90]: array([[ 1., 1.], [ 1., 1.]])向量与矩阵乘法
numpy中向量与矩阵的乘法由dot()函数完成。
In [137]: A = np.ones((2, 2)) In [138]: B = np.ones((2, 2)) In [139]: np.dot(A, B) Out[139]: array([[ 2., 2.], [ 2., 2.]])
In [94]: A = np.empty((2, 2)) In [95]: A Out[95]: array([[ 3.48091887e-262, 1.14802984e-263], [ 3.61513512e-313, -1.25232371e-041]]) In [96]: np.dot(A, (0, 1)) Out[96]: array([ 1.14802984e-263, -1.25232371e-041])这里(0,1)被认为是一个列向量
比较操作,比较的是两个array上相对应位置的元素的值,返回的是元素类型为bool的array
In [97]: z = np.array([2, 3]) In [98]: y = np.array([2, 3]) In [99]: z == y Out[99]: array([ True, True], dtype=bool) In [100]: y[0] = 5 In [101]: z == y Out[101]: array([False, True], dtype=bool) In [102]: z != y Out[102]: array([ True, False], dtype=bool)比较符号依然是,>,<,==,!=,>=,<=
array可以直接与标量比较
In [103]: z = np.linspace(0, 10, 5) In [104]: z Out[104]: array([ 0. , 2.5, 5. , 7.5, 10. ]) In [105]: z > 3 Out[105]: array([False, False, True, True, True], dtype=bool)比较操作经常用于条件索引:
In [106]: b = z > 3 In [107]: b Out[107]: array([False, False, True, True, True], dtype=bool) In [108]: <span style="color:#ff0000;">z[b]</span> Out[108]: array([ 5. , 7.5, 10. ])更加直接的比较索引如下:
In [109]:<span style="color:#ff0000;"> z[z > 3]</span> Out[109]: array([ 5. , 7.5, 10. ])
numpy中还有一些其他函数可以直接处理array数据。如np.sin(),np.cos(),np.exp(),np.log()
In [110]: z = np.array([1, 2, 3]) In [111]: np.sin(z) Out[111]: array([ 0.84147098, 0.90929743, 0.14112001])
In [112]: z Out[112]: array([1, 2, 3]) In [113]: (1 / np.sqrt(2 * np.pi)) * np.exp(- 0.5 * z**2) Out[113]: array([ 0.24197072, 0.05399097, 0.00443185])np.where(x>0,1,0) 十分像C语言中的唯一三元运算符 a>b? 1:0
一个对标量数据进行处理的函数,如何才能用于处理向量呢?
当然可以直接重新写一个,但是比较费时费力,numpy给我们提供了另一个思路:
在原有标量函数的基础上,将标量函数向量化,得到的新函数可以直接处理向量数据:
In [118]: def f(x): return 1 if x > 0 else 0 In [119]: f = np.vectorize(f) In [120]: f(x) # Passing same vector x as previous example Out[120]: array([0, 1, 0, 0])
In [131]: A = np.array([[1, 2], [3, 4]]) In [132]: np.linalg.det(A) # 行列式 Out[132]: -2.0000000000000004 In [133]: np.linalg.inv(A) # 求逆矩阵 Out[133]: array([[-2. , 1. ], [ 1.5, -0.5]]) In [134]: Z = np.random.randn(10000) # 生成正态分布 In [135]: y = np.random.binomial(10, 0.5, size=1000) # 生成伯努利分布 In [136]: y.mean() Out[136]: 5.0369999999999999