python科学计算之narray对象用法
写在前面
最近在系统的看一些python科学计算开源包的内容,虽然以前是知道一些的,但都属于零零碎碎的,希望这次能把常用的一些函数、注意项整理下。小白的一些废话,高手请略过^_^。文章中的函数仅仅是为了自己好理解,并没有按照官方文档上的函数声明形式记录。
numpy.narray
numpy.narray创建
numpy.narray的构造方式挺多的,这里就不一一说明,因为一般情况下,在进行科学计算时是通过给定的数据文件来读取的,而读取时使用的是pandas,具体可参考官方文档,或者参见这位大牛的文章。
numpy.narray.shape&numpy.narray.reshape
numpy.narray的形状可以用numpy.narray.shape属性来获取,它返回的是narray形状的tuple,反映了各个轴的长度。
na_a=np.array([1,2,3,4])#长度为4的一维数组 na_b=np.array([[1,2,3,4],[5,6,7,8]])#2行4列的二维数组 out: #printna_a [1234] #printna_b [[1234] [5678]] #printna_a.shape (4,) #printna_b.shape (2,4)
numpy.narray.shape相当于一个c++的public成员,不仅可以获取,还可以通过它改变narray的形状。当某一轴指定为-1时,该轴的长度将通过其他轴来计算。
na_b.shape=(4,2) na_a.shape=(2,-1) out: #printna_b [[12] [34] [56] [78]] #printna_a [[12] [34]]
需要注意的是:通过shape属性改变narray的形状时,并没对narray元素内存中的位置改变,只是改变了外观,仅仅是换了件马甲。
当然,如果你熟悉了使用函数,不想使用属性来改变形状时,可以通过narray.reshape(),注意的是该函数返回的结果和原narray共享内存空间,换句话说,一个narray对象的改变将导致另一个narray也发生相应的改变。
na_c=na_b.reshape((4,2)) na_c[0][0]=100 out: #printna_c [[12] [34] [56] [78]] #printna_c [[1002] [34] [56] [78]] #printna_b [[1002] [34] [56] [78]]
numpy.narray.dtype
narray元素的类型可以使用dtype属性来获取,当然也可以在构造narray对象时指定元素的类型,需要注意的是,在numpy中float是64位,而complex是128位的。这里的float和complex是python内置的数据类型,numpy也定义了自己的float等数据类型,而且更加的细化,比如float类型,numpy就有float16、float32、float64和float128.
af=np.array([1,2,3,4],dtype=float) ac=np.array([5,6,7,8],dtype=complex) af.dtype ac.dtype dtype('float64') dtype('complex128')
python的完整数据类型中有大部分是所占字节来细化的,完整的数据在typeDict中定义,可通过numpy.typeDict.values()来获取完整类型。numpy在多维数组上的计算很高效,但是在数值对象计算上却比python慢很多,所以在进行数值计算时应避免使用numpy。
numpy.narray.astype()类型转换
numpy.narray.astype()可以对narray对象中元素逐一进行类型转换。
a=np.array([1,2,3,4],dtype=np.float) a.dtype dtype('float64') b=a.astype(np.int32) b.dtype dtype('int32') c.dtype c=a.astype(np.complex) c.dtype dtype('complex128')
numpy.narray的自动生成
1.np.arange(start,end,step,dtype)指定开始值、终值和步长生成一个等差数列,生成的narray中不包括end值。
2.np.linspace(start,end,element_nums,endpoint,dtype)指定开始值、终值和元素个数生成一个等差数列,通过endpoint指定包不包括end,默认为True。
3.np.logspace(start,end,element_nums,base,endpoint,dtype)endpoint默认为True,base默认为10,该函数产生一个等比数列,元素为
4.np.zeros(dim,dtype)对维度为dim的narray对象初始化为0,数据类型为dtype
5.np.ones(dim,dtype)对维度为dim的narray对象初始化为1,数据类型为dtype
6.np.empty(dim,dtype)该函数相当于对narray对象分配内存空间,但不进行初始化,所以切不可认为产生的元素为0。
7.np.full(dim,val,dtype)产生维度为dim的narray对象并且全部初始为val,前面的zeros()和ones()可看作该函数的特殊形式。
8.上面函数的like版本,即np.zeros_like(object)、np.ones_like(object)、np.empty_like(object)、np.full_like(object),这里的object是narray对象,这些函数产生的narray对象和上面一样,但narray的维度(shape)以及数据类型(dtype)是和传入的参数一样的,例如np.zeros_like(object)==np.zeros(object.shape,object.dtype)。
9.fromstring(s,dtype)这个函数是比较又意思的,将字符串转换为一个narray对象,我们先看看这个函数输出情况。
s="abcdefgh" np.fromstring(s) array([8.54088322e+194])##这是什么鬼? ###输出一下dtype呢? dtype('float64')
显然,这里是按照float64类型存放的,那如果换一个数据类型呢?
np.fromstring(s,dtype=np.int8) array([97,98,99,100,101,102,103,104],dtype=int8)
这个学过c语言的都应该知道是ASCII编码,也就可以看出,在python中一个字符是占8位,即一个字节的,继续看:
np.fromstring(s,dtype=np.int16) array([25185,25699,26213,26727],dtype=int16)
这里改变数据类型位2个字节,那么应该是两个字符联立一起表示一个int16,25185=98*256+97,高位存放在低字节中,这是小端模式。OK,那如果我现在要存放的是[‘a','b'…'h']这样的narray对象呢?数据类型是什么?应该是‘|s1'
np.fromstring(s,'|S1') array(['a','b','c','d','e','f','g','h'], dtype='|S1')
frombuffer()也可以创建的narray对象,但此时创建的narray对象和原字符串是内存共享的,学过c++的都知道,string类型是只读类型,无法修改,所以在frombuffer()创建的narray无法做修改,如果要修改,请用fromstring()。
.fromfunction(fun,dim)通过自定义函数接口来创建narray对象,fun是一个函数名(看作指针),dim是一个创建对象的维度。
deffun(i): returni%4+1 np.fromfunction(fun,(10,)) array([1.,2.,3.,4.,1.,2.,3.,4.,1.,2.])
可见利用fromfunction()创建narray时,参数i是从0开始自增的,自增的次数是维度的大小给定的,上面给定的维度位(10,),是一个一维数组,i从0自增到9(共10次)。看另外一个例子:
deffun2(i,j): return(i+1)*(j+1) np.fromfunction(fun2,(9,9)) 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.]])
行可以看作j的自增,列可以看作i的自增,所以可以看作是两个for循环。
numpy.narray的元素存取
可以按照python中list存取元素的方式。
a=np.arange(10)#array([0,1,2,3,4,5,6,7,8,9]) a[5]#5 a[3:5]#[3,4] a[:5]#[0,1,2,3,4] a[:-1]#[0,1,2,3,4,5,6,7,8] ###也可以指定步长,通过第三个数指定 a[1:-1:2]#从开始到结束,没隔两个数取一次array([1,3,5,7]) a[5:1:-2]#反向取array([5,3])
注意,通过这种方式取的新narray和原始narray内存共享,所以任何一个改变,另一个也将改变。除此之外,numpy还提供了一下几个存取方式:使用list存取,list的每个元素作为下标,这种方式得到的新narray和原始narray不共享内存。
a=np.arange(10) a[[1,1,7,7]]#array([1,1,7,7])
使用narray提取新数组,narray的元素作为下标,得到的新narray维度和参数narray维度相同。这个有点绕,看个例子吧:
a[np.array([2,1,3,6])]#array([2,1,3,6]) a[np.array([[2,1,3,6],[7,4,6,1]])] ## ##array([[2,1,3,6], [7,4,6,1]])
使用bool数组提取,提取bool数组中为True的下标元素:
a[np.array([True,False,True,False,False,False,True,False,False,False])] ##array([0,2,6]) a[np.array([True,False,True,False,False,False,True,False,False,False])]=-1,-2,-3 printa#array([-1,1,-2,3,4,5,-3,7,8,9])
多维数组
请先看一张图:
左边是用切片方式提取右边6*6的narray对象元素。这种提取元素方式和原narray对象内存共享。
这里个人的理解,利用切片方式提取的新narray和原narray是内存共享的,而使用列表、bool数组等方式则不共享,原因很简单,利用切片方式,例如a[3:5],是从第三个元素到第5个元素(不包括),那么是用元素所占字节来移动的,就像c中的指针,这样比较便利。而其他方式是用下标,这些下标往往不连续,如果用指针方式的话则要来回移动,比较麻烦。所以不提供内存共享这种方式。
在这之前我们使用切片都是通过在[]中指定起点、终点以及步长,如果要单独创建切片对象呢?使用slice对象,创建的方式很简单,把[]中的:替换为None。
a=np.arange(0,60,10).reshape(-1,1)+np.arange(6) ###广播,后面会说到 array([[0,1,2,3,4,5], [10,11,12,13,14,15], [20,21,22,23,24,25], [30,31,32,33,34,35], [40,41,42,43,44,45], [50,51,52,53,54,55]]) a[::2,2:] ## array([[2,3,4,5], [22,23,24,25], [42,43,44,45]]) idx=slice(None,None,2),slice(2,None) a[idx] ## array([[2,3,4,5], [22,23,24,25], [42,43,44,45]])
同时,numpy提供了IndexExpression类的对象s_来方便slice的创建。
np.s_[::2,2:] ## (slice(None,None,2),slice(2,None,None))
结构体数组
numpy提供了和c类似的结构体数组,并且相互之间能够读取,以一个例子来说明:
##创建persontype类型 persontype=np.dtype({ 'names':['name','age','weight'], 'formats':['S30','i','f']},align=True) ##创建结构体数组 a=np.array([("zhang",20,55.5),("wang",24,65.2)],dtype=persontype)
persontype有两个key,names和formats,names是以字典的方式标明结构体所含的字段,formats是对相应字段的数据类型。S30表示长度不超过30个字节的字符串,i相当于np.int32,f相当于np.float32,下面创建结构体数组的时候指定数据类型是我们创建的persontype。
##printa array([('zhang',20,55.5),('wang',24,65.19999695)], dtype={'names':['name','age','weight'],'formats':['S30','通过tostring()和tofile()可以将结构体数组写入文件,并可以通过c读取,由于c中的结构体存在对齐,所以在python创建结构体数组时也需要使用相应的对齐方式,这一点通过align来指定,True为对齐,False不对齐。
narray内存结构
以二维narray对象为例,我们来看看narray对象在内存中的结构。
a=np.array([[0,1,2],[3,4,5],[6,7,8]],dtype=np.float32)该二维数组的结构如下图:
左边时一个结构体,描述了该narray对象的基本信息,包括数据类型(np.float32)、维度(轴的数量)、每个轴的数据个数、每个轴相邻元素的字节差、最后是存放数据的内存地址。通过切片方式得到的新narray就是在data字段表示的内存上获得原始narray的视图,我们来看看:
b=a[::2,::2] ##b array([[0.,2.], [6.,8.]],dtype=float32) ##b.strides (24,8)获得的新narray.strides发生了变化,而这个变化也刚好是每个轴相邻元素跨越的字节数。narray的数据在内存上的排列有两种形式,分别是C和FORTRAN格式,上面我们展示的就是C的格式,第0轴是最上位的,也就是说,第0轴作为行,所以第0轴的相邻元素跨越的字节数是最多的(比如这里为3*4=12),而FORTRAN结构与C格式相反,它是第1轴跨越的字节数最多。numpy默认是C格式,如果想改成FORTRAN的格式,只需要在创建narray的时候设置order=‘F'。narray的flags属性描述了存储区的一些属性:
##a.flags C_CONTIGUOUS:True#C语言格式 F_CONTIGUOUS:False#Fortran语言格式 OWNDATA:True#数组是否拥有该存储区,如果是一个narray的视图则不拥有 WRITEABLE:True#是否可写(改变其中数据) ALIGNED:True#对齐 UPDATEIFCOPY:FalseOK,这里引出一个东东,如果要将a进行转置,我们是需要将需要将a顺时针旋转90°,那么还有上面简单的方法?我们先看看a.T.flags:
##a.T.flags C_CONTIGUOUS:False F_CONTIGUOUS:True OWNDATA:False WRITEABLE:True ALIGNED:True UPDATEIFCOPY:False从这上面可以看到,对于a的转置,numpy是将其内存格式改变了,从C语言格式变成了Fortran的格式,并且转置是a的一个视图。这样的方式比旋转方式更加快速。
以上这篇python科学计算之narray对象用法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。