快捷搜索:
来自 计算机编程 2019-08-03 17:47 的文章
当前位置: 67677新澳门手机版 > 计算机编程 > 正文

整理的NumPy详细教程

Numpy介绍

NumPy在数据分析就像Django在web开发中那样出名,就是老大哥,也是在工作中最常用的库,没有之一,今天给大家详细的讲解一下这个库的妙用!

 

图片 1

Numpy是Python的一个科学计算的库,提供了矩阵运算的功能,其一般与Scipy、matplotlib一起使用。

103456743

NumPy的主要对象是同种元素的多维数组。这是一个所有的元素都是一种类型、通过一个正整数元组索引的元素表格(通常是元素是数字)。在NumPy中维度(dimensions)叫做轴(axes),轴的个数叫做秩(rank)。

图片 2

例如,在3D空间一个点的坐标 [1, 2, 3] 是一个秩为1的数组,因为它只有一个轴,这个轴长度为3。

图片 3

又例如,在以下例子中,数组的秩为2(它有两个维度).第一个维度长度为2,第二个维度长度为3。

ndarray.ndim

  1. [[ 1., 0., 0.],
  2.  [ 0., 1., 2.]]

数组轴的个数,在python的世界中,轴的个数被称作秩

NumPy的数组类(type)被称作 ndarray 。通常被称作数组。注意numpy.array和标准Python库类array.array并不相同,后者只处理一维数组和提供少量功能。更多重要ndarray对象属性有:

ndarray.shape

  • ndarray.ndim

数组的维度。这是一个指示数组在每个维度上大小的整数元组。例如一个n排m列的矩阵,它的shape属性将是(2,3),这个元组的长度显然是秩,即维度或者ndim属性

数组轴的个数,在python的世界中,轴的个数被称作秩

ndarray.size

  • ndarray.shape

数组元素的总个数,等于shape属性中元组元素的乘积。

数组的维度。这是一个指示数组在每个维度上大小的整数元组。例如一个n排m列的矩阵,它的shape属性将是(2,3),这个元组的长度显然是秩,即维度或者ndim属性

ndarray.dtype

  • ndarray.size

一个用来描述数组中元素类型的对象,可以通过创造或指定dtype使用标准Python类型。另外NumPy提供它自己的数据类型。

数组元素的总个数,等于shape属性中元组元素的乘积。

ndarray.itemsize

  • ndarray.dtype

数组中每个元素的字节大小。例如,一个元素类型为float64的数组itemsiz属性值为8(=64/8),又如,一个元素类型为complex32的数组item属性为4(=32/8).

一个用来描述数组中元素类型的对象,可以通过创造或指定dtype使用标准Python类型。另外NumPy提供它自己的数据类型;而且可以使用astype转换类型,在处理文件时候会很实用,注意astype 调用会返回一个新的数组,也就是原始数据的一份拷贝。

ndarray.data

例:

包含实际数组元素的缓冲区,通常我们不需要使用这个属性,因为我们总是通过索引来使用数组中的元素。

>>> import numpy as np
>>> pp = np.array(['1.23','2.34','3.45'],dtype=np.string_)
>>> pp
array([b'1.23', b'2.34', b'3.45'], dtype='|S4')
>>> pp.astype(float)   # 使用astype转换类型
array([1.23, 2.34, 3.45])

图片 4

  • ndarray.itemsize

图片 5

数组中每个元素的字节大小。例如,一个元素类型为float64的数组itemsiz属性值为8(=64/8),又如,一个元素类型为complex32的数组item属性为4(=32/8).

图片 6

  • ndarray.data

图片 7

包含实际数组元素的缓冲区,通常我们不需要使用这个属性,因为我们总是通过索引来使用数组中的元素。

图片 8

导入numpy,通用做法:import numpu as np ,或 from numpy import *。

图片 9

例:

图片 10

>>> from numpy import *
>>> a = arange(15).reshape(3,5)
>>> a

图片 11

# 执行结果:
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])

图片 12

>>> a.shape   # 数组的维度

图片 13

# 执行结果:
(3, 5) 

图片 14

>>> a.ndim   # 数组轴的个数,在python的世界中,轴的个数被称作秩

图片 15

# 执行结果:
2

图片 16

>>> a.dtype.name  # 元素类型 

x[1,2,…] 等同于 x[1,2,:,:,:],

# 执行结果:
'int32' 

x[…,3] 等同于 x[:,:,:,:,3]

>>> a.itemsize  # 数组中每个元素的字节大小 

x[4,…,5,:] 等同 x[4,:,:,5,:].

# 执行结果:

图片 17

>>> a.size  # 数组元素的总个数,等于shape属性中元组元素的乘积

图片 18

# 执行结果:
15 

图片 19

>>> type(a)  # 返回数组的类型

图片 20

# 执行结果:
<class 'numpy.ndarray'> 

图片 21

>>> a.data  # 实际数组元素的缓冲区

图片 22

# 执行结果:
<memory at 0x05A6D5D0>

图片 23

 

图片 24

创建数组

图片 25

 

图片 26

建数组的方法有多种。

进阶

例如,你可以使用 array 函数从常规的Python列表和元组创造数组。所创建的数组类型由原序列中的元素类型推导而来。

广播法则(rule)

>>> from numpy import *
>>> a = array( [2,3,4] )
>>> a

广播法则能使通用函数有意义地处理不具有相同形状的输入。

