快速熟练使用numpy(学习笔记)

来源:互联网 发布:centos和redhat的区别 编辑:程序博客网 时间:2024/06/05 16:35

注:主要参考python科学计算(张若愚 著)

       工作中,有些技巧时间稍长不用,便容易遗忘,根据自己工作常会需要的功能,特汇总如下技巧,以供后续参考。

10分钟熟练使用numpy

1、什么是numpy?

numpy提供的两种基本对象

ndarray(n-dimensional arrayobject)和ufunc(universal function object)。其中,ndarray下文统一称之为数组,是存储单一数据类型的多维数组;ufunc则是能够对数组进行处理的函数。

2、numpy如何创建数组

import numpy as np

a=np.array([1,2,3,4])

c=np.array([[1,2,3,4],[5,6,7,8],[7,6,9,10]]) #传递多层嵌套序列,创建多维数组

 

3、numpy数组的形状

a.shape #获取数组的形状

c.shape=4,3 #从(3,4)到(4,3)并不是对数组进行转置,

     ...: #而只是改变每个轴的大小,数组元素在内存中的位置并没有改变

c.shape=2,-1 #当设置某轴的元素个数为-1时,将自动计算此轴的长度

d=a.reshape((2,2))#也可以用a.reshape(2,2),创建指定形状的新数组,而原数组形状不变

注:此时,数组a和数组d其实共享数据存储空间,因此修改其中任意一个数组都会同时修改另外一个数组内容。

4、numpy元素类型

c.dtype #数组的元素类型可以通过dtype 属性获得,输出为:dtype('int32')

np.array([1, 2, 3, 4], dtype=np.float)  #可以通过dtype 参数在创建数组时指定元素类型,类型查看为:dtype('float64')

注:,注意float 是64 bit 的双精度浮点类型

np.array([1, 2, 3, 4], dtype=np.complex)  #complex 是128 bit 的双精度复数类型,类型名为:dtype('complex128')

5、完整数据类型查看

NumPy 中的数据类型都有几种字符串表示方式,字符串和类型之间的对应关系都存储在typeDict 字典中,例如'd'、'double'、'float64'都表示双精度浮点类型

>>>np.typeDict["d"]

<type'numpy.float64'>

>>>np.typeDict["double"]

<type'numpy.float64'>

>>>np.typeDict["float64"]

<type'numpy.float64'>

完整的类型列表可以通过下面的语句得到,它将typeDict字典中所有的值转换为一个集合,

从而去除其中的重复项:set(np.typeDict.values())

Out[222]:

{numpy.bool_,

 ……   ……

 numpy.complex128}

 

6、快速初始化数组矩阵的方法

(1)np.arange(0,1,0.1) #arange()类似于内置函数range(),通过指定开始值、终值和步长创建表示等差数列的一维数组,注意得到的结果数组不包含终值。

(2)np.linspace(0, 1, 10)  # linspace()通过指定开始值、终值和元素个数创建表示等差数列的一维数组,可以通过endpoint参数指定是否包含终值,默认值为True,即包含终值。此处步长为1/9;另外,np.linspace(0, 1, 10, endpoint=False) # 步长为1/10;

(3)np.logspace(0, 2, 5) #logspace()和linspace()类似,不过它所创建的数组是等比数列。例子产生从10^0 到10^2、有5个元素的等比数列,注意起始值0表示10^0,而终值2表示10^2:

基数可以通过base 参数指定,默认值为10。下面通过将base 参数设置为2,并设置endpoint参数为False,创建一个比例为2^(1/12) 等比数组③:

(4) zeros()、ones()、empty()可以创建指定形状和类型的数组.

np.empty((2,3),np.int)# empty()仅仅分配数组所使用的内存,不对数组元素进行初始化操作,因此它的运行速度是最快的,类型为:dtype('int32');

np.zeros((3,4))  #zeros()则将数组元素初始化为0;

np.ones((3,4)) # ones()将数组元素初始化为1;

(5) zeros_like()、ones_like()、empty_like()等函数可创建与参数数组的形状及类型相同的数组。因此,“zeros_like(a)”和“zeros(a.shape, a.dtype)”的效果相同;

(6) 使用frombuffer()、fromstring()、fromfile()等函数可以从字节序列或文件创建数组;

s ="abcdefgh"

>>>np.fromstring(s, dtype=np.int8)

array([ 97, 98,99, 100, 101, 102, 103, 104], dtype=int8)

(7) 还可以先定义一个从下标计算数值的函数,然后用fromfunction()通过此函数创建数组, 参数形式:np.fromfunction(function,shape, **kwagrs)

>>> deffunc(i):

... return i%4+1

...

