<!DOCTYPE html>
numpy提供了两种基本的对象,ndarray,ufunc
html
Numpy中全部的函数都是围绕ndarray对象进行的
python
import numpy as np
a=np.array([1,2,3,4]) #列表作参数
b=np.array((5,6,7,8)) #元祖作参数
c=np.array([[1,2,3,4],[5,6,7,8],[7,8,9,10]])
想知道数组的形状能够用 shape属性(不是函数)得到,他是一个描述数组各轴的长度的元祖(tuple) git
a.shape #输出(4,)一个元素,一维数组
b.shape #输出(4,)
c.shape #输出(3,4)两个元素,二维数组 0轴3,一轴4
能够经过修改数组的shape属性,在保持数组元素个数不变的状况下,改变数组每一个轴的长度,只是改变轴长,数组元素在内存中的位置不变 c.shape=(4,3) 数组将改变轴长 当设置某个轴的元素个数为-1时,将自动计算此轴的长度。
c.shape(2,-1) c的shape属性将变为(2,6)
使用reshape()方法,能够建立指定的形状的新数组,而原数组形状不变, d=a.reshape((2,2)) #也能够用a.reshape(2,2) d#输出[[1,2],[3,4]]
数组a和d共享数据存储空间,所以修改任意元素,另外一个数组也会被修改
2. 元素类型
数组的元素类型能够经过dtype属性获取,类型有int32,float64,complex128,当须要指定dtype参数时,可使用字符串,全部的元素类型关系都存储在typeDict字典中。获取与float64类型对应的全部键值
列表推导 github
[key for key,value in np.typeDict.items() if value is np.float64]
set(np.typeDict.values())获取全部typeDict值并去重,这种方式获取的属性与dtype是不一样的对象,经过dtype对象的type属性能够找到与其对应的数值
c.dtype.type #输出numpy.int32
经过numpy也能够建立数值对象,但运算比python数值对象运算慢。
使用astype()方法能够对数组的元素类型进行转换, web
t1=np.array([1,2,3,4],dtype=np.float)
t2=np.array([1,2,3,4],dtype=np.complex)
t3=t1.astype(np.init32)
t4=t2.astype(np.complex64)
自动生成数组
前面例子都是先建立一个序列对象,而后经过array转化为数组,显然效率不高。所以Numpy提供了许多专门的建立数组的函数 canvas
logspace()为等比数列,下面产生从10^0 到10^二、有5个元素的等比数列,注意起始值0表示10^0,而终值2表示10^2:
np.logspace(0,2,5)
array([ 1. , 3.16227766, 10. , 31.6227766 , 100. ])
基数能够经过base参数指定,其默认值为10,下面将base参数设置为2,并设置endpoint参数为False,建立一个比例为2^1/12的等比数组。
np.logspace(0,1,12,base=2,endpoint=False) array([ 1. , 1.05946309, 1.12246205, 1.18920712, 1.25992105, 1.33483985, 1.41421356, 1.49830708, 1.58740105, 1.68179283, 1.78179744, 1.88774863]) 数组
empyt(),zeros(),ones()能够建立指定形状和类型的数组,empyt初始化元素为0,zeros初始化元素为0,ones初始化元素为1
np.empty((2,3),np.int) array([[0, 0, 0], [0, 0, 0]]) np.ones(3,np.int) array([1, 1, 1]) np.zeros(2,np.int) array([0, 0])ruby
fromfunction,先定义一个从下标计算数值的函数,而后用fromfunction()经过此函数建立数组,下标从0,1,2,3,4...依次计算,下标从第二个参数规定的轴开始计算
def func(i): return i%4+1 np.fromfunction(func,(10,)) array([ 1., 2., 3., 4., 1., 2., 3., 4., 1., 2.]) markdown
def func2(x,y): return (x+1)*(y+1)
np.fromfunction(func2,(2,3)),传进去的参数依次为[(0,0),(0,1),(0,2)],[(1,0),(1,1),(1,2)]
array([[ 1., 2., 3.], [ 2., 4., 6.]])
存取元素有两种,一种和列表相同的方式,另外一种使用列表或者数组下标的方式,
可使用和列表相同的方式对数组元素进行存取 获取的元素和原数组共享内存
a=np.arange(10) a[5]:用整数做为下标能够获取数组中的某个元素
a[3:5] 用切片做为下标获取数组的一部分,包括a[3]但不包括a[5]包头不包尾
a[:5] 切片中省略开始下标,表示从a[0]开始
a[:-1] 下标可使用负数,表示从数组最后往前数
a[1:-1:2] 切片中的第三个参数表示步长,2表示隔一个去一个元素
a[::-1] 省略切片的开始下标和结束下标,步长为-1,整个数组颠倒过来
a[5:1:-2] 步长为负数是,开始下标必须大于结束下标
下标能够用来修改元素
a[2:4]=100,101
除了使用切片,还提供了整数列表、整数数组和布尔数组等几种高级下标存取方法,在numpy10.1之后,布尔列表和布尔数组取得结果相同不共享内存
多维数组
多维数组的存取和一维数组相似,由于多维数组有多个轴,因此它的下标须要用多个值来表示。Numpy采用元祖做为数组的下标,元祖中的每隔元素和数组的每一个轴对应。
a=np.arange(0,60,10).reshape(-1,1)+np.arange(0,6)
a[0,3:5] #3,4 a[4:,4:] #44,45,54,55 a[:,2] #2,12,22,32,42,52 a{2::2,::2] #20,22,24,40,42,44 下标元祖与原数组共享数据
在多维数组的下标元祖中,也可使用整数元祖或列表、整数数组和布尔数组,当下标中使用这些对象时,得到的数据是元数据的副本,更改不会改变元数据
a[(0,1,2,3),(1,2,3,4)] #获取(0,1),(1,2),(2,3),(3,4)
a[3:,[0,2,5]] #获取(3,0)(3,2)(3,5)(4,0)(4,2)(4,5)(5,0)(5,2)(5,5)
mask=np.array([1,0,1,0,0,1],dtype=np.bool) a[mask,2] #获取(0,2),(2,2)(5,2)
结构数组
假设咱们须要定义一个结构数组,他的每一个元素都有name,age和weight字段。在numpy中能够这样定义 persiontype=np.dtype({'names':['name','age','weight'],'formats':['S30','i','f']},align=True)
a=np.array([('wang',32,75.5),('zhang',24,65.2)],dtype=persiontype)
array([(b'wang', 32, 75.5 ), (b'zhang', 24, 65.19999695)], dtype={'names':['name','age','weight'], 'formats':['S30','<i4','<f4'], 'offsets':[0,32,36], 'itemsize':40, 'aligned':True})
dtype({'names':['name','age','weight'], 'formats':['S30','<i4','<f4'], 'offsets':[0,32,36], 'itemsize':40}, align=True)
a[0] (b'wang', 32, 75.5)
a[0]['name'] b'wang' a[0]是结构元素,他和数组a共享内存数据
咱们不但能够得到结构元素的某个字段,并且能够直接得到结构数组的字段,返回的是原始数组的视图,所以能够经过改变b[0]来改变a[0]['age'] b=a['name']
b[0] b'wang' b[1] b'zhang'
经过a.tostring()或a.tofile()方法,能够将数组a以二进制的方式转换城字符串或写入文件
结构类型中能够包含其余结构类型
np.dtype(['f1',[('f22',np.int16)])]) 当某个字段类型为数组是,用元祖的第三个元素表示其形状
np.dtype([('f0','i4'),('f1','f8',(2,3))]) 字典的键为结构的字段名,值为字段的类型描述,可是因为字典的键是没有顺序的,所以字段的顺序须要在类型描述中给出。类型描述是一个元祖,它的第二个值给出的字段以字节为单位的偏移量,偏移量用于避开第一个字段的长度
np.dtype({'sunname':('S25',0),'age':(np.uint8,25)})
内存结构
好东西,重要属性,strides步长,指内存里的数据相隔的字节数
a=np.array([[1,2,3,4],[5,6,7,8]])
a.strides (16, 4)#首先这个元祖里的元素的下标对应的是多维数组中的维数,此结果表示的是第0轴和第1轴,这是一个2维数组,由于数组内存连续,元素类型为int32,因此1与2之间间隔四个字节,1,2,3,4这四个元素共用16字节,因此1与5相聚16字节
元素在数据存储区中的排列格式有两种:C语言格式和Fortran语言格式。在C语言中第0轴中元素相隔最远,第1轴相隔最近,而F中相反 C的存储方式是Z型,F是倒着的N型
a.flags CCONTIGUOUS : True FCONTIGUOUS : False OWNDATA : True WRITEABLE : True ALIGNED : True UPDATEIFCOPY : False
a.T.flags CCONTIGUOUS : False FCONTIGUOUS : True OWNDATA : False WRITEABLE : True ALIGNED : True UPDATEIFCOPY : False
当时用view()方法从同一块数据区建立不一样的dtype的数组对象,也就是使用不一样的数值类型查看同一段内存中的二进制数据
g=e.view(np.uint8) g array([0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0], dtype=uint8) e array([0, 1, 2, 3, 4, 5]) h=e.view(np.uint32)h array([0, 1, 2, 3, 4, 5], dtype=uint32)
有趣实验
from numpy.lib.stridetricks import asstrided i=np.arange(6) j=as_strided(i,shape=(4,3),strides=(4,4)) j array([[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5]]) i array([0, 1, 2, 3, 4, 5])
strides规定了如何取数据,shape规定了数组形状,好比j第(0,0)位取0,那么根据strides,第0轴和第一轴间隔字节数按4来查找,第(0,1)位就应该是1,由于1与0相隔4个字节,这里的数据是部分重复的,修改一个其余的也被修改。
ufunc (universal function(通用函数)),许多ufunc都是用C语言实现的,所以它们计算速度很是快。
np.sin() 比 math.sin()快10倍
经过下标运算获取的数组元素类型位NumPy中定义的类型,将其转换为python的标准类型还须要花费额外的时间。为了解决这个问题,数组提供了item()方法,它用来获取数组中的单个元素,而且直接返回标准的 python数值类型
1. 四则运算
1. 加法(使用+号或者使用np.add()方法)
>>> np.add(a,b)
array([[ 0., 3., 6.],
[ 9., 12., 15.]])
>>> a+b
array([[ 0., 3., 6.],
[ 9., 12., 15.]])
>>> b
array([[ 0., 2., 4.],
[ 6., 8., 10.]])
>>> a
array([[0, 1, 2],
[3, 4, 5]])
使用add方法,能够指定第三个参数out,则不产生新的数组,而直接将结果保存进指定的数组
np.add(a,b,b) 等效于 a=a+b
array([[ 0., 3., 6.],
[ 9., 12., 15.]])
2. 其余运算
>>> x1=np.array([1,2,3,4,5])
>>> x2=np.array([2,3,4,5,6])
>>> y=x1*x2(y=multiply(x1,x2))
>>> y
array([ 2, 6, 12, 20, 30])
>>> y=x1-x2 (y=subtract(x1,x2))
>>> y
array([-1, -1, -1, -1, -1])
>>> y=x1/x2 (y=divide(x1,x2))
>>> y
array([ 0.5 , 0.66666667, 0.75 , 0.8 , 0.83333333])
>>> y=x1//x2 (y=floor_divide(x1,x2),老是对返回值取整)
>>> y
array([0, 0, 0, 0, 0], dtype=int32)
>>> y=-x1 (y=negative(x))
>>> y
array([-1, -2, -3, -4, -5])
>>> y=x1**x2 (power(x1,x2))
>>> y
array([ 1, 8, 81, 1024, 15625], dtype=int32)
>>> y=x1%x2 (mod(x1,x2),remainder(x1,x2))
>>> y
array([1, 2, 3, 4, 5], dtype=int3
数组运算支持操做符,简化了编写,当算式复杂时,避免中间值
a*b+c算式写成
x=a*b
x+=c
np.array([1,2,3])<np.array([3,2,1])
array([ True, False, False], dtype=bool)
y=x1==x2 y=equal(x1,x2)
y=x1!=x2 y=not_equal(x1,x2)
y=x1<x2 y=less(x1,x2)
y=x1<=x2 y=less_equal(x1,x2)
y=x1>x2 y=geater(x1,x2)
y=x1>=x2 y=greater_equal(x1,x2)
布尔运算在ufunc函数中,函数名以logical开头,
np.logicaland np.logicalnot np.logicalor np.logicalxor
例子
a=np.arange(5) b=np.arange(4,-1,-1) np.logicalor(a==b,a>b)
数组的any()和all()方法
只有数组中有一个元素为True,any()方法就返回True
只有全部元素的为True,all()才返回True
以bitwise开头的为位运算函数,包括bitwiseand、bitwise_not、bitwiseor、bitwisexor,也可使用&,~,|,^操做符进行运算,位运算结果与布尔运算结果相同
(a==b)|(a>b) 由于位运算符比比较运算符优先级高,因此须要加括号提高优先级
自定义ufun函数
能够用frompyfunc()函数将计算单个元素的函数转换成数组ufunc函数,这样就能够用所产生的ufunc函数对数组进行计算
举例,计算三角波,三个阶段,上坡,下坡,平坦
def trianglewave(x,c,c0,hc): x=x-int(x) #三角波的周期为1
if x>=c: r=0.0
elif x<c0: x=x/c0hc
else: r=(c-x)/(c-c0)hc
return r
先使用列表推导计算出一个列表,而后用array()将列表转换为数组。每次使用列表推导调用 函数,多维数组应用很麻烦 x=np.linspace(0,2,1000) y1=np.array([trianglewave(t,0.6,0.4,1.0) for t in x])
经过frompyfunc()能够将计算单个值的函数转换位能对数组的每一个元素进行计算的ufunc函数。frompyfunc()的调用能格式
frompyfunc(func,func须要输入参数个数,func返回参数个数) triangleufunc1=np.frompyfunc(trianglewave,4,1)
y2=triangle_ufunc1(x,0.6,0.4,1.0)
triangleufunc1()返回的数组的元素类型为object,所以还须要调用数组astype()方法,以将其转换为双精度浮点数组: y2.dtype #dtype('O') y2.astype(np.float).dtype #dtype('float64')
使用vectorize()也能够实现和frompyfunc()相似的功能,但它能够经过otypes参数指定返回数组的元素类型。otypes参数能够是一个表示元素类型的字符串,也能够是一个类型列表,使用列表能够描述多个返回数组的元素类型
triangleufunc2 = np.vectorize(trianglewave,otypes=[np.float])
y3=triangleufunc2(x,0.6,0.4,1.0)
验证咱们的结果
np.all(y1==y2) # True
np.all(y2==y3) # True
广播
当时用ufunc函数对两个数组进行计算时,ufunc函数会对两个数组的对应的元素进行计算,所以要求两个数组形状相同,,若是不一样,会调用广播来处理
a=np.arange(0,60,10).reshape(-1,1) b=np.arange(0,5) c=a+b
x,y=np.ogrid[-2:2:20j,-2:2:20j] z=xnp.exp(-x2-y*2) 在x前加负号不知道为啥,exp计算各元素指数ex; z array([[-0.00067093, -0.00148987, -0.00302777, -0.00563122, -0.00958484, -0.01493034, -0.02128422, -0.02776827, -0.03315453, -0.03622763, -0.03622763, -0.03315453, -0.02776827, -0.02128422, -0.01493034, -0.00958484, -0.00563122, -0.00302777, -0.00148987, -0.00067093], ... [ 0.00067093, 0.00148987, 0.00302777, 0.00563122, 0.00958484, 0.01493034, 0.02128422, 0.02776827, 0.03315453, 0.03622763, 0.03622763, 0.03315453, 0.02776827, 0.02128422, 0.01493034, 0.00958484, 0.00563122, 0.00302777, 0.00148987, 0.00067093]])
z.shape (20, 20) z.dtype dtype('float64') 为了利用广播功能,常常须要调整数组的形状,所以数组支持特殊的下标对象None,它表示在None对应的位置建立一个长度为1的新轴如:a[None,:]和a.reshape(1,-1)等效,而a[:None]和a.reshape(-1,1)等效
还可使用ix()函数将两个一维数组转换成可广播的二维数组
x=np.array([0,1,4,10]) >>> y=np.array([2,3,8]) >>> gy,gx=np.ix(y,x) >>> gy array([[2], [3], [8]]) >>> gx array([[ 0, 1, 4, 10]]) >>> gz=gy+gx >>> gz array([[ 2, 3, 6, 12], [ 3, 4, 7, 13], [ 8, 9, 12, 18]]) 经过ix()函数将数组x和y转换成能进行广播运算的二维数组。数组y对应结果0轴,x对应1轴。ix()的参数能够时N个一维数组,将这些数组转换成N维空间中可广播的N维数组
5. ufunc方法
ufunc对象自己还有一些方法函数,这些方法只对两个输入,一个输出的ufunc函数有效,其余的ufunc对象调用这些方法会抛出异常 reduce()方法它沿着axis参数指定的轴对数组进行操做,至关于将运算符沿axis轴插入到全部元素中间
r1=np.add.reduce([1,2,3]) #1+2+3 6
r2=np.add.reduce([[1,2,3],[4,5,6]],axis=1) #(1+2+3),(4+5+6)
[6,15]
accumulate()方法和reduce()相似,只是它返回的数组和输入数组的形状相同,保存因此的中间计算结果
a1=np.add.accumulate([1,2,3]) #a1 [1,3,6]
a2=np.add.accumulate([[1,2,3],[4,5,6]],axis=1)# a2 [[1,3,6],[4,9,15]]
reduceat()方法计算多组reduce()结果,经过indices参数指定一系列的起始和终止位置
a=np.array([1,2,3,4])
result=np.add.reduceat(a,indices=[0,1,0,2,0,3,0])
result # array([1,2,3,3,6,4,10])
对于indices参数中的每一个元素都会计算出一个值,由于最红的计算结果和indices参数的长度相同。结果数组result中除最后一个元素以外。
if indices[i]<indices[i+1]
result[i]=<op>.reduce(a[indices[i]:indices[i+1]])
else:
result[i]=a[indices[i]]
而最后一个元素以下计算
1:a[0] ->1
2:a[1] ->2
3:a[0]+a[1] -> 1+2
3:a[2] ->3
6:a[0]+a[1]+a[2] -> 1+2+3=6
4:a[3] ->4
10: a[0] + a[1] +a[2]+a[3] -> 1+2+3+4=10
ufunc函数对象的outer()方法 np.multiply.outer([1,2,3,4,5],[2,3,4])
至关于 a.shape+=(1,)*b.ndim ,
2 3 4 1 2 3 4 2 4 6 8 3 6 9 12 4 8 12 16 5 10 15 20
首先,多维数组的下标应该是一个长度和数组的维度相同的元祖。若是下标元组的长度比数组的维数大,就会出错。若是小,就会在下标元组后面补":",使它的长度与数组维数相同
若是下标对象不是元组,则numpy会首先把他转换为元组。 通过各类转换和添加“:”以后获得一个标准的下标元组。它的各个元素有以下几种类型:切片、整数、整数数组和布尔数组。若是元素不是这些类型,如列表或元组,就将其转换成整数数组。若是下标元组的全部元素都是切片和整数,那么他是原数组的一个视图,共享内存。
2. 整数数组做为下标
下标元组中元素的切片和整数数组构成的状况。假设整数数组有Nt个,而切片有Ns个。Nt+Ns为数组的维数D 首先,这Nt个整数数组必须知足广播条件,假设它们进行广播以后的维数为M,形状为(d0,d1,...,dM-1)
若是Ns为0,即没有切片元素时,则下标所获得的结果数组result的形状和整数数组广播以后的形状相同。它的每一个元素值按照下面的公式得到: result[i0,i1,...,im-1]=X[ind0[i0,i1,...,iM-1]...,indNt-1[i0,i1,...,im-1]]
其中,ind0到indNt-1为进行广播以后的整数数组
当存在切片下标时,状况就变得更加复杂。下标元组中的整数数组之间没有下标,即整数数组只有一个或连续多个整数数组。这是结果数组的shape属性为,姜原始数组的shape属性中的整数数组所占据的部分替换为它们广播以后的shape属性。
当下标元组中的整数数组不连续时,结果数组的shape属性为整数数组广播以后的形状后面添加上切片元素所对应的形状
3. 一个复杂的例子
4. 布尔数组作下标
当时用布尔数组直接做为下标对象或者元组下标对象中有布尔数组时,都至关于nonzero()将布尔数组转换成一组整数数组,而后使用整数数组进行下标运算
b1=np.array([True,False,True,False])
np.nonzero(b1)
(array([0, 2], dtype=int64),)
a[np.nonzero(b2)] array([[ 0, 1, 2, 3, 4], [10, 11, 12, 13, 14], [20, 21, 22, 23, 24]])