# 执行结果:
array([2, 3, 4])

广播第一法则是,如果所有的输入数组维度不都相同,一个“1”将被重复地添加在维度较小的数组上直至所有的数组拥有一样的维度。

 

广播第二法则确定长度为1的数组沿着特殊的方向表现地好像它有沿着那个方向最大形状的大小。对数组来说,沿着那个维度的数组元素的值理应相同。

>>> a.dtype

应用广播法则之后,所有数组的大小必须匹配。更多细节可以从这个文档找到。

# 执行结果:
dtype('int32')

图片 27

 

图片 28

>>> b = array([1.2,3.5,5.1])
>>> b.dtype

图片 29

# 执行结果:
dtype('float64')

图片 30

 

图片 31

>>> a = array(1,2,3,4)  #一个常见的错误包括用多个数值参数调用`array`而不是提供一个由数值组成的列表作为一个参数。

图片 32

# 执行结果:(报错)

图片 33

Traceback (most recent call last):
File "<pyshell#27>", line 1, in <module>
a = array(1,2,3,4)
ValueError: only 2 non-keyword arguments accepted

第二种通过布尔来索引的方法更近似于整数索引;对数组的每个维度我们给一个一维布尔数组来选择我们想要的切片。

 

>>> a = arange(12).reshape(3,4)>>> b1 = array([False,True,True]) # first dim selection>>> b2 = array([True,False,True,False]) # second dim selection>>>>>> a[b1,:] # selecting rowsarray([[ 4, 5, 6, 7], [ 8, 9, 10, 11]])>>>>>> a[b1] # same thingarray([[ 4, 5, 6, 7], [ 8, 9, 10, 11]])>>>>>> a[:,b2] # selecting columnsarray([[ 0, 2], [ 4, 6], [ 8, 10]])>>>>>> a[b1,b2] # a weird thing to doarray([ 4, 10])

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

注意一维数组的长度必须和你想要切片的维度或轴的长度一致,在之前的例子中,b1是一个秩为1长度为三的数组(a的行数),b2(长度为4)与a的第二秩(列)相一致。7

>>> a

ix_()函数

# 执行结果:(正确)
array([1, 2, 3, 4])

ix_函数可以为了获得多元组的结果而用来结合不同向量。例如,如果你想要用所有向量a、b和c元素组成的三元组来计算a b*c:

 

>>> a = array([2,3,4,5])>>> b = array([8,5,4])>>> c = array([5,4,6,8,3])>>> ax,bx,cx = ix_(a,b,c)>>> axarray([[[2]], [[3]], [[4]], [[5]]])>>> bxarray([[[8], [5], [4]]])>>> cxarray([[[5, 4, 6, 8, 3]]])>>> ax.shape, bx.shape, cx.shape((4, 1, 1), (1, 3, 1), (1, 1, 5))>>> result = ax bx*cx>>> resultarray([[[42, 34, 50, 66, 26], [27, 22, 32, 42, 17], [22, 18, 26, 34, 14]], [[43, 35, 51, 67, 27], [28, 23, 33, 43, 18], [23, 19, 27, 35, 15]], [[44, 36, 52, 68, 28], [29, 24, 34, 44, 19], [24, 20, 28, 36, 16]], [[45, 37, 53, 69, 29], [30, 25, 35, 45, 20], [25, 21, 29, 37, 17]]])>>> result[3,2,4]17>>> a[3] b[2]*c[4]17

>>> b = array([(1.5,2,3),(4,5,6)])   # 数组将“序列包含序列”转化成二维的数组,“序列包含序列”转化成三维数组等等。
>>> b

你也可以实行如下简化:

# 执行结果:
array([[1.5, 2. , 3. ],
           [4. , 5. , 6. ]])

def ufunc_reduce(ufct, *vectors): vs = ix_(*vectors) r = ufct.identity for v in vs: r = ufct(r,v) return r

 

然后这样使用它:

>>> c = array( [ [1,2], [3,4] ], dtype=complex )  #数组类型可以在创建时显示指定
>>> c

>>> ufunc_reduce(add,a,b,c)array([[[15, 14, 16, 18, 13], [12, 11, 13, 15, 10], [11, 10, 12, 14, 9]], [[16, 15, 17, 19, 14], [13, 12, 14, 16, 11], [12, 11, 13, 15, 10]], [[17, 16, 18, 20, 15], [14, 13, 15, 17, 12], [13, 12, 14, 16, 11]], [[18, 17, 19, 21, 16], [15, 14, 16, 18, 13], [14, 13, 15, 17, 12]]])

# 执行结果:
array([[1. 0.j, 2. 0.j],
           [3. 0.j, 4. 0.j]])

这个reduce与ufunc.reduce(比如说add.reduce)相比的优势在于它利用了广播法则,避免了创建一个输出大小乘以向量个数的参数数组。8

 

用字符串索引

通常,数组的元素开始都是未知的,但是它的大小已知。因此,NumPy提供了一些使用占位符创建数组的函数。这最小化了扩展数组的需要和高昂的运算代价。

参见RecordArray。

 

线性代数

函数 zeros  创建一个全是0的数组,函数 ones 创建一个全1的数组,函数 empty 创建一个内容随机并且依赖于内存状态的数组。默认创建的数组类型(dtype)都是float64。

继续前进,基本线性代数包含在这里。

例:

简单数组运算

