Python科学计算-----NumPy(一)

来源:互联网 发布:区块链的共识机制 算法 编辑:程序博客网 时间:2024/05/16 07:51

Numpy

NumPy 是 Numerical Python的简称,是Python的高性能计算和数据分析的基础核心包。与Python的基本数据类型相比,其具有以下突出优势

  • 提供功能更强大的高维数组(N-dimensional)对象
  • 强大的广播功能(broadcasting),便于矢量化数组操作(直接对数组进行数据处理,而不需要编写循环)
  • 集成了 C/C++ 以及 Fortran代码编写的工具
  • 包含常用的线性代数、傅里叶变换,以及随机数生成
  • 提供易用的C API,可以将数据传递到使用低级语言编写的外部库,也可以使外部库返回NumPy数组数据到Python
  • 通用的数组算法,例如:sorting,unique和set等操作
  • NumPy提供了两种基本的对象:ndarray(N-dimensional array object)和ufunc(universal function object)。ndarray用来存储单一数据类型的多维数组,ufunc是对数组进行处理的函数。

    ndarray

    笔者在初次接触NumPy的数组对象时,一直搞不清其与Python的基本数据对象List,array的区别,在此对三者用于数值操作时的差异进行对比:

  • list在Python中应用非常广泛,常常被当作数组使用,List的大小可以随意改变,同一个List的元素可以是任意类型的数据,因此List需要保存每个对象的指针。但是这样的特性在数值操作中就成为了很大的弊端,试想List中存储的都是类似于1,2,3这样的数值类型,此时仍要保存这些整数对象的指针,这种存储结构对于数值计算来说显然是极浪费内存和计算时间的。
  • 由于List强大的灵活性,Python自带的array模块很少被使用,array数组只能存储同种数据类型,但是它所占的存储空间的要远小于List,类似于c语言中的数组类型。如果是对一致的数据类型进行数值运算,array在性能上要优与List。但是array和List相比,不支持多维数组,也没有丰富的数值运算函数,因此在数值运算上也很鸡肋。
  • NumPy数组对象ndarray支持多维数组,同时数组类型必须是同质的,高效的数值操纵,弥补了以上两者的不足。
  • 基本属性

    ndarray.ndim
    数组的最大维度,也叫做数组的轴的个数(从0开始)。

    In [12]: a = np.arange(20).reshape(1,4,5)In [13]: aOut[13]:array([[[ 0,  1,  2,  3,  4],        [ 5,  6,  7,  8,  9],        [10, 11, 12, 13, 14],        [15, 16, 17, 18, 19]]])In [14]: a.ndimOut[14]: 3

    ndarray.shape
    数组的形状,是一个整数元组,显示了每个轴的大小。对于一个n行m列的数组,shape就是元组(n,m) ,元祖的长度也是轴的总数。

    In [15]: a.shapeOut[15]: (1L, 4L, 5L)In [18]: len(a.shape)Out[18]: 3

    使用shape改变数组形状

    In [19]: a.shape = 2,2,5  #也可以是a.shape = ((2,2,5))In [20]: aOut[20]:array([[[ 0,  1,  2,  3,  4],        [ 5,  6,  7,  8,  9]],       [[10, 11, 12, 13, 14],        [15, 16, 17, 18, 19]]])

    如果数组的某个轴的长度被设置为-1,则该轴的长度将被自动计算出来

    In [38]: a.shape = 4,-1In [39]: aOut[39]:array([[ 0,  1,  2,  3,  4],       [ 5,  6,  7,  8,  9],       [10, 11, 12, 13, 14],       [15, 16, 17, 18, 19]])

    使用reshape方法创建一个改变了尺寸的新的数组,原数组的大小不变

    In [21]: a.reshape(5,2,2)Out[21]:array([[[ 0,  1],        [ 2,  3]],       [[ 4,  5],        [ 6,  7]],       [[ 8,  9],        [10, 11]],       [[12, 13],        [14, 15]],       [[16, 17],        [18, 19]]])In [22]: aOut[22]:array([[[ 0,  1,  2,  3,  4],        [ 5,  6,  7,  8,  9]],       [[10, 11, 12, 13, 14],        [15, 16, 17, 18, 19]]])

    注意:1、使用reshape创建的数组是原数组的试图,和原数组共享内存,修改任何一个数组的元素值都会同时改变两个数组。
    2、使用reshape并不改变数组中元素在内存中的位置,这和矩阵的转置不同,后者将改变元素在内存中的位置。

    In [45]: b = a.reshape(5,2,2)In [46]: b[2]=10In [47]: bOut[47]:array([[[ 0,  1],        [ 2,  3]],       [[ 4,  5],        [ 6,  7]],       [[10, 10],        [10, 10]],       [[12, 13],        [14, 15]],       [[16, 17],        [18, 19]]])In [48]: aOut[48]:array([[ 0,  1,  2,  3,  4],       [ 5,  6,  7, 10, 10],       [10, 10, 12, 13, 14],       [15, 16, 17, 18, 19]])

    ndarray.size
    数组中总的元素个数,等于元组shape的内积

    In [49]: a.shapeOut[49]: (4L, 5L)In [50]: a.size20

    ndarray.dtype
    一个描述数组中元素类型的对象。NumPy提供了 numpy.int32, numpy.int16, 和 numpy.float64 等类型。创建数组的时候可以指定数组内元素的类型,对dtype属性指定元素类型

    In [54]: a = arange(0,19,2,dtype=float)In [55]: aOut[55]: array([  0.,   2.,   4.,   6.,   8.,  10.,  12.,  14.,  16.,  18.])In [56]: a = arange(0,19,2,dtype=complex)In [57]: aOut[57]:array([  0.+0.j,   2.+0.j,   4.+0.j,   6.+0.j,   8.+0.j,  10.+0.j,        12.+0.j,  14.+0.j,  16.+0.j,  18.+0.j])

    ndarray.itemsize
    数组中每个元素的大小。
    例如 数组元素类型是 float64 的itemsize为 8 (=64/8), complex32 类型的 itemsize是4 (=32/8). 等价于ndarray.dtype.itemsize.

    >>> a = np.array([[1.3,3.5],[3.6,6.]])>>> a.dtypedtype('float64')>>> a.itemsize8

    创建数组

    NumPy创建数组的方式很多,主要有以下几种:

    array创建数组

    使用Python的array模块创建数组,传入的参数类似于List创建的多维数组,参数也可以是dtype,用于指定数据的类型

    >>> np.array([[1,2,3],[4,5,6]])array([[1, 2, 3],       [4, 5, 6]])

    等价于

    In [10]: a = [[1,2,3],[4,5,6]]In [11]: np.array(a)Out[11]:array([[1, 2, 3],       [4, 5, 6]])

    注意:不能缺少最外围的[ ]

    >>> np.array([1,2,3],[4,5,6])Traceback (most recent call last):  File "<pyshell#47>", line 1, in <module>    np.array([1,2,3],[4,5,6])TypeError: data type not understood

    占位符创建数组

    以上几种方式只是对数据创建方式的简单解释,实际应用中,数组中的元素常常是未知的,但是其大小是确定的,因此可以使用占位符来初始化数组的内容,NumPy提供了几种占位符方法。每种方法都可以指定元素的类型
    np.zeros
    创建一个内容全是0的数组

    >>> np.zeros((3,4))array([[ 0.,  0.,  0.,  0.],       [ 0.,  0.,  0.,  0.],       [ 0.,  0.,  0.,  0.]])

    np.ones
    创建内容全是1的数组, 可以通过dtype制定参数数据类型

    >>> np.ones((2,3,4),dtype=np.float64)array([[[ 1.,  1.,  1.,  1.],        [ 1.,  1.,  1.,  1.],        [ 1.,  1.,  1.,  1.]],       [[ 1.,  1.,  1.,  1.],        [ 1.,  1.,  1.,  1.],        [ 1.,  1.,  1.,  1.]]])

    np.empty
    不对内容进行初始化,只分配内存空间。内容常常是未初始化的垃圾值

    指定范围生成数组

    np.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])

    如果步长为负数,表示起始值大于终止值

    In [103]: x = arange(7,2,-2)In [104]: xOut[104]: array([7, 5, 3])

    np.linspace
    对于浮点类型的数组,给出范围和步长,通常很难预测元素的数量(与浮点数的精度有关),因此对于浮点类型数组,最好指定其元素个数,而不是其步长。
    前两个参数依然是元素值范围,最后一个参数是产生的数据个数。

    >>> np.linspace(1,6,4)array([ 1.        ,  2.66666667,  4.33333333,  6.        ])

    np.logspace
    logspace函数和linspace函数类似,但是前者创建以10为底的等比数列,如下,创建一个含有10个元素的等比数列,范围在1(10^0)到(10^20)

    In [58]: a = logspace(0,20,10)In [59]: aOut[59]:array([  1.00000000e+00,   1.66810054e+02,   2.78255940e+04,         4.64158883e+06,   7.74263683e+08,   1.29154967e+11,         2.15443469e+13,   3.59381366e+15,   5.99484250e+17,         1.00000000e+20])

    也可以使用frombuffer, fromstring, fromfile等函数可以从字节序列创建数组
    也可以自定义函数,生成数组,使用fromfunction。

    随机数生成数组

    np.random.rand()
    [0,1)上的均匀分布产生产生的随机样本,参数是生成的数组的大小

    In [5]: np.random.rand(2,3)Out[5]:array([[ 0.26865184,  0.62972262,  0.58904232],       [ 0.47760496,  0.18785592,  0.85511524]])

    np.random.randn()
    不指定参数,默认服从标准正态分布(sigma为1,mu为0)
    指定参数,服从 N(mu, sigma^2)的正态分布随机产生的样本,可以使用:
    sigma * np.random.randn(…) + mu

    In [6]: np.random.randn(2,3)Out[6]:array([[ 0.88717589, -0.22562155,  1.44601412],       [ 1.15406383,  0.75708636,  0.69189156]])#其中mu是3, sigma是2.5In [7]: 2.5*np.random.randn(2,3)+3Out[7]:array([[ 1.22514961,  3.72308164,  2.62028917],       [ 3.25345077,  4.35030785,  3.76266858]])

    更多关于产生随机数的方法参见NumPy的random模块

    索引和切片

    一维数组切片

    一维数组的切片与python的list切片差不多,主要的不同是,数组切片返回的是原数组的视图,即数据不会被复制,任何对切片后数组的修改都会反映到原数组上,而List的切片返回的是切片后的副本。

    多维数组索引

    数组的索引灵活而丰富,大部分索引的数组操作都是通过索引进行的。一维数组的索引较为简单,本文不再详述,接下来引入几种常见的多维数组的索引。

    整数索引
    不同轴的索引对应单个整数,不同轴的索引以逗号隔开

    In [5]: aOut[5]:array([[ 0.03664104,  0.63714562,  0.1265633 ],       [ 0.12740582,  0.03731622,  0.17917975],       [ 0.04590225,  0.74800245,  0.74495221],       [ 0.99799526,  0.90753861,  0.93806741]])#只选择第1个轴的索引In [6]: a[1]Out[6]: array([ 0.12740582,  0.03731622,  0.17917975])#选择第1个轴和第二个轴的索引In [8]: a[1,2]Out[8]: 0.17917974571757078

    注意:通过整数索引获取的数据是原数组的视图,两者共享内存,改变对应索引的数据会相应地改变原数组的数据。

    In [29]: a[1][1]=10In [30]: aOut[30]:array([[  0.03664104,   0.63714562,   0.1265633 ],       [  0.12740582,  10.        ,   0.17917975],       [  0.04590225,   0.74800245,   0.74495221],       [  0.99799526,   0.90753861,   0.93806741]])

    切片索引
    数组的每一个轴(axis)都有一个索引,可以对一个或者多个轴进行切片,也可以与整数索引混合使用,相邻轴之间的索引参数使用逗号隔开。

    In [32]: a[1:3,1:3]Out[32]:array([[ 10.        ,   0.17917975],       [  0.74800245,   0.74495221]])In [34]: a[1:3,1]Out[34]: array([ 10.        ,   0.74800245])

    使用:(冒号)选择数组某个轴的所有元素

    In [36]: a[:,1]Out[36]: array([  0.63714562,  10.        ,   0.74800245,   0.90753861])

    负数索引,从尾部开始选取数据

    In [40]: a[:,-1]Out[40]: array([ 0.1265633 ,  0.17917975,  0.74495221,  0.93806741])

    负数切片,逆序选择指定间隔的数据,切片的起始值要大小终止值

    In [44]: a[:,-3:-1]Out[44]:array([[  0.03664104,   0.63714562],       [  0.12740582,  10.        ],       [  0.04590225,   0.74800245],       [  0.99799526,   0.90753861]])

    参数的个数少于轴的个数,缺失参数的轴默认为完整的切片

    In [45]: a[1]                       #等价于a[1,:]Out[45]: array([  0.12740582,  10.        ,   0.17917975])

    注意:通过切片索引获取的数据也是原数组的视图。

    布尔型索引
    对数组进行算数运算,将会产生一个布尔型数组,运算符可以是>,<,==,!=,|(或),&(与),-(负)等

    In [51]: a = np.array(['one','two','three'])In [55]: a == 'two'Out[55]: array([False,  True, False], dtype=bool)In [53]: b = np.random.rand(3,4)In [54]: bOut[54]:array([[ 0.23529625,  0.87521492,  0.1038766 ,  0.10058617],       [ 0.25178891,  0.1172799 ,  0.51411217,  0.86013535],       [ 0.75510171,  0.81136768,  0.12842083,  0.22549127]])In [56]: b[a=='two']Out[56]: array([[ 0.25178891,  0.1172799 ,  0.51411217,  0.86013535]])

    布尔型索引也可以和整数型索引和切片索引混合使用

    In [57]: b[a=='two',:3]Out[57]: array([[ 0.25178891,  0.1172799 ,  0.51411217]])In [58]: b[a=='two',3]Out[58]: array([ 0.86013535])

    注意:1、通过布尔索引从原数组中选取的数据,将复制到新创建的数组中。2、布尔数组的长度要与原数组被索引的轴的长度相等。

    #布尔数组的长度大于数组第1轴的长度In [59]:  a = np.array(['one','two','three','four'])  #选取元素索引在数组对应轴范围内,发出警告In [60]: a!='four'Out[60]: array([ True,  True,  True, False], dtype=bool)In [61]: b[a!='four',:3]D:\Python27\Scripts\ipython:1: VisibleDeprecationWarning: boolean index did not match indexed array along dimension 0; dimension is 3 but corresponding boolean dimension is 4Out[62]:array([[ 0.23529625,  0.87521492,  0.1038766 ],       [ 0.25178891,  0.1172799 ,  0.51411217],       [ 0.75510171,  0.81136768,  0.12842083]])In [63]: a!='one'Out[63]: array([False,  True,  True,  True], dtype=bool)#选取元素索引不在数组对应轴范围内,发出警告并报错In [64]: b[a!='one',:3]D:\Python27\Scripts\ipython:1: VisibleDeprecationWarning: boolean index did not match indexed array along dimension 0; dimension is 3 but corresponding boolean dimension is 4---------------------------------------------------------------------------IndexError                                Traceback (most recent call last)<ipython-input-61-0bbfcbfce657> in <module>()----> 1 b[a!='one',:3]IndexError: index 3 is out of bounds for axis 0 with size 33

    花式索引(fancy indexing)
    使用整数数组进行索引。
    单个整数数组索引。

    In [66]: a = np.random.rand(4,3,2)In [67]: aOut[67]:array([[[ 0.16476724,  0.76267306],        [ 0.73596533,  0.79242585],        [ 0.56103429,  0.7122396 ]],       [[ 0.35827947,  0.10465505],        [ 0.5550632 ,  0.0872461 ],        [ 0.57150649,  0.07027542]],       [[ 0.61577706,  0.81542217],        [ 0.24874289,  0.15173563],        [ 0.96633552,  0.85607585]],       [[ 0.96521609,  0.41418405],        [ 0.67424316,  0.04368679],        [ 0.37650282,  0.96858812]]])In [69]: a[[1,3]]Out[69]:array([[[ 0.35827947,  0.10465505],        [ 0.5550632 ,  0.0872461 ],        [ 0.57150649,  0.07027542]],       [[ 0.96521609,  0.41418405],        [ 0.67424316,  0.04368679],        [ 0.37650282,  0.96858812]]])

    多个整数数组索引

    In [70]: a[[1,3],[0,1]]      #等价于选取元素a[1,0]和a[3,1]Out[70]:array([[ 0.35827947,  0.10465505],       [ 0.67424316,  0.04368679]])In [71]: a[[1,3],[0,1],[0,1]] #等价于选取元素a[1,0,0]和a[3,1,1]Out[71]: array([ 0.35827947,  0.04368679])       

    也可以使用元祖选取数组元素,与多个整数数组选取元素的方法没有差别

    In [77]: a[(1,3),(0,1),(0,1)]Out[77]: array([ 0.35827947,  0.04368679])

    注意:1、通过整数数组索引从原数组中选取的数据,将复制到新创建的数组中。2、每个轴对应的整数数组的长度必须相同。

    In [72]: a[[1,2],[1,2,3]]---------------------------------------------------------------------------IndexError                                Traceback (most recent call last)<ipython-input-72-7e69e200063a> in <module>()----> 1 a[[1,2],[1,2,3]]IndexError: shape mismatch: indexing arrays could not be broadcast together with shapes (2,) (3,)

    关于数组切片,NumPy也允许使用多个点代替完整切片
    比如:x是有可以5个轴的数组
    x[1,2,…]等价于x[1,2,:,:,:],
    x[…,3]等价于 x[:,:,:,:,3]
    x[4,…,5,:] 等价于x[4,:,:,5,:].

    想了解更多数组索引方法,参见NumPy的indexing模块

    输出和展开

    一维数组的输出和展开类似于List,多维数组的输出,都是相对于第一个轴进行输出。

    In [78]: aOut[78]:array([[[ 0.16476724,  0.76267306],        [ 0.73596533,  0.79242585],        [ 0.56103429,  0.7122396 ]],       [[ 0.35827947,  0.10465505],        [ 0.5550632 ,  0.0872461 ],        [ 0.57150649,  0.07027542]],       [[ 0.61577706,  0.81542217],        [ 0.24874289,  0.15173563],        [ 0.96633552,  0.85607585]],       [[ 0.96521609,  0.41418405],        [ 0.67424316,  0.04368679],        [ 0.37650282,  0.96858812]]]) In [80]: for row in a:   ....:     print row   ....:     print '====='   ....:[[ 0.16476724  0.76267306] [ 0.73596533  0.79242585] [ 0.56103429  0.7122396 ]]=====[[ 0.35827947  0.10465505] [ 0.5550632   0.0872461 ] [ 0.57150649  0.07027542]]=====[[ 0.61577706  0.81542217] [ 0.24874289  0.15173563] [ 0.96633552  0.85607585]]=====[[ 0.96521609  0.41418405] [ 0.67424316  0.04368679] [ 0.37650282  0.96858812]]=====

    也可以使用flat方法将数组元素单个输出,,flat生成矩阵或者数据的迭代器 ,输出当个元素

    In [81]: for element in a.flat:   ....:     print element   ....:0.1647672406730.7626730611640.7359653277460.7924258468260.5610342935450.7122396023630.3582794665660.1046550506650.5550631969680.08724609928860.5715064853790.07027541552230.6157770616560.8154221742990.248742893150.1517356345420.9663355157890.8560758525120.9652160900910.4141840523080.6742431634030.0436867922050.3765028231140.968588116022

    数组的展开一般使用方法flatten,ravel,主要用于将矩阵或者数组降为1维,两者的主要区别是:flatten返回时是原来数组或者矩阵的副本,而ravel返回的是原数组或者矩阵的视图,两者共享内存,任何一个被改变,另外一个也会被改变。

    #使用flatten()方法展开数组In [88]: b = a.flatten()In [89]: bOut[89]:array([ 0.16476724,  0.76267306,  0.73596533,  0.79242585,  0.56103429,        0.7122396 ,  0.35827947,  0.10465505,  0.5550632 ,  0.0872461 ,        0.57150649,  0.07027542,  0.61577706,  0.81542217,  0.24874289,        0.15173563,  0.96633552,  0.85607585,  0.96521609,  0.41418405,        0.67424316,  0.04368679,  0.37650282,  0.96858812])In [90]: b[2]=10In [91]: bOut[91]:array([  0.16476724,   0.76267306,  10.        ,   0.79242585,         0.56103429,   0.7122396 ,   0.35827947,   0.10465505,         0.5550632 ,   0.0872461 ,   0.57150649,   0.07027542,         0.61577706,   0.81542217,   0.24874289,   0.15173563,         0.96633552,   0.85607585,   0.96521609,   0.41418405,         0.67424316,   0.04368679,   0.37650282,   0.96858812])In [92]: aOut[92]:array([[[ 0.16476724,  0.76267306],        [ 0.73596533,  0.79242585],        [ 0.56103429,  0.7122396 ]],       [[ 0.35827947,  0.10465505],        [ 0.5550632 ,  0.0872461 ],        [ 0.57150649,  0.07027542]],       [[ 0.61577706,  0.81542217],        [ 0.24874289,  0.15173563],        [ 0.96633552,  0.85607585]],       [[ 0.96521609,  0.41418405],        [ 0.67424316,  0.04368679],        [ 0.37650282,  0.96858812]]])#使用ravel()方法展开数组In [93]: b = a.ravel()In [94]: bOut[94]:array([ 0.16476724,  0.76267306,  0.73596533,  0.79242585,  0.56103429,        0.7122396 ,  0.35827947,  0.10465505,  0.5550632 ,  0.0872461 ,        0.57150649,  0.07027542,  0.61577706,  0.81542217,  0.24874289,        0.15173563,  0.96633552,  0.85607585,  0.96521609,  0.41418405,        0.67424316,  0.04368679,  0.37650282,  0.96858812])In [95]: b[2]=20In [96]: bOut[96]:array([  0.16476724,   0.76267306,  20.        ,   0.79242585,         0.56103429,   0.7122396 ,   0.35827947,   0.10465505,         0.5550632 ,   0.0872461 ,   0.57150649,   0.07027542,         0.61577706,   0.81542217,   0.24874289,   0.15173563,         0.96633552,   0.85607585,   0.96521609,   0.41418405,         0.67424316,   0.04368679,   0.37650282,   0.96858812])In [98]: aOut[98]:array([[[  0.16476724,   0.76267306],        [ 20.        ,   0.79242585],        [  0.56103429,   0.7122396 ]],       [[  0.35827947,   0.10465505],        [  0.5550632 ,   0.0872461 ],        [  0.57150649,   0.07027542]],       [[  0.61577706,   0.81542217],        [  0.24874289,   0.15173563],        [  0.96633552,   0.85607585]],       [[  0.96521609,   0.41418405],        [  0.67424316,   0.04368679],        [  0.37650282,   0.96858812]]])

    :文中所有的模块可以使用help(np.模块名字)的方式查看该模块的详细说明。使用dir(**)查看模块的内置函数,使用ipython的童鞋可以使用?(内省)的方式查看不同模块的详细使用方法

    reference

    1、https://docs.scipy.org/doc/numpy-dev/user/quickstart.html
    2、python for data analysis
    3、用Python做科学计算
    4、http://docs.scipy.org/doc/numpy/reference/
    5、http://cs231n.github.io/python-numpy-tutorial/#numpy-datatypes

    1 0