>>> np.fromfunction(func,(10,))

array([ 1., 2.,3., 4., 1., 2., 3., 4., 1., 2.])

 

7、一维存取元素

(1) 使用切片下标存取元素

>>> a =np.arange(10)

>>> a[5]# 用整数作为下标可以获取数组中的某个元素

>>>a[3:5] # 用切片作为下标可以获取数组的一部分,包括a[3]但不包括a[5]

>>> a[:5]# 切片中省略开始下标,表示从a[0]开始

>>>a[:-1] # 下标可以使用负数,表示从数组最后往前数

>>>a[2:4] = 100,101 # 下标还可以用来修改元素的值

>>>a[1:-1:2] # 切片中的第三个参数表示步长,2 表示隔一个元素获取一个元素

>>>a[::-1] # 省略切片的开始下标和结束下标,步长为-1,表示整个数组头尾颠倒

>>>a[5:1:-2] # 步长为负数时,开始下标必须大于结束下标

注:和列表不同的是,通过切片获取的新数组是原始数组的一个视图。它与原始数组共享同一块数据存储空间

>>> b =a[3:7] # 通过切片产生一个新的数组b,b 和a 共享同一块数据存储空间

>>> b[2]= -10 # 将b 的第2 个元素修改为-10

>>> a # a的第5 个元素也被修改为-10

(2) 整数列表、整数数组和布尔数组等几种高级下标存取方法

当使用整数列表对数组元素进行存取时,将使用列表中的每个元素作为下标。使用列表作为下标得到的数组不和原始数组共享数据:

>>> x =np.arange(10,1,-1)

>>> x[[3,3, 1, 8]] # 获取数组x 中下标为3、3、1、8 的4 个元素,组成一个新的数组

>>> b =x[[3,3,-3,8]] #下标可以是负数

>>> b[2]= 100 # 由于数组b 和x 不共享数据空间,因此数组x 中的值并没有改变

>>> x[[3,5,1]]= -1, -2, -3 # 整数序列下标也可以用来修改元素的值

>>>x[np.array([3,3,1,8])] #当下标数组是一维时,结果和用列表作为下标的结果相同

>>>x[np.array([[3,3,1,8],[3,3,-3,8]])] #而当下标是多维数组时,则得到的也是多维数组

#可以将其理解为:先将下标数组展平为一维数组,并作为下标获得一个新的一维数组,然后再将其形状修改为下标数组的形状

当使用布尔数组b 作为下标存取数组x 中的元素时,将收集数组x 中所有在数组b 中对应下标为True的元素。使用布尔数组作为下标获得的数组不和原始数组共享数据内存,注意这种方式只对应于布尔数组,不能使用布尔列表

>>> x =np.arange(5,0,-1)

>>>x[np.array([True, False, True, False, False])] ## 布尔数组中下标为0、2 的元素为True,因此获取数组x 中下标为0、2 的元素,布尔数组的长度不够时,不够的部分都当作False

>>>x[[True, False, True, False, False]] ## 如果是布尔列表,则把True 当作1, False 当作0,按照整数序列方式获取数组x 中的元素

>>>x[np.array([True, False, True, True])] = -1, -2, -3 #布尔数组下标也可以用来修改元素

注:布尔数组一般不是手工产生,而是使用布尔运算的ufunc 函数产生

>>> x =np.random.rand(10) # 产生一个长度为10、元素值为0 到1 的随机数组

>>> # 数组x 中的每个元素和0.5 进行大小比较,得到一个布尔数组,True表示x 中对应的值大于0.5

array([ True,True, True, False, False, True, False, True, False, True], dtype=bool)

>>> # 使用x>0.5 得到的布尔数组收集x 中的元素,因此结果就是包含x 中所有大于0.5 的元素的数组

>>>x[x>0.5]

 

8、多维数组

多维数组的存取和一维数组类似,因为多维数组有多个轴,因此它的下标需要用多个值表示。NumPy 采用元组(tuple)作为数组的下标,元组中的每个元素和数组的每个轴对应

在Python 程序中,经常用圆括号将元组的元素括起来,但其实元组的语法只需要用逗号隔开元素即可,因此,a[1,2]和a[(1,2)]完全相同,都是使用元组(1,2)作为数组a的下标。

>>> a =np.arange(0, 60, 10).reshape(-1, 1) + np.arange(0, 6)

>>> a

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

(1)多维数组切片举例

>>>a[0,3:5]

>>>a[4:,4:]

>>>a[:,2]

>>>a[2::2,::2]

(2)内存问题

如果下标元组中只包含整数和切片,那么得到的数组和原始数组共享数据,它是原数组的视图。