>>> zeros( (3,4) )

参考numpy文件夹中的linalg.py获得更多信息

# 执行结果:
array([[0., 0., 0., 0.],
           [0., 0., 0., 0.],
           [0., 0., 0., 0.]])

>>> from numpy import *>>> from numpy.linalg import *>>> a = array([[1.0, 2.0], [3.0, 4.0]])>>> print a[[ 1. 2.][ 3. 4.]]>>> a.transpose()array([[ 1., 3.], [ 2., 4.]])>>> inv(a)array([[-2. , 1. ], [ 1.5, -0.5]])>>> u = eye(2) # unit 2x2 matrix; "eye" represents "I">>> uarray([[ 1., 0.], [ 0., 1.]])>>> j = array([[0.0, -1.0], [1.0, 0.0]])>>> dot (j, j) # matrix productarray([[-1., 0.], [ 0., -1.]])>>> trace(u) # trace2.0>>> y = array([[5.], [7.]])>>> solve(a, y)array([[-3.], [ 4.]])>>> eig(j)(array([ 0. 1.j, 0.-1.j]),array([[ 0.70710678 0.j, 0.70710678 0.j], [ 0.00000000-0.70710678j, 0.00000000 0.70710678j]]))Parameters: square matrixReturns The eigenvalues, each repeated according to its multiplicity. The normalized (unit "length") eigenvectors, such that the column ``v[:,i]`` is the eigenvector corresponding to the eigenvalue ``w[i]`` .

 

矩阵类

>>>ones( (2,3,4), dtype=int16 )  # 数组类型可以在创建时显示指定

这是一个关于矩阵类的简短介绍。

# 执行结果:
array([[[1, 1, 1, 1],
    [1, 1, 1, 1],
    [1, 1, 1, 1]],

>>> A = matrix('1.0 2.0; 3.0 4.0')>>> A[[ 1. 2.][

     [[1, 1, 1, 1],
    [1, 1, 1, 1],
    [1, 1, 1, 1]]], dtype=int16)

  1. 4.]]>>> type(A) # file where class is defined>>> A.T # transpose[[ 1. 3.][ 2. 4.]]>>> X = matrix('5.0 7.0')>>> Y = X.T>>> Y[[5.][7.]]>>> print A*Y # matrix multiplication[[19.][43.]]>>> print A.I # inverse[[-2. 1. ][ 1.5 -0.5]]>>> solve(A, Y) # solving linear equationmatrix([[-3.], [ 4.]])

 

索引:比较矩阵和二维数组

>>> empty((2,3))

注意NumPy中数组和矩阵有些重要的区别。NumPy提供了两个基本的对象:一个N维数组对象和一个通用函数对象。其它对象都是建构在它们之上 的。特别的,矩阵是继承自NumPy数组对象的二维数组对象。对数组和矩阵,索引都必须包含合适的一个或多个这些组合:整数标量、省略号 (ellipses)、整数列表;布尔值,整数或布尔值构成的元组,和一个一维整数或布尔值数组。矩阵可以被用作矩阵的索引,但是通常需要数组、列表或者 其它形式来完成这个任务。

# 执行结果:(32位操作系统)
array([[1.39069238e-309, 1.39069238e-309, 1.39069238e-309],
[1.39069238e-309, 1.39069238e-309, 1.39069238e-309]])

图片 34

 

现在有些和Python索引不同的了:你可以同时使用逗号分割索引来沿着多个轴索引。

为了创建一个数列,NumPy提供一个类似arange的函数返回数组而不是列表:

>>> print A[:,1]; print A[:,1].shape[1 5 9](3,)>>> print M[:,1]; print M[:,1].shape[[1][5][9]](3, 1)

>>> arange(10,30,5)

图片 35

# 执行结果:
array([10, 15, 20, 25])  # 相当于步长为5

>>> A[:,[1,3]]array([[ 1, 3], [ 5, 7], [ 9, 11]])

 

稍微复杂点的方法是使用take()方法(method):

>>> arange( 0, 2, 0.3 )

>>> A[:,].take([1,3],axis=1)array([[ 1, 3], [ 5, 7], [ 9, 11]])

# 执行结果:
array([0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8])  # 相当于步长为0.3

如果我们想跳过第一行,我们可以这样:

当 arange 使用浮点数参数时,由于有限的浮点数精度,通常无法预测获得的元素个数。因此,最好使用函数 linspace 去接收我们想要的元素个数来代替用range来指定步长。

>>> A[1:,].take([1,3],axis=1)array([[ 5, 7], [ 9, 11]])

其它函数array, zeros, zeros_like, ones, ones_like, empty, empty_like, arange, linspace, rand, randn, fromfunction, fromfile参考: NumPy示例

或者我们仅仅使用A[1:,[1,3]]。还有一种方法是通过矩阵向量积(叉积)。

 

>>> A[ix_((1,2),(1,3))]array([[ 5, 7], [ 9, 11]])

打印数组

为了读者的方便,在次写下之前的矩阵:

当你打印一个数组,NumPy以类似嵌套列表的形式显示它,但是呈以下布局:

>>> A[ix_((1,2),(1,3))]array([[ 5, 7], [ 9, 11]])

  • 最后的轴从左到右打印
  • 次后的轴从顶向下打印
  • 剩下的轴从顶向下打印,每个切片通过一个空行与下一个隔开

