Numpy快速处理数据
numpy提供了两种基本的对象,ndarray,ufunc
ndarray对象
Numpy中所有的函数都是围绕ndarray对象进行的
1. 创建
首先需要创建数组,通过给array()函数传递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)
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类型对应的所有键值
列表推导
[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()方法可以对数组的元素类型进行转换,
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提供了许多专门的创建数组的函数- arange()函数类似于内置函数range(),需要指定,开始值、终值和步长,生成结果不包括终值。
np.arange(0,2,0.1)
array([ 0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]) - linspace()为等差数列,可以通过指定endpoint参数指定是否包含终值,默认值为True,包含终值。
np.linspace(0,1,10)输出array([ 0. , 0.11111111, 0.22222222, 0.33333333, 0.44444444,0.55555556, 0.66666667, 0.77777778, 0.88888889, 1. ])np.linspace(0,1,10,endpoint=False)输出array([ 0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]) logspace()为等比数列,下面产生从10^0 到10^2、有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])- full()函数将数组元素初始化为指定值np.full(3,234)array([234, 234, 234])
- fromstring()方法可以将字符串转成整数数组
np.fromstring('abcdefgh',dtype=np.int8) array([ 97, 98, 99, 100, 101, 102, 103, 104], dtype=int8) -
fromfunction,先定义一个从下标计算数值的函数,然后用fromfunction()通过此函数创建数组,下标从0,1,2,3,4...依次计算,下标从第二个参数规定的轴开始计算
def func(i): return i%4+1np.fromfunction(func,(10,))array([ 1., 2., 3., 4., 1., 2., 3., 4., 1., 2.])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.]])
- arange()函数类似于内置函数range(),需要指定,开始值、终值和步长,生成结果不包括终值。
-
存取元素有两种,一种和列表相同的方式,另一种使用列表或者数组下标的方式,
-
可以使用和列表相同的方式对数组元素进行存取 获取的元素和原数组共享内存
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以后,布尔列表和布尔数组取得结果相同不共享内存
- 当使用整数列表对数组元素进行存取时,,将使用列表中的每个元素作为下标。不共享内存x=np.arange(10,1,-1) array([10, 9, 8, 7, 6, 5, 4, 3, 2])x[[3,3,1,8]] 结果取出下标为3318的四个元素 [7,7,9,2]x[[3,3,-3,8]] 结果取出下标为33-38的四个元素 [7,7,4,2]
整数序列下标也可以用来修改元素的值
x[[3,5,1]]=-1,-2,-3 - 当使用整数数组作为数组下标时,将得到一个形状和下标数组相同的新数组,新数组的每隔元素都是用下标中对应的值作为下标从原数组获得的值,当数组下标为一维数组时,结果和列表作为下标的结果相同
x=np.arange(10,1,-1)x[np.array([3,3,1,8]) [7,7,9,2]x[np.array([[3,3,1,8],[3,3,-3,8]])]array([[7,7,9,2],[7,7,4,2]])
可以这样理解:下将下标数组展平为一维数组,并作为下标获得一个新的一维数组,然后将其形状修改为下标数组的形状:
x[[3,3,1,8,3,3,-3,8]].reshape(2,4) - 当时用布尔数组,布尔数组得长度必须和数组得长度相同
x=np.arange(5,0,-1)x array([5,4,3,2,1])x[np.array([True,False,True,False,False])] array([5,3])
x=np.random.randint(0,10,6)#产生一个长度为6,元素值为0到9的随机数数组array([6, 2, 5, 8, 2, 6])x[x>5]array([6, 8, 6])
- 当使用整数列表对数组元素进行存取时,,将使用列表中的每个元素作为下标。不共享内存x=np.arange(10,1,-1) array([10, 9, 8, 7, 6, 5, 4, 3, 2])x[[3,3,1,8]] 结果取出下标为3318的四个元素 [7,7,9,2]x[[3,3,-3,8]] 结果取出下标为33-38的四个元素 [7,7,4,2]
-
-
多维数组
多维数组的存取和一维数组类似,因为多维数组有多个轴,所以它的下标需要用多个值来表示。Numpy采用元祖作为数组的下标,元祖中的每隔元素和数组的每个轴对应。
a=np.arange(0,60,10).reshape(-1,1)+np.arange(0,6)
a[0,3:5] #3,4a[4:,4:] #44,45,54,55a[:,2] #2,12,22,32,42,52a{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型- 当下标使用整数和切片时,所取得数据时等间分布的,只需要修改数据结构中的,dim count(维度),dimensions(维度上的元素个数),stride(个维度上元素相差的字节数)等属性以及指向数据的存储区域的指针data,就实现切片,所以新数组和原数组共享内存
- 当时用整数序列,整数数组和布尔数组时,不能保证数据时在数据存储区域是等间隔的,因此无法和原始数组共享数据,只能对数据进行复制。
数组的flags属性
CCONTIGUOUS:是否使用C语言的格式FCONTIGUOUS:是否使用F的格式
OWNDATA:数组是否拥有数据存储区域(True),视图(False)
数组的转置使用T属性
a.flagsCCONTIGUOUS : TrueFCONTIGUOUS : FalseOWNDATA : TrueWRITEABLE : TrueALIGNED : TrueUPDATEIFCOPY : False
a.T.flagsCCONTIGUOUS : FalseFCONTIGUOUS : TrueOWNDATA : FalseWRITEABLE : TrueALIGNED : TrueUPDATEIFCOPY : False
当时用view()方法从同一块数据区创建不同的dtype的数组对象,也就是使用不同的数值类型查看同一段内存中的二进制数据
g=e.view(np.uint8)garray([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)earray([0, 1, 2, 3, 4, 5])h=e.view(np.uint32)harray([0, 1, 2, 3, 4, 5], dtype=uint32)
有趣实验
from numpy.lib.stridetricks import asstridedi=np.arange(6)j=as_strided(i,shape=(4,3),strides=(4,4))jarray([[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5]])iarray([0, 1, 2, 3, 4, 5])
strides规定了如何取数据,shape规定了数组形状,比如j第(0,0)位取0,那么根据strides,第0轴和第一轴间隔字节数按4来查找,第(0,1)位就应该是1,因为1与0相隔4个字节,这里的数据是部分重复的,修改一个其他的也被修改。
ufunc函数
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函数会对两个数组的对应的元素进行计算,因此要求两个数组形状相同,,如果不同,会调用广播来处理- 让所有的数组向其中维数最多的看其,shape属性中不足的部分加1补齐
- 输出数组的shape属性,是输入数组的shape属性的各个轴上的最大值
- 如果输入数组的某个轴的长度为1或与输出数组的对应轴的长度相同,这个数组能够用来计算,否则出错
- 当输入数组的某个轴的长度为1时,沿着此轴运算时都用此轴的第一组值
a=np.arange(0,60,10).reshape(-1,1)b=np.arange(0,5)c=a+b
- 需要b的shape属性向a看齐,
b.shape=1,5 - 输出数组的各个轴的长度为输入数组各个轴的长度的最大值,输出数组的shape(6,5),由于b的第0轴的长度为1,而a的第0轴的长度为6, 为了让它们在第0轴上能够向加,需要将b的第0轴的长度扩展为6
b=b.repeat(6,axis=0)#这里的repeat()方法表示沿着axis参数指定的轴复制数组中的各个元素的值。
a=a.repeat(5,axis=1) - 经过处理后,a和b就可以进行加法运算了。当然numpy内部不会真正的用repeat进行扩展,这样浪费内存。
因为广播常用,所以numpyt提供ogrid对象,用于创建广播运算用的数组
x,y=np.ogrid[:5,:5]
还提供了mgrid对象,返回的时进行广播之后的数组 x,y=np.mgrid[:5,:5]
ogrid和多维数组一样,用切片元祖作为下标,返回的是一组可以用来广播计算的数组。其切片下标有两种方式 - 开始值:结束值:步长 和np.arange()类似
- 开始值:结束值:长度j,当第三个参数为虚数时,它表示所返回的数组的长度,和np.linspace()类似包括结束值
x,y=np.ogrid[:1:4j,:1:3j]
x为0到1的4个元素的等差数列
y为0到1的3个元素的等差数列
利用ogrid的返回值,我们很容易计算二元函数在等间距网络上的值,下面时绘制三维曲面f(x,y)=xe^(x2-y2)
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.dtypedtype('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 ,
多维数组的下标存取
首先,多维数组的下标应该是一个长度和数组的维度相同的元祖。如果下标元组的长度比数组的维数大,就会出错。如果小,就会在下标元组后面补":",使它的长度与数组维数相同
如果下标对象不是元组,则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]])
庞大的函数库
- 随机数from numpy import random as nr
使用numpy.set_printoptions(precision=2)可以指定小数点后保留两位- rand 0到1之间的随机浮点数,它的所有参数用于指定所产生的数组的形状
r1=nr.rand(4,3) - randn()产生标准动态分布的随机数,参数也是产生数组的形状 r2=nr.randn(4,3)
- randint()产生指定范围的随机整数,包括起始值,但不包括终值r3=nr.randint(0,10,(4,3))random模块提供了许多产生符合特点定随机分布的随机数的函数
- normal():正态分布,前两个参数分别为期望值和标准差
r1=nr.normal(100,10,(4,3)) - uniform():均匀分布,前两个参数分别为区间的起始值和终值
r2=nr.uniform(10,20,(4,3)) - poisson():泊松分布,第一个参数指定λ参数,他表示单位时间(或单位面积)内随机事件的平均发生率。由于泊松分布是一个离散分布,因此他输出的数组时一个整数数组
r3=nr.poisson(2.0,(4,3)) - permutation()可以用于生产一个乱序数组,当参数为整数n时,它返回[0,n)这n个整数的随机排列;当参数为一个序列时,它返回一个随机排列之后的序列:
a=np.array([1,10,20,30,40])
nr.permutation(10)nr.permutation(a) - shuffle()直接将参数数组顺序打乱,permutation()返回一个新数组
nr.shuffle(a) - choice()从指定的样本中随机进行抽取
size参数用于指定输出数组的形状replace参数为True时,进行可重复抽取,而为False时进行不重复抽取,默认值巍峨True。c1可能有重复数值,c2每隔数值都不同
p参数指定每个元素对应的抽取概率,如果不指定,所有的元素倍抽取到的概率相同。值越大的元素被抽到的概率越大,因此c3中数值较大的元素比较多
a=np.arange(10,25,dtype=float)c1=nr.choice(a,size=(4,3))c2=nr.choice(a,size=(4,3),replace=False)c3=nr.choice(a,size=(4,3),p=a/np.sum(a)) - seed()函数指定随机数的种子,在伪随机数生成器里,使用seed方法可以生成固定的随机数数组
nr.seed(10)r1=nr.randint(0,100,3)
nr.seed(10)r2=nr.randint(0,100,3)
r1和r2一样
- rand 0到1之间的随机浮点数,它的所有参数用于指定所产生的数组的形状
- 求和、平均数、方差
- sum()计算数组元素之和,也可以对列表、元组等与数组类似的序列进行求和。当数组时多维时,它计算数组中所有元素的和。
np.random.seed(42)
a=np.random.randint(0,10,size=(4,5))
如果指定axis参数,则求和运算沿着指定的轴进行。结果数组为原数组的形状去掉axis个元素
np.sum(a,axis=1)
np.sum(a,axis=0)
当axis参数时一个轴的序列时,对指定的所有轴进行求和运算。
np.sum(np.ones((2,3,4)),axis=(0,2))array([8,8,8])
- sum()计算数组元素之和,也可以对列表、元组等与数组类似的序列进行求和。当数组时多维时,它计算数组中所有元素的和。