>>> b =a[0,3:5]

>>> b[0]= -b[0]

>>> a[0,3:5] #修改b[0]时,数组a 中对应的元素也被修改

array([-3, 4])

(3)slice对象(python内置对象)

数组的下标是一个元组,所以我们可以将下标元组保存起来,用同一个元组存取多个数组。

>>> idx =slice(None, None, 2), slice(2,None)

>>>a[idx] # 和a[::2,2:]相同

>>>a[idx][idx] # 和a[::2,2:][::2,2:]相同

slice 对象

在[]中可以使用以冒号隔开的两个或三个整数表示切片,但是单独生成切片对象时需要使用slice()创建。它有三个参数,分别为开始值、结束值和间隔步长,当这些值需要省略时可以使用None。例如,a[slice(None,None,None),2]和a[:,2]相同。

(4) s_对象(NumPy对象,创建数组下标)

>>>np.s_[::2,2:]

(slice(None, None,2), slice(2, None, None))

>>>np.s_   #s_实际上是一个IndexExpression类的对象

<numpy.lib.index_tricks.IndexExpressionobject at 0x015093D0>

注:根据Python的语法,只有在方括号“[]”中才能使用以冒号隔开的切片语法。

(4)创建副本

在多维数组的下标元组中,也可以使用整数元组或列表、整数数组和布尔数组。当在下标

中使用这些对象时,所获得的数据是原始数据的副本,因此修改结果数组不会改变原始数组。

>>>a[(0,1,2,3),(1,2,3,4)] #下标仍然是一个含有两个元素的元组,元组中的每个元素都是一个整数元组,分别对应数组的第0 轴和第1轴。从两个序列的对应位置取出两个整数组成下标,于是得到的结果是:a[0,1]、a[1,2]、a[2,3]、a[3,4]。

>>> a[3:,[0,2,5]] #第0 轴的下标是一个切片对象,它选取第3 行之后的所有行;第1 轴的下标是整数列表,它选取第0、2、5 列。

>>> mask= np.array([1,0,1,0,0,1], dtype=np.bool)

>>>a[mask, 2] #第0 轴的下标是一个布尔数组,它选取第0、2、5 行;第1轴的下标是一个整数,选取第2 列, 注意如果mask 不是布尔数组而是整数数组、列表或元组,就按照第一种的方式进行运算。

array([ 2, 22,52])

(5)其它

当下标的长度小于数组的维数时,则剩余的各轴所对应的下标是“:”,即选取它们的所有数据

>>>a[[1,2]] #与a[[1,2],:]相同

当所有轴都用形状相同的整数数组作为下标时,得到的数组和下标数组的维数相同

>>> x =np.array([[0,1],[2,3]])

>>> y =np.array([[-1,-2],[-3,-4]])

>>>a[x,y]

array([[ 5, 14],

[23, 32]])

它的效果和下面程序的相同:

>>>a[(0,1,2,3),(-1,-2,-3,-4)].reshape(2,2)

当没有指定第1 轴的下标时,则使用“:”作为其下标,因此得到了一个三维数组:

>>> a[x]

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

 

9、结构数组

(1)创建对象

persontype =np.dtype({ Œ

'names':['name','age', 'weight'],

'formats':['S32','i','f']}, align= True )

Œ先创建一个dtype 对象persontype,它的参数是一个描述结构类型的各个字段的字典。字典有两个键:'names'和'formats'。每个键对应的值都是一个列表。'names'定义结构中每个字段的名称,而'formats'则定义每个字段的类型。这里使用类型字符串定义字段类型:

● 'S32' :长度为32 字节的字符串类型,由于结构中每个元素的大小必须固定,因此需

要指定字符串的长度。

● 'i' :32 bit 的整数类型,相当于np.int32。

● 'f' :32 bit 的单精度浮点数类型,相当于np.float32。

(2)创建数组

a =np.array([("Zhang",32,75.5),("Wang",24,65.2)], 

dtype=persontype)

然后调用array()创建数组,通过dtype 参数指定所创建数组的元素类型为persontype

>>>a.dtype

dtype([('name','|S32'), ('age', '<i4'), ('weight', '<f4')])

这里我们看到了另外一种描述结构类型的方法:一个包含多个元组的列表,其中形如(字段名, 类型描述)的元组描述了结构中的每个字段。类型字符串前面的'|'、'<'、'>'等字符表示字段值的字节顺序:

| :忽视字节顺序

< :低位字节在前,即小端模式(little endian)

> :高位字节在前,即大端模式(big endian)

(3)数据获取

a.使用下标获取元素

>>> a[0] #通过下标能够取得其中的元素

('Zhang', 32,75.5)