现在让我们做些更复杂的。比如说我们想要保留第一行大于1的列。一种方法是创建布尔索引:

一维数组被打印成行,二维数组成矩阵,三维数组成矩阵列表。

>>> A[0,:]>1array([False, False, True, True], dtype=bool)>>> A[:,A[0,:]>1]array([[ 2, 3], [ 6, 7], [10, 11]])

>>> a = arange(6)                                 
>>> print(a)

就是我们想要的!但是索引矩阵没这么方便。

# 输出结果:(1d array
[0 1 2 3 4 5]

>>> M[0,:]>1matrix([[False, False, True, True]], dtype=bool)>>> M[:,M[0,:]>1]matrix([[2, 3]])

 

图片 36

>>> b = arange(12).reshape(4,3)        
>>> print(b)

技巧和提示

# 输出结果:(2d array
[[ 0 1 2]
[ 3 4 5]
[ 6 7 8]
[ 9 10 11]]

下面我们给出简短和有用的提示。

 

“自动”改变形状

>>> c = arange(24).reshape(2,3,4)      
>>> print(c)

更改数组的维度,你可以省略一个尺寸,它将被自动推导出来。

# 输出结果:(3d array
[[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]

>>> a = arange(30)>>> a.shape = 2,-1,3 # -1 means "whatever is needed">>> a.shape(2, 5, 3)>>> aarray([[[ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8], [ 9, 10, 11], [12, 13, 14]], [[15, 16, 17], [18, 19, 20], [21, 22, 23], [24, 25, 26], [27, 28, 29]]])

[[12 13 14 15]
[16 17 18 19]
[20 21 22 23]]]

图片 37

查看形状操作一节获得有关reshape的更多细节

图片 38

如果一个数组用来打印太大了,NumPy自动省略中间部分而只打印角落

2 NumPy-快速处理数据

>>> print (arange(10000))

标准安装的Python中用列表(list)保存一组值,可以用来当作数组使用,不过由于列表的元素可以是任何对象,因此列表中所保存的是对象的指针。这样为了保存一个简单的[1,2,3],需要有3个指针和三个整数对象。对于数值运算来说这种结构显然比较浪费内存和CPU计算时间。

# 输出结果:
[ 0 1 2 ... 9997 9998 9999]

此外Python还提供了一个array模块,array对象和列表不同,它直接保存数值,和C语言的一维数组比较类似。但是由于它不支持多维,也没有各种运算函数,因此也不适合做数值运算。

 

NumPy的诞生弥补了这些不足,NumPy提供了两种基本的对象:ndarray(N-dimensional array object)和 ufunc(universal function object)。ndarray(下文统一称之为数组)是存储单一数据类型的多维数组,而ufunc则是能够对数组进行处理的函数。

>>> print (arange(10000).reshape(100,100))

图片 39

# 输出结果:
[[ 0 1 2 ... 97 98 99]
[ 100 101 102 ... 197 198 199]
[ 200 201 202 ... 297 298 299]
...
[9700 9701 9702 ... 9797 9798 9799]
[9800 9801 9802 ... 9897 9898 9899]
[9900 9901 9902 ... 9997 9998 9999]]

数组的大小可以通过其shape属性获得:

禁用NumPy的这种行为并强制打印整个数组,你可以设置printoptions参数来更改打印选项。

>>> a.shape(4,)>>> c.shape(3, 4)

set_printoptions(threshold='nan')

数组a的shape只有一个元素,因此它是一维数组。而数组c的shape有两个元素,因此它是二维数组,其中第0轴的长度为3,第1轴的长度为4。还可以通过修改数组的shape属性,在保持数组元素个数不变的情况下,改变数组每个轴的长度。下面的例子将数组c的shape改为(4,3),注意从(3,4)改为(4,3)并不是对数组进行转置,而只是改变每个轴的大小,数组元素在内存中的位置并没有改变:

 

图片 40

基本运算

数组的元素类型可以通过dtype属性获得。上面例子中的参数序列的元素都是整数,因此所创建的数组的元素类型也是整数,并且是32bit的长整型。可以通过dtype参数在创建时指定元素类型:

 

>>> np.array([[1, 2, 3, 4],[4, 5, 6, 7], [7, 8, 9, 10]], dtype=np.float)array([[ 1., 2., 3., 4.], [ 4., 5., 6., 7.], [ 7., 8., 9., 10.]])>>> np.array([[1, 2, 3, 4],[4, 5, 6, 7], [7, 8, 9, 10]], dtype=np.complex)array([[ 1. 0.j, 2. 0.j, 3. 0.j, 4. 0.j], [ 4. 0.j, 5. 0.j, 6. 0.j, 7. 0.j], [ 7. 0.j, 8. 0.j, 9. 0.j, 10. 0.j]])

数组的算术运算是按元素及其顺序进行的。新的数组被创建并且被结果填充。

上面的例子都是先创建一个Python序列,然后通过array函数将其转换为数组,这样做显然效率不高。因此NumPy提供了很多专门用来创建数组的函数。下面的每个函数都有一些关键字参数,具体用法请查看函数说明。

>>> a = array([20,30,40,50])
>>> b = arange(4)
>>> b
array([0, 1, 2, 3])
>>> c = a - b
>>> c
array([20, 29, 38, 47])
>>> b**2
array([0, 1, 4, 9], dtype=int32)
>>> 10*sin(a)
array([ 9.12945251, -9.88031624, 7.4511316 , -2.62374854])
>>> a < 35
array([ True, True, False, False])

arange函数类似于python的range函数,通过指定开始值、终值和步长来创建一维数组,注意数组不包括终值:

不像许多矩阵语言,NumPy中的乘法运算符 * 指示按元素计算,矩阵乘法可以使用 dot 函数或创建矩阵对象实现(参见教程中的矩阵章节)

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

>>> A = array([[1,1],
...                     [0,1]])
>>> B = array([[2,0],
...                     [3,4]])

linspace函数通过指定开始值、终值和元素个数来创建一维数组,可以通过endpoint关键字指定是否包括终值,缺省设置是包括终值:

>>> A*B
array([[2, 0],
           [0, 4]])

>>> np.linspace(0, 1, 12)array([ 0. , 0.09090909, 0.18181818, 0.27272727, 0.36363636, 0.45454545, 0.54545455, 0.63636364, 0.72727273, 0.81818182, 0.90909091, 1. ])

>>> dot(A,B)
array([[5, 4],
           [3, 4]])

logspace函数和linspace类似,不过它创建等比数列,下面的例子产生1(10^0)到100(10^2)、有20个元素的等比数列:

有些操作符像  = 和 *= 被用来更改已存在数组而不创建一个新的数组。

>>> np.logspace(0, 2, 20)array([ 1. , 1.27427499, 1.62377674, 2.06913808, 2.6366509 , 3.35981829, 4.2813324 , 5.45559478, 6.95192796, 8.8586679 , 11.28837892, 14.38449888, 18.32980711, 23.35721469, 29.76351442, 37.92690191, 48.32930239, 61.58482111, 78.47599704, 100. ])

>>> a = ones((2,3), dtype=int)
>>> b = random.random((2,3))
>>> a *= 3
>>> a
array([[3, 3, 3],
[3, 3, 3]])
>>> b = a
>>> b
array([[3.42638252, 3.61573799, 3.38830443],
[3.99384044, 3.81334296, 3.85276701]])
>>> a = b

图片 41

>>> a

图片 42

array([[6, 6, 6],

图片 43

       [6, 6, 6]])

使用布尔数组

当运算的是不同类型的数组时,结果数组和更普遍和精确的已知(这种行为叫做upcast)。

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

>>> a = ones(3, dtype=int32)
>>> b = linspace(0,pi,3)
>>> b.dtype.name
'float64'
>>> c = a b
>>> c
array([1. , 2.57079633, 4.14159265])
>>> c.dtype.name
'float64'
>>> d = exp(c*1j)
>>> d
array([ 0.54030231 0.84147098j, -0.84147098 0.54030231j,
-0.54030231-0.84147098j])
>>> d.dtype.name
'complex128'    # 许多非数组运算,如计算数组所有元素之和,被作为ndarray类的方法实现
>>> a = random.random((2,3))
>>> a
array([[0.28138224, 0.32397153, 0.9059845 ],
[0.24017656, 0.06064039, 0.70122219]])
>>> a.sum()
2.5133774156980775
>>> a.min()
0.0606403869957034
>>> a.max()
0.9059844988977899

图片 44

这些运算默认应用到数组好像它就是一个数字组成的列表,无关数组的形状。然而,指定 axis 参数你可以吧运算应用到数组指定的轴上:

.1.3 多维数组

>>> b = arange(12).reshape(3,4)
>>> b
array([[ 0, 1, 2, 3],
           [ 4, 5, 6, 7],
           [ 8, 9, 10, 11]])
>>> b.sum(axis=0)
array([12, 15, 18, 21])

图片 45

>>> b.min(axis=1)
array([0, 4, 8])
>>> b.cumsum(axis=1)
array([[ 0, 1, 3, 6],
   [ 4, 9, 15, 22],
   [ 8, 17, 27, 38]], dtype=int32)

多维数组的存取和一维数组类似,因为多维数组有多个轴,因此它的下标需要用多个值来表示,NumPy采用组元(tuple)作为数组的下标。如图2.1所示,a为一个6x6的数组,图中用颜色区分了各个下标以及其对应的选择区域。

 

组元不需要圆括号

通用函数(ufunc)

虽然我们经常在Python中用圆括号将组元括起来,但是其实组元的语法定义只需要用逗号隔开即可,例如 x,y=y,x 就是用组元交换变量值的一个例子。

 

图片 46

NumPy提供常见的数学函数如 sin , cos 和 exp 。在NumPy中,这些叫作“通用函数”(ufunc)。在NumPy里这些函数作用按数组的元素运算,产生一个数组作为输出。

图片 47

>>> B = arange(3)
>>> B
array([0, 1, 2])
>>> exp(B)
array([1. , 2.71828183, 7.3890561 ])
>>> sqrt(B)
array([0. , 1. , 1.41421356])
>>> C = array([2.,-1.,4.])
>>> add(B,C)
array([2., 0., 6.])

图片 48

更多函数all, alltrue, any, apply along axis, argmax, argmin, argsort, average, bincount, ceil, clip, conj, conjugate, corrcoef, cov, cross, cumprod, cumsum, diff, dot, floor, inner, inv, lexsort, max, maximum, mean, median, min, minimum, nonzero, outer, prod, re, round, sometrue, sort, std, sum, trace, transpose, var, vdot, vectorize, where 参见: NumPy示例