>>>a[0].dtype #元素的值看上去像是元组,实际上它是一个结构

dtype([('name','|S32'), ('age', '<i4'), ('weight', '<f4')])

>>>a[0]["name"]  #可以使用字段名作为下标获取对应的字段值

'Zhang'

注:a[0]是一个结构元素,它和数组a 共享内存数据,因此可以通过修改它的字段,改变原始数组中对应元素的字

>>> c =a[1]

>>>c["name"] = "Li"

>>>a[1]["name"]

"Li"

b. 使用字段名直接获取结构数组的字段,它返回的是原始数组的视图,共享内存。

>>>a["name"]

array(['Zhang','Wang'],

      dtype='|S32')

>>>b=a["age"]

>>> b

array([32, 24])

>>> b[0]= 40

>>>a[0]["age"]

40

 

10、numpy种ufunc运算

ufunc 是universalfunction 的缩写,它是一种能对数组中每个元素进行操作的函数。NumPy内置的许多ufunc 函数都是在C语言级别实现的,因此它们的计算速度非常快。

>>> np.sin#查看函数类型

<ufunc'sin'>

>>> x =np.linspace(0, 2*np.pi, 10) #先用linspace()产生一个从0 到2 的等差数组

>>> y =np.sin(x) #将其传递给np.sin()函数计算每个元素的正弦

由于np.sin()是一个ufunc函数,因此在其内部对数组x 的每个元素进行循环,分

别计算它们的正弦值,并返回一个保存各个计算结果的数组。

运算之后数组x 中的值并没有改变,而是新创建了一个数组来保存结果。也可以通过out 参数指定计算结果的保存位置。因此如果希望直接在数组x 中保存结果,可以将它传递给out 参数:

>>> t =np.sin(x,out=x)

>>> id(t)== id(x)

True

 

11、ufunc运算之四则运算

NumPy 为数组定义了各种数学运算操作符,数组的运算符及其对应的ufunc 函数如下:

运 算 符      对应的ufunc 函数

y = x1+ x2     add(x1, x2 [, y])

y = x1- x2     subtract(x1, x2 [, y])

y = x1* x2     multiply (x1, x2 [, y])

y = x1/ x2     divide (x1, x2 [, y]), 如果两个数组的元素为整数,那么用整数除法

y = x1/ x2     true_divide (x1, x2 [, y]), 总是返回精确的商

y = x1// x2     floor_divide (x1, x2 [, y]), 总是对返回值取整

y =-x         negative(x [,y])

y =x1**x2     power(x1, x2 [, y])

y = x1% x2     remainder(x1, x2 [, y]),或mod(x1, x2, [, y])

补充:“del t”减少变量t内存分配

 

12、ufunc运算之比较和布尔运算

(1)比较运算符

比较运算符及其对应的ufunc 函数如下:

比较运算符     ufunc 函数

y = x1== x2    equal(x1, x2 [, y])

y = x1!= x2    not_equal(x1, x2 [, y])

y = x1< x2     less(x1, x2, [, y])

y = x1<= x2    less_equal(x1, x2, [, y])

y = x1> x2     greater(x1, x2, [, y])

y = x1>= x2    greater_equal(x1, x2, [, y])

使用“==”、“>”等比较运算符对两个数组进行比较,将返回一个布尔数组。

(2)布尔运算

由于Python 中的布尔运算使用and、or 和not 等关键字,它们无法被重载,因此数组的布尔运算只能通过相应的ufunc 函数进行。

>>>np.logical # 按Tab 键进行自动补全

np.logical_and np.logical_not np.logical_ornp.logical_xor

>>> np.logical_and#查看函数类型

<ufunc 'logical_and'>

下面是一个使用logical_or()进行或运算的例子:

exp1:

>>> a =np.arange(5)

>>> b =np.arange(4,-1,-1)

>>> a ==b

array([False,False, True, False, False], dtype=bool)

>>> a> b

array([False,False, False, True, True], dtype=bool)

>>>np.logical_or(a==b, a>b) # 和 a>=b 相同

array([False,False, True, True, True], dtype=bool)

对两个布尔数组使用and、or 和not 等进行布尔运算,将抛出ValueError 异常。因为布尔数组中有True 也有False,所以NumPy 无法确定用户的运算目的:

exp2:

>>> a==band a>b

ValueError: Thetruth value of an array with more than one

element isambiguous. Use a.any() or a.all()

错误信息告诉我们可以使用数组的any()或all()方法④。只要数组中有一个值为True,any()

就返回True;而只有当数组的全部元素都为True 时,all()才返回True

exp3:

>>>np.any(a==b)

True

>>>np.any(a==b) and np.any(a>b)

True

(3) 比特运算函数(对于布尔数组来说,位运算和布尔运算的结果相同)

以“bitwise_”开头的函数是比特运算函数,包括bitwise_and、bitwise_not、bitwise_or 和bitwise_xor等。也可以使用"&"、"~"、"|"和"^"等操作符进行计算。

注意:对于布尔数组来说,位运算和布尔运算的结果相同。但在使用时要注意,位运算符的优先级比比较运算符高,因此需要使用括号提高比较运算的运算优先级。例如:

>>>(a==b) | (a>b)

array([False,False, True, True, True], dtype=bool)

 

13、自定义ufunc 函数

方便地用所产生的ufunc 函数对数组进行计算

举例:一个分段函数描述三角波

deftriangle_wave(x, c, c0, hc):

x = x - int(x) # 三角波的周期为1,因此只取x 坐标的小数部分进行计算

if x >= c: r = 0.0

elif x < c0: r = x / c0 * hc

else: r = (c-x) / (c-c0) * hc

return r

方法1:列表推导

x = np.linspace(0,2, 1000)

y1 =np.array([triangle_wave(t, 0.6, 0.4, 1.0) for t in x])

方法2:frompyfunc函数

通过frompyfunc()可以将计算单个值的函数转换为一个能对数组中每个元素进行计算的ufunc 函数。frompyfunc()的调用格式为:

frompyfunc(func, nin, nout)

其中,func 是计算单个元素的函数,nin 是func 输入参数的个数,nout 是func 返回值的个

数。下面的程序使用frompyfunc()将triangle_wave()转换为一个ufunc 函数对triangle_ufunc1:

triangle_ufunc1 =np.frompyfunc(triangle_wave, 4, 1) #简单定义下即可!

y2 =triangle_ufunc1(x, 0.6, 0.4, 1.0)

值得注意的是,triangle_ufunc1()所返回数组的元素类型是object,因此还需要再调用数组的astype()方法以将其转换为双精度浮点数组:

>>>y2.dtype

dtype('object')

>>> y2 =y2.astype(np.float)

>>>y2.dtype

dtype('float64')

方法3:vectorize()函数

使用vectorize()可以实现和frompyfunc()类似的功能,但它可以通过otypes 参数指定返回数组的元素类型。otypes 参数可以是一个表示元素类型的字符串,也可以是一个类型列表,使用列表可以描述多个返回数组的元素类型。下面的程序使用vectorize()计算三角波:

triangle_ufunc2 =np.vectorize(triangle_wave, otypes=[np.float])

y3 =triangle_ufunc2(x, 0.6, 0.4, 1.0)

 

14、广播

当使用ufunc 函数对两个数组进行计算时,ufunc 函数会对这两个数组的对应元素进行计算,因此要求这两个数组的形状相同。如果形状不同,会进行如下的广播(broadcasting)处理:

(1) 让所有输入数组都向其中维数最多的数组看齐,shape 属性中不足的部分都通过在前面

加1 补齐。

(2) 输出数组的shape 属性是输入数组的shape 属性在各个轴上的最大值。

(3) 如果输入数组的某个轴长度为1 或与输出数组对应轴的长度相同,这个数组就能够用

来计算,否则出错。

(4) 当输入数组的某个轴长度为1 时,沿着此轴运算时都用此轴上的第一组值。

a.广播举例

>>> a =np.arange(0, 60, 10).reshape(-1, 1)

>>> b =np.arange(0, 5)

>>> c = a+ b  # 等价于以下扩展后的a+b

>>> a =a.repeat(5, axis=1)

>>> a

array([[ 0, 0, 0,0, 0],

[10, 10, 10, 10,10],

[20, 20, 20, 20,20],

[30, 30, 30, 30,30],

[40, 40, 40, 40,40],

[50, 50, 50, 50,50]])

>>> b =b.repeat(6,axis=0)

>>> b

array([[0, 1, 2,3, 4],

[0, 1, 2, 3, 4],

[0, 1, 2, 3, 4],

[0, 1, 2, 3, 4],

[0, 1, 2, 3, 4],

[0, 1, 2, 3, 4]])

b.快速产生能进行广播运算(ogrid对象与mgrid对象)

>>> x,y =np.ogrid[:5,:5]

>>> x

array([[0],[1],[2],[3],[4]])

>>> y

array([[0, 1, 2,3, 4]])

mgrid 对象的用法和ogrid 对象类似,但是它所返回的是进行广播之后的数组

>>> np.mgrid[:2,:2]

array([[[0, 0],

        [1, 1]],

       [[0, 1],

        [0, 1]]])

 

15、ufunc 函数的方法

ufunc 函数对象本身还有一些方法,这些方法只对两个输入、一个输出的ufunc 对象有效,其他的ufunc 对象调用这些方法时会抛出ValueError异常。

(1) reduce()方法

reduce()方法和Python的reduce()函数类似,它沿着axis 参数指定的轴对数组进行操作,相当于将<op>运算符插入到沿axis 轴的所有元素之间。

<op>.reduce (array, axis=0, dtype=None)

例如:

>>>np.add.reduce([1,2,3]) # 1 + 2 + 3

6

>>>np.add.reduce([[1,2,3],[4,5,6]], axis=1) # (1+2+3),(4+5+6)

array([ 6, 15])

(2) accumulate()方法

accumulate()和reduce()类似,只是它返回的数组和输入数组的形状相同,保存所有的中间计算结果:

>>>np.add.accumulate([1,2,3])

array([1, 3, 6])

>>>np.add.accumulate([[1,2,3],[4,5,6]], axis=1)

array([[ 1, 3, 6],

[ 4, 9, 15]])

(3) outer()方法

ufunc 函数对象的outer()方法对其两个参数数组中每两对元素的组合进行运算。如果数组a的维数为M,数组b 的维数为N,那么使用ufunc 函数op 的outer()方法对数组a、b 计算后,生成的数组c 的维数为M+N。

>>>np.multiply.outer([1,2,3,4,5],[2,3,4])

array([[ 2, 3, 4],

[ 4, 6, 8],

[ 6, 9, 12],

[ 8, 12, 16],

[10, 15, 20]])

可以看出,通过outer()计算得到的结果是如下的乘法表:

*| 2 3 4

------------

1| 2 3 4

2| 4 6 8

3| 6 9 12

4| 8 12 16

5|10 15 20

 

16、numpy如何求和、平均值、标准差、方差

numpy中sum方法计算数组元素之和,可以对列表、元组等和数组类似的序列进行求和,当数组是多维时,它计算所有元素之和。

>>> a=np.random.randint(0,10,size=(4,5))

>>> a

array([[3, 4, 6,4, 7],

       [0, 6, 1, 2, 1],

       [6, 3, 4, 7, 4],

       [1, 5, 1, 3, 9]])

>>>  np.sum(a)

77

如果指定axis参数,求和运算在指定轴进行。

In [393]:np.sum(a,axis=1)

Out[393]:array([24, 10, 24, 19])

In [394]:np.sum(a,axis=0)

Out[394]:array([10, 18, 12, 16, 21])

 

mean()用于求数组平均值,也可以通过axis参数指定求平均值的轴,通过out参数指定输出数组。此外,average()也可以对数组进行平均计算,它没有out和dtype参数,但它有一个指定weights参数。

  std()和var()分别计算数组的标准差和方差,有axis、out及dtype等参数。

 

17、最值和排序

(1)最值

    np.max()和np.min()可以计算数组最大值和最小值,而pyp()计算最大最小值之间的差它们有axis和out两个参数,用法与np.sum()相同。

np.argmax()和np.argmin()可以求最大值最小值下标,如果不指定axis参数,就返回平坦化后的数组下标。如:

In [401]:np.argmax(a) #找到数组a中最大值的小标,有多个值时得到第一个最值下标

Out[401]: 19

In [404]:a.ravel()[19] #求平坦化后数组中第19个元素

Out[404]: 9

可以通过unravel_index()将一维下标转化为多维数组中的下标,它的第一个参数为一维下标值,第二个参数为多维数组形状:

In [405]: a

Out[405]:

array([[3, 4, 6,4, 7],

       [0, 6, 1, 2, 1],

       [6, 3, 4, 7, 4],

       [1, 5, 1, 3, 9]])

 

In [406]:idx=np.unravel_index(19,a.shape)

 

In [407]: idx

Out[407]: (3, 4)

 

In [408]: a[idx]

Out[408]: 9

 

  当使用axis参数时,可以沿着指定轴计算最大值的下标:

idx=np.argmax(a,axis=1)

idx

Out[410]:array([4, 1, 3, 4], dtype=int64)

  下面使用idx选择每行的最大值:

 

In [414]:a[range(a.shape[0]),idx]

Out[414]:array([7, 6, 7, 9])

(2)排序

数组的.sort()方法用于对数组进行排序,它将改变数组的内容。而np.sort()函数则返回一个数组,不改变原始数组。它们的axis默认值都是-1,即沿着数组的最后一个轴进行排序。sort()函数的axis可以设置为None, 此时它将得到平坦化后进行排序的新数组。

In [416]:np.sort(a)  #对每行的数据进行排序

Out[416]:

array([[3, 4, 4,6, 7],

       [0, 1, 1, 2, 6],

       [3, 4, 4, 6, 7],

       [1, 1, 3, 5, 9]])

 

In [417]:np.sort(a,axis=0) #对每列的数据进行排序

Out[417]:

array([[0, 3, 1,2, 1],

       [1, 4, 1, 3, 4],

       [3, 5, 4, 4, 7],

       [6, 6, 6, 7, 9]])

 np.argsort()返回数组的排序下标,axis参数默认值是-1:

In [418]:idx=np.argsort(a)

 

In [419]: idx

Out[419]:

array([[0, 1, 3,2, 4],

       [0, 2, 4, 3, 1],

       [1, 2, 4, 0, 3],

       [0, 2, 3, 1, 4]], dtype=int64)

  为了使用idx计算排序之后的数组,即np.sort(a)的结果,需要产生第0轴的下标,用ogrid对象产生第0轴的下标x:

In [420]: x,_=np.ogrid[:a.shape[0], :a.shape[1]]

 

In [421]: x

Out[421]:

array([[0],

       [1],

       [2],

       [3]])

 

In [422]: a[x,idx]#和np.sort(a)结果相同

Out[422]:

array([[3, 4, 4,6, 7],

       [0, 1, 1, 2, 6],

       [3, 4, 4, 6, 7],

       [1, 1, 3, 5, 9]])

(3)其它

排序相关的方法还可以通过kind参数指定排序算法,对于结构数组,可以通过order参数指定排序所使用的字段。

用np.median()可以获得数组的中值,即对数组排序后,位于数组中间位置的值。

 

18、统计函数

(1)np.unique()

返回其参数数组中所有不同的值,并且按照从小到大的顺序排列。有两个参数:

return_index: True表示同时返回原始数组中的下标;

return_inverse: True表示返回重建原始数组用的下标数组。

(2)np.bincount()

对整数数组中的各个元素出现的次数进行统计,它要求数组中的所有元素都是非负的,其返回值中第i个元素表示整数i在参数数组中出现的次数。

(3)histogram()

对一维数组进行直方图统计,其参数列表如下:

histogram(a,bins=10, range=None, normed=False, weights=None)

 

19、矩阵运算

matrix对象

numpy库提供了matrix类,使用matrix类创建的是矩阵对象,它们的加减乘除运算缺省采用矩阵方式计算,因此用法和matlab十分类似。但是由于NumPy中同时存在ndarray和matrix对象,因此用户很容易将两者弄混。这有违Python的“显式优于隐式”的原则,因此并不推荐在较复杂的程序中使用matrix。下面是使用matrix的一个例子:

 

>>> a =np.matrix([[1,2,3],[5,5,6],[7,9,9]])

>>>a*a**-1

matrix([[  1.00000000e+00,   1.66533454e-16,  -8.32667268e-17],

        [ -2.77555756e-16,   1.00000000e+00,  -2.77555756e-17],

        [ 1.66533454e-16,  5.55111512e-17,  1.00000000e+00]])

因为a是用matrix创建的矩阵对象,因此乘法和幂运算符都变成了矩阵运算,于是上面计算的是矩阵a和其逆矩阵的乘积,结果是一个单位矩阵。

 

20、文件存取

NumPy提供了多种文件操作函数方便我们存取数组内容。文件存取的格式分为两类:二进制和文本。而二进制格式的文件又分为NumPy专用的格式化二进制类型和无格式类型。

 

使用数组的方法函数tofile可以方便地将数组中数据以二进制的格式写进文件。tofile输出的数据没有格式,因此用numpy.fromfile读回来的时候需要自己格式化数据:

 

>>> a =np.arange(0,12)

>>>a.shape = 3,4

>>> a

array([[ 0,  1, 2,  3],

       [ 4, 5,  6,  7],

       [ 8, 9, 10, 11]])

>>>a.tofile("a.bin")

>>> b =np.fromfile("a.bin", dtype=np.float) # 按照float类型读入数据

>>> b # 读入的数据是错误的

array([  2.12199579e-314,   6.36598737e-314,   1.06099790e-313,

         1.48539705e-313,   1.90979621e-313,   2.33419537e-313])

>>>a.dtype # 查看a的dtype

dtype('int32')

>>> b =np.fromfile("a.bin", dtype=np.int32) # 按照int32类型读入数据

>>> b # 数据是一维的

array([ 0,  1, 2,  3,  4, 5,  6,  7, 8,  9, 10, 11])

>>>b.shape = 3, 4 # 按照a的shape修改b的shape

>>> b # 这次终于正确了

array([[ 0,  1, 2,  3],

       [ 4, 5,  6,  7],

       [ 8, 9, 10, 11]])

从上面的例子可以看出,需要在读入的时候设置正确的dtype和shape才能保证数据一致。并且tofile函数不管数组的排列顺序是C语言格式的还是Fortran语言格式的,统一使用C语言格式输出。

 

此外如果fromfile和tofile函数调用时指定了sep关键字参数的话,数组将以文本格式输入输出。

numpy.load和numpy.save函数以NumPy专用的二进制类型保存数据,这两个函数会自动处理元素类型和shape等信息,使用它们读写数组就方便多了,但是numpy.save输出的文件很难和其它语言编写的程序读入:

>>>np.save("a.npy", a)

>>> c =np.load( "a.npy" )

>>> c

array([[ 0,  1, 2,  3],

       [ 4, 5,  6,  7],

       [ 8, 9, 10, 11]])

如果你想将多个数组保存到一个文件中的话,可以使用numpy.savez函数。savez函数的第一个参数是文件名,其后的参数都是需要保存的数组,也可以使用关键字参数为数组起一个名字,非关键字参数传递的数组会自动起名为arr_0, arr_1, ...。savez函数输出的是一个压缩文件(扩展名为npz),其中每个文件都是一个save函数保存的npy文件,文件名对应于数组名。load函数自动识别npz文件,并且返回一个类似于字典的对象,可以通过数组名作为关键字获取数组的内容:

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

>>> b =np.arange(0, 1.0, 0.1)

>>> c =np.sin(b)

>>>np.savez("result.npz", a, b, sin_array = c)

>>> r =np.load("result.npz")

>>>r["arr_0"] # 数组a

array([[1, 2, 3],

       [4, 5, 6]])

>>>r["arr_1"] # 数组b

array([ 0. ,  0.1, 0.2,  0.3,  0.4, 0.5,  0.6,  0.7, 0.8,  0.9])

>>>r["sin_array"] # 数组c

array([ 0.        , 0.09983342,  0.19866933,  0.29552021, 0.38941834,

        0.47942554,  0.56464247, 0.64421769,  0.71735609,  0.78332691])

如果你用解压软件打开result.npz文件的话,会发现其中有三个文件:arr_0.npy,arr_1.npy, sin_array.npy,其中分别保存着数组a, b, c的内容。

 

使用numpy.savetxt和numpy.loadtxt可以读写1维和2维的数组:

 

>>> a =np.arange(0,12,0.5).reshape(4,-1)

>>>np.savetxt("a.txt", a) # 缺省按照'%.18e'格式保存数据,以空格分隔

>>>np.loadtxt("a.txt")

array([[  0. ,  0.5,   1. ,   1.5,  2. ,   2.5],

       [ 3. ,   3.5,   4. ,  4.5,   5. ,   5.5],

       [ 6. ,   6.5,   7. ,  7.5,   8. ,   8.5],

       [ 9. ,   9.5,  10. , 10.5,  11. ,  11.5]])

>>>np.savetxt("a.txt", a, fmt="%d", delimiter=",") #改为保存为整数,以逗号分隔

>>>np.loadtxt("a.txt",delimiter=",") # 读入的时候也需要指定逗号分隔

array([[  0.,  0.,   1.,   1.,  2.,   2.],

       [ 3.,   3.,   4.,  4.,   5.,   5.],

       [ 6.,   6.,   7.,  7.,   8.,   8.],

       [ 9.,   9.,  10., 10.,  11.,  11.]])

文件名和文件对象

 

本节介绍所举的例子都是传递的文件名,也可以传递已经打开的文件对象,例如对于load和save函数来说,如果使用文件对象的话,可以将多个数组储存到一个npy文件中:

 

>>> a =np.arange(8)

>>> b =np.add.accumulate(a)

>>> c = a+ b

>>> f =file("result.npy", "wb")

>>>np.save(f, a) # 顺序将a,b,c保存进文件对象f

>>>np.save(f, b)

>>>np.save(f, c)

>>>f.close()

>>> f =file("result.npy", "rb")

>>>np.load(f) # 顺序从文件对象f中读取内容

array([0, 1, 2, 3,4, 5, 6, 7])

>>>np.load(f)

array([ 0,  1, 3,  6, 10, 15, 21, 28])

>>>np.load(f)

array([ 0,  2, 5,  9, 14, 20, 27, 35])


补充:对齐打印问题

s1 = 'I am a long sentence.'  
s2 = 'I\'m short.'  
  
print '%-30s%-20s' %(s1,s2) #'%-30s' 含义是 左对齐,且占用30个字符位   
print '%-30s%-20s' %(s2,s1)  

原创粉丝点击