a[(0,1,2,3,4),(1,2,3,4,5)] : 用于存取数组的下标和仍然是一个有两个元素的组元,组元中的每个元素都是整数序列,分别对应数组的第0轴和第1轴。从两个序列的对应位置取出两个整数组成下标: a[0,1], a[1,2], ..., a[4,5]。

 

a[3:, [0, 2, 5]] : 下标中的第0轴是一个范围,它选取第3行之后的所有行;第1轴是整数序列,它选取第0, 2, 5三列。

索引,切片和迭代

a[mask, 2] : 下标的第0轴是一个布尔数组,它选取第0,2,5行;第1轴是一个整数,选取第2列。

 

2.1.4 结构数组

一维 数组可以被索引、切片和迭代,就像 列表 和其它Python序列。

图片 49

>>> a = arange(10)**3
>>> a
array([ 0, 1, 8, 27, 64, 125, 216, 343, 512, 729], dtype=int32)
>>> a[2]
8
>>> a[2:5]
array([ 8, 27, 64], dtype=int32)
>>> a[:6:2] = -1000
>>> a
array([-1000, 1, -1000, 27, -1000, 125, 216, 343, 512,
729], dtype=int32)
>>> a[ : :-1]
array([ 729, 512, 343, 216, 125, -1000, 27, -1000, 1,
-1000], dtype=int32)
>>> for i in a:
print (i**(1/3.))

在C语言中我们可以通过struct关键字定义结构类型,结构中的字段占据连续的内存空间,每个结构体占用的内存大小都相同,因此可以很容易地定义结构数组。和C语言一样,在NumPy中也很容易对这种结构数组进行操作。只要NumPy中的结构定义和C语言中的定义相同,NumPy就可以很方便地读取C语言的结构数组的二进制数据,转换为NumPy的结构数组。

nan
1.0
nan
3.0
nan
4.999999999999999
5.999999999999999
6.999999999999999
7.999999999999999
8.999999999999998

假设我们需要定义一个结构数组,它的每个元素都有name, age和weight字段。在NumPy中可以如下定义

多维 数组可以每个轴有一个索引。这些索引由一个逗号分割的元组给出。

图片 50

>>>def f(x,y):
...         return 10*x y

图片 51

>>> b = fromfunction(f,(5,4),dtype=int)
>>> b
array([[ 0, 1, 2, 3],
   [10, 11, 12, 13],
   [20, 21, 22, 23],
   [30, 31, 32, 33],
   [40, 41, 42, 43]])
>>> b[2,3]
23
>>> b[0:5,1]
array([ 1, 11, 21, 31, 41])
>>> b[1:3,:]
array([[10, 11, 12, 13],
   [20, 21, 22, 23]])

内存对齐

当少于轴数的索引被提供时,缺失的索引被认为是整个切片:

C语言的结构体为了内存寻址方便,会自动的添加一些填充用的字节,这叫做内存对齐。例如如果把下面的name[32]改为name[30]的话,由于内存对齐问题,在name和age中间会填补两个字节,最终的结构体大小不会改变。因此如果numpy中的所配置的内存大小不符合C语言的对齐规范的话,将会出现数据错位。为了解决这个问题,在创建dtype对象时,可以传递参数align=True,这样numpy的结构数组的内存对齐和C语言的结构体就一致了。

>>> b[-1]                        # the last row. Equivalent to b[-1,:]
array([40, 41, 42, 43])

图片 52

b[ i ] 中括号中的表达式被当作 i 和一系列 : ,来代表剩下的轴。NumPy也允许你使用“点”像 b[ i,... ] 。

用下面的字典参数也可以定义结构类型,字典的关键字为结构中字段名,值为字段的类型描述,但是由于字典的关键字是没有顺序的,因此字段的顺序需要在类型描述中给出,类型描述是一个组元,它的第二个值给出字段的字节为单位的偏移量,例如age字段的偏移量为25个字节:

点 (…)代表许多产生一个完整的索引元组必要的分号。如果x是秩为5的数组(即它有5个轴),那么:

>>> np.dtype({'surname':('S25',0),'age':(np.uint8,25)})dtype([('surname', '|S25'), ('age', '|u1')])

  • x[1,2,...] 等同于 x[1,2,:,:,:],
  • x[…,3] 等同于 x[:,:,:,:,3]
  • x[4,…,5,:] 等同 x[4,:,:,5,:]

2.1.5 内存结构

迭代 多维数组是就第一个轴而言的: 

图片 53

>>> for row in b:
...         print (row)

下面让我们来看看ndarray数组对象是如何在内存中储存的。如图2.3所示,关于数组的描述信息保存在一个数据结构中,这个结构引用两个对象:一块用于保存数据的存储区域和一个用于描述元素类型的dtype对象。

...
[0 1 2 3]
[10 11 12 13]
[20 21 22 23]
[30 31 32 33]
[40 41 42 43]

图片 54

然而,如果一个人想对每个数组中元素进行运算,我们可以使用flat属性,该属性是数组元素的一个迭代器:

图片 55

>>> for element in b.flat:
...          print (element)

图片 56

0
1
2
3
10
11
12
13
20
21
22
23
30
31
32
33
40
41
42
43

sin函数的第二个参数也是x,那么它所做的事情就是对x中的每给值求正弦值,并且把结果保存到x中的对应的位置中。此时函数的返回值仍然是整个计算的结果,只不过它就是x,因此两个变量的id是相同的(变量t和变量x指向同一块内存区域)。

更多[], …, newaxis, ndenumerate, indices, index exp 参考 NumPy示例

我用下面这个小程序,比较了一下numpy.math和Python标准库的math.sin的计算速度::

形状操作

图片 57

更改数组的形状

请注意numpy.sin的计算速度只有math.sin的1/5。这是因为numpy.sin为了同时支持数组和单个值的计算,其C语言的内部实现要比math.sin复杂很多,如果我们同样在Python级别进行循环的话,就会看出其中的差别了。此外,numpy.sin返回的数的类型和math.sin返回的类型有所不同,math.sin返回的是Python的标准float类型,而numpy.sin则返回一个numpy.float64类型:

 

图片 58

一个数组的形状由它每个轴上的元素个数给出:

由于Python的操作符重载功能,计算两个数组相加可以简单地写为a b,而np.add(a,b,a)则可以用a =b来表示。下面是数组的运算符和其对应的ufunc函数的一个列表,注意除号"/"的意义根据是否激活__future__.division有所不同。

>>> a = floor(10*random.random((3,4)))

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

>>> a

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

array([[5., 0., 5., 6.],
   [6., 2., 7., 9.],
   [3., 4., 2., 8.]])

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

>>> a.shape

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

(3, 4)

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

一个数组的形状可以被多种命令修改:

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

a.ravel()

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

array([5., 0., 5., 6., 6., 2., 7., 9., 3., 4., 2., 8.])

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

>>> a.shape = (6,2)

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

>>> a.transpose()

图片 59

array([[5., 5., 6., 7., 3., 2.],
   [0., 6., 2., 9., 4., 8.]])

图片 60

由 ravel() 展平的数组元素的顺序通常是“C风格”的,就是说,最右边的索引变化得最快,所以元素a[0,0]之后是a[0,1]。如果数组被改变形状(reshape)成其它形状,数组仍然是“C风格”的。NumPy通常创建一个以这个顺序保存数据的数组,所以 ravel() 将总是不需要复制它的参数 。但是如果数组是通过切片其它数组或有不同寻常的选项时,它可能需要被复制。函数 reshape() 和 ravel() 还可以被同过一些可选参数构建成FORTRAN风格的数组,即最左边的索引变化最快。

图片 61

reshape 函数改变参数形状并返回它,而 resize 函数改变数组自身。

图片 62

>>> a

值得注意的是用frompyfunc得到的函数计算出的数组元素的类型为object,因为frompyfunc函数无法保证Python函数返回的数据类型都完全一致。因此还需要再次 y2.astype(np.float64)将其转换为双精度浮点数组。

array([[5., 0.],
      [5., 6.],
      [6., 2.],
      [7., 9.],
   [3., 4.],
   [2., 8.]])
>>> a.resize((2,6))

2.2.1 广播

>>> a

图片 63

array([[5., 0., 5., 6., 6., 2.],
   [7., 9., 3., 4., 2., 8.]])

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

如果在改变形状操作中一个维度被给做-1,其维度将自动被计算

让所有输入数组都向其中shape最长的数组看齐,shape中不足的部分都通过在前面加1补齐

更多 shape, reshape, resize, ravel 参考 NumPy示例

输出数组的shape是输入数组shape的各个轴上的最大值

 

如果输入数组的某个轴和输出数组的对应轴的长度相同或者其长度为1时,这个数组能够用来计算,否则出错

组合(stack)不同的数组

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

 

上述4条规则理解起来可能比较费劲,让我们来看一个实际的例子。

几种方法可以沿不同轴将数组堆叠在一起:

先创建一个二维数组a,其shape为(6,1):

>>> a = floor(10*random.random((2,2)))

图片 64

>>> a

这样加法运算的两个输入数组的shape分别为(6,1)和(1,5),根据规则2,输出数组的各个轴的长度为输入数组各个轴上的长度的最大值,可知输出数组的shape为(6,5)。

array([[8., 4.],
   [0., 9.]])

由于b的第0轴上的长度为1,而a的第0轴上的长度为6,因此为了让它们在第0轴上能够相加,需要将b在第0轴上的长度扩展为6,这相当于:

>>> b = floor(10*random.random((2,2)))

图片 65

>>> b

ogrid是一个很有趣的对象,它像一个多维数组一样,用切片组元作为下标进行存取,返回的是一组可以用来广播计算的数组。其切片下标有两种形式:

array([[6., 6.],
   [4., 0.]])

开始值:结束值:步长,和np.arange(开始值, 结束值, 步长)类似

>>> vstack((a,b))

开始值:结束值:长度j,当第三个参数为虚数时,它表示返回的数组的长度,和np.linspace(开始值, 结束值, 长度)类似:

array([[8., 4.],
   [0., 9.],
   [6., 6.],
   [4., 0.]])

图片 66

>>> hstack((a,b))

图片 67

array([[8., 4., 6., 6.],
   [0., 9., 4., 0.]])

.2.2 ufunc的方法

函数 column_stack 以列将一维数组合成二维数组,它等同与 vstack 对一维数组。

图片 68

>>> column_stack((a,b))

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

array([[8., 4., 6., 6.],
   [0., 9., 4., 0.]])

reduce 方法和Python的reduce函数类似,它沿着axis轴对array进行操作,相当于将运算符插入到沿axis轴的所有子数组或者元素当中。

>>> a = array([4.,2.])

.reduce (array=, axis=0, dtype=None)

>>> b = array([2.,8.])

例如:

>>> a[:,newaxis]

图片 69

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

if indices[i] < indices[i 1]:result[i] = np.reduce(a[indices[i]:indices[i 1]])else:result[i] = a[indices[i]

>>> column_stack((a[:,newaxis],b[:,newaxis]))

而最后一个元素如下计算:

array([[4., 2.],
   [2., 8.]])

np.reduce(a[indices[-1]:])

>>> vstack((a[:,newaxis],b[:,newaxis]))

因此上面例子中,结果的每个元素如下计算而得:

array([[4.],
   [2.],
   [2.],
   [8.]])

图片 70

row_stack 函数,另一方面,将一维数组以行组合成二维数组。

2.3 矩阵运算

对那些维度比二维更高的数组, hstack 沿着第二个轴组合, vstack 沿着第一个轴组合, concatenate 允许可选参数给出组合时沿着的轴。

图片 71

注意:

NumPy和Matlab不一样,对于多维数组的运算,缺省情况下并不使用矩阵运算,如果你希望对数组进行矩阵运算的话,可以调用相应的函数。

在复杂情况下, r_[] 和 c_[] 对创建沿着一个方向组合的数很有用,它们允许范围符号(“:”)。

matrix对象

>>> r_[1:4,0,4]

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

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

图片 72

当使用数组作为参数时, r_ 和 c_ 的默认行为和 vstack 和 hstack 很像,但是允许可选的参数给出组合所沿着的轴的代号。

图片 73

更多函数hstack , vstack, column_stack , row_stack , concatenate , c_ , r_ 参见 NumPy示例 。

图片 74

 

图片 75

将一个数组分割(split)成几个小数组

图片 76

 

图片 77

使用 hsplit 你能将数组沿着它的水平轴分割,或者指定返回相同形状数组的个数,或者指定在哪些列后发生分割:

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

>>> a = floor(10*random.random((2,12)))

图片 78

>>> a

图片 79

array([[9., 5., 9., 8., 6., 7., 6., 5., 0., 7., 6., 3.],
         [4., 3., 8., 1., 4., 5., 1., 0., 5., 7., 4., 1.]])

图片 80

>>> hsplit(a,3)

[array([[9., 5., 9., 8.],
          [4., 3., 8., 1.]]), array([[6., 7., 6., 5.],
          [4., 5., 1., 0.]]), array([[0., 7., 6., 3.],
          [5., 7., 4., 1.]])]

>>> hsplit(a,(3,4))

[array([[9., 5., 9.],
          [4., 3., 8.]]), array([[8.],
          [1.]]), array([[6., 7., 6., 5., 0., 7., 6., 3.],
          [4., 5., 1., 0., 5., 7., 4., 1.]])]

vsplit 沿着纵向的轴分割, array split 允许指定沿哪个轴分割。

 

复制和视图

 

当运算和处理数组时,它们的数据有时被拷贝到新的数组有时不是。这通常是新手的困惑之源。这有三种情况:

完全不拷贝

简单的赋值不拷贝数组对象或它们的数据。

>>> a = arange(12)

>>> b = a                 # no new object is created

>>> b is a                # a and b are two names for the same ndarray object

True

>>> b.shape = 3,4   # changes the shape of a

>>> a.shape

(3, 4)

Python 传递不定对象作为参考 ,所以函数调用不拷贝数组。

>>> def f(x):
print (id(x))

>>> id(a)
90965360

>>> f(a)
90965360

视图(view)和浅复制

不同的数组对象分享同一个数据。视图方法创造一个新的数组对象指向同一数据。

>>> c = a.view()
>>> c is a

False

>>> c.base is a               # c is a view of the data owned by a
True

>>> c.flags.owndata
False

>>> c.shape = 2,6          # a's shape doesn't change

>>> a.shape

(3, 4)

>>> c[0,4] = 1234          # a's data changes
>>> a

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

切片数组返回它的一个视图:

>>> s = a[ : , 1:3]
>>> s[:] = 10
>>> a

array([[ 0, 10, 10, 3],
   [1234, 10, 10, 7],
   [ 8, 10, 10, 11]])

深复制

这个复制方法完全复制数组和它的数据。

>>> d = a.copy()
>>> d is a

False

>>> d[0,0] = 9999
>>> a

array([[ 0, 10, 10, 3],
   [1234, 10, 10, 7],
   [ 8, 10, 10, 11]])

函数和方法(method)总览

这是个NumPy函数和方法分类排列目录。这些名字链接到 NumPy示例 ,你可以看到这些函数起作用。

创建数组

arange, array, copy, empty, empty_like, eye, fromfile, fromfunction, identity, linspace, logspace, mgrid, ogrid, ones, ones_like, r , zeros, zeros_like

转化

astype, atleast 1d, atleast 2d, atleast 3d, mat

操作

array split, column stack, concatenate, diagonal, dsplit, dstack, hsplit, hstack, item, newaxis, ravel, repeat, reshape, resize, squeeze, swapaxes, take, transpose, vsplit, vstack

询问

all, any, nonzero, where

排序

argmax, argmin, argsort, max, min, ptp, searchsorted, sort

本文由67677新澳门手机版发布于计算机编程,转载请注明出处:整理的NumPy详细教程

关键词: