Python NumPy教程

基础篇

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

例如,在3D空间一个点的坐标[1, 2, 3]是一个秩为1的数组,因为它只有一个轴。那个轴长度为3.又例如,在以下例子中,数组的秩为2(它有两个维度).第一个维度长度为2,第二个维度长度为3.

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

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

  • ndarray.ndim
    数组轴的个数,在python的世界中,轴的个数被称为秩
  • ndarray.shape
    数组的维度。这是一个指示数组在每个维度上大小的整数元组。例如一个n排m列的矩阵,它的shape属性将是(2,3),这个元组的长度显然是秩,即维度或者ndim属性
  • ndarray.size
    数组元素的总个数,等于shape属性中元组元素的乘积。
  • ndarray.dtype
    一个用来描述数组中元素类型的对象,可以通过创造或指定dtype使用标准Python类型。另外NumPy提供它自己的数据类型。
  • ndarray.itemsize
    数组中每个元素的字节大小。例如,一个元素类型为float64的数组itemsiz属性值为8(=64/8),又如,一个元素类型为complex32的数组item属性为4(=32/8).
  • ndarray.data
    包含实际数组元素的缓冲区,通常我们不需要使用这个属性,因为我们总是通过索引来使用数组中的元素。

栗子:

In [2]: from  numpy  import * 

In [3]: a = arange(15).reshape(3,5)

In [4]: a
Out[4]: 
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14]])

In [5]: a.shape 
Out[5]: (3, 5)

In [6]: a.ndim
Out[6]: 2

In [7]: a.dtype.name 
Out[7]: 'int64'

In [8]: a.itemsize
Out[8]: 8

In [9]: a.size
Out[9]: 15

In [10]: type(a) 
Out[10]: numpy.ndarray

In [11]: b = array([6,7,8])

In [12]: b
Out[12]: array([6, 7, 8])

In [13]: type(b) 
Out[13]: numpy.ndarray

创建数组

有好几种创建数组的方法
例如,你可以使用array函数从常规的Python列表个元组创建数组。所创建的数组类型由原序列中的元素类型推导而来。

In [14]: from  numpy import * 

In [15]: a = array([2,3,4])

In [16]: a
Out[16]: array([2, 3, 4])

In [17]: a.dtype
Out[17]: dtype('int64')

In [18]: b = array([1.2,3.5,5.1]) 

In [19]: b.dtype
Out[19]: dtype('float64')

一个常见的错误包括用多个数值参数调用array而不是提供一个由数值组成的列表作为一个参数。

In [20]: a = array(1,2,3,4) 
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-20-79e204e243c8> in <module>()
----> 1 a = array(1,2,3,4)

ValueError: only 2 non-keyword arguments accepted

In [21]: a = array([1,2,3,4]) 

数组将序列包含序列转化成二维的数组,序列包含序列包含序列转化成三维数组等等。

In [22]: b = array([(1.5,2,3),(4,5,6)]) 

In [23]: b
Out[23]: 
array([[ 1.5,  2. ,  3. ],
       [ 4. ,  5. ,  6. ]])

数组类型可以在创建时显示指定

In [24]: c = array([[1,2],[3,4]],dtype=complex)

In [25]: c
Out[25]: 
array([[ 1.+0.j,  2.+0.j],
       [ 3.+0.j,  4.+0.j]])

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

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

In [26]: zeros( (3,4) )
Out[26]: 
array([[ 0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.]])

In [27]: ones( (2,3,4), dtype=int16 ) 
Out[27]: 
array([[[1, 1, 1, 1],
        [1, 1, 1, 1],
        [1, 1, 1, 1]],

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

In [28]: empty( (2,3) )
Out[28]: 
array([[ 0.,  0.,  0.],
       [ 0.,  0.,  0.]])

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

In [29]: arange(10,30,5) 
Out[29]: array([10, 15, 20, 25])

In [30]: arange(0,2,0.3)    # it accepts float arguments
Out[30]: array([ 0. ,  0.3,  0.6,  0.9,  1.2,  1.5,  1.8])

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

打印数组

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

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

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

In [31]: a = arange(6) 

In [32]: print(a) 
[0 1 2 3 4 5]

In [33]: b = arange(12).reshape(4,3) 

In [34]: print(b) 
[[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]]

In [35]: c = arange(24).reshape(2,3,4) 

In [36]: print(c) 
[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]

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

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

In [37]: print(arange(10000))
[   0    1    2 ..., 9997 9998 9999]

In [38]: print(arange(10000).reshape(100,100))
[[   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]]

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

>>> set_printoptions(threshold='nan') 

基本运算

数组的算数运算是按元素的。新的数组被创建,并且被结果填充

In [1]: from numpy import  * 

In [2]: a = array([20,30,40,50]) 

In [3]: b = arange(4) 

In [4]: b 
Out[4]: array([0, 1, 2, 3])

In [5]: c = a - b 

In [6]: c 
Out[6]: array([20, 29, 38, 47])

In [7]: b**2
Out[7]: array([0, 1, 4, 9])

In [8]: 10*sin(a) 
Out[8]: array([ 9.12945251, -9.88031624,  7.4511316 , -2.62374854])

In [9]: a<35
Out[9]: array([ True,  True, False, False], dtype=bool)

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

In [10]: A = array([[1,1],[0,1]]) 

In [11]: B = array([[2,0],[3,4]]) 

In [12]: A*B
Out[12]: 
array([[2, 0],
       [0, 4]])

In [13]: dot(A,B) 
Out[13]: 
array([[5, 4],
       [3, 4]])

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

In [14]: a = ones((2,3),dtype=int)

In [15]: a
Out[15]: 
array([[1, 1, 1],
       [1, 1, 1]])

In [16]: b = random.random((2,3))

In [17]: b
Out[17]: 
array([[ 0.59203579,  0.33035089,  0.77216489],
       [ 0.57561703,  0.73380547,  0.10118917]])

In [18]: a *=3

In [19]: a
Out[19]: 
array([[3, 3, 3],
       [3, 3, 3]])

In [20]: b += a 

In [21]: b
Out[21]: 
array([[ 3.59203579,  3.33035089,  3.77216489],
       [ 3.57561703,  3.73380547,  3.10118917]])

In [22]: a += b 
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-22-368d0b76b60a> in <module>()
----> 1 a += b

TypeError: Cannot cast ufunc add output from dtype('float64') to dtype('int64') with casting rule 'same_kind'

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

In [24]: a = ones(3,dtype=int32)

In [25]: b = linspace(0,pi,3)

In [26]: b.dtype.name
Out[26]: 'float64'

In [27]: c = a + b 

In [28]: c 
Out[28]: array([ 1.        ,  2.57079633,  4.14159265])

In [29]: c.dtype.name
Out[29]: 'float64'

In [30]: d = exp(c*1j) 

In [31]: d 
Out[31]: 
array([ 0.54030231+0.84147098j, -0.84147098+0.54030231j,
       -0.54030231-0.84147098j])

In [32]: d.dtype.name
Out[32]: 'complex128'
'complex128' 许多非数组运算,如计算数组所有元素之和,被作为ndarray类的方法实现

In [33]: a = random.random((2,3))

In [34]: a
Out[34]: 
array([[ 0.47405377,  0.3554812 ,  0.77247355],
       [ 0.28015991,  0.28447145,  0.27666715]])

In [35]: a.sum()
Out[35]: 2.4433070197253133

In [36]: a.min()
Out[36]: 0.27666714728871389

In [37]: a.max()
Out[37]: 0.77247354602573004

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

In [38]: b = arange(12).reshape(3,4) 

In [39]: b
Out[39]: 
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

In [40]: b.sum(axis=0)   # sum of each column
Out[40]: array([12, 15, 18, 21])

In [41]: b.min(axis=1)   # min of each row
Out[41]: array([0, 4, 8])

In [42]: b.cumsum(axis=1)   # cumulative sum along each rowOut[42]: 
array([[ 0,  1,  3,  6],
       [ 4,  9, 15, 22],
       [ 8, 17, 27, 38]])

通用函数(ufunc)

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

In [43]: B = arange(3) 

In [44]: B 
Out[44]: array([0, 1, 2])

In [45]: exp(B) 
Out[45]: array([ 1.        ,  2.71828183,  7.3890561 ])

In [46]: sqrt(B) 
Out[46]: array([ 0.        ,  1.        ,  1.41421356])

In [47]: C = array([2.,-1,4.]) 

In [48]: add(B,c) 
Out[48]: array([ 1.        ,  3.57079633,  6.14159265])

更多函数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 参见:<a href=http://scipy.org/Numpy_Example_List>[NumPy示例]</a>

索引,切片和迭代

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

In [49]: a = arange(10)**3 

In [50]: a 
Out[50]: array([  0,   1,   8,  27,  64, 125, 216, 343, 512, 729])

In [51]: a[2] 
Out[51]: 8

In [52]: a[2:5] 
Out[52]: array([ 8, 27, 64])

In [53]: a[:6:2] = -1000 

In [54]: a 
Out[54]: array([-1000,     1, -1000,    27, -1000,   125,   216,   343,   512,   729])

In [55]: a[::-1]
Out[55]: array([  729,   512,   343,   216,   125, -1000,    27, -1000,     1, -1000])

In [56]: for i in a:
    ...:     print(i**(1/3.),)
    ...:     
/usr/local/bin/ipython:2: RuntimeWarning: invalid value encountered in power
  
nan
1.0
nan
3.0
nan
5.0
6.0
7.0
8.0
9.0

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

In [57]: def f(x,y):
    ...:     return 10*x + y 
    ...: 

In [58]: b = fromfunction(f,(5,4),dtype=int)

In [59]: b
Out[59]: 
array([[ 0,  1,  2,  3],
       [10, 11, 12, 13],
       [20, 21, 22, 23],
       [30, 31, 32, 33],
       [40, 41, 42, 43]])

In [60]: b[2,3] 
Out[60]: 23

In [61]: b[0:5,1]      # each row in the second column of b
Out[61]: array([ 1, 11, 21, 31, 41])

In [62]: b[ : ,1]     # equivalent to the previous example
Out[62]: array([ 1, 11, 21, 31, 41])

In [63]: b[1:3,:]    # each column in the second and third row of b
Out[63]: 
array([[10, 11, 12, 13],
       [20, 21, 22, 23]])

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

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

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

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

  • x[1,2,…] 等同于 x[1,2,:,:,:],
  • x[…,3] 等同于 x[:,:,:,:,3]
  • x[4,…,5,:] 等同 x[4,:,:,5,:].
 >>> c = array( [ [[ 0, 1, 2], # a 3D array (two stacked 2D arrays) ... [ 10, 12, 13]], ... ... [[100,101,102], ... [110,112,113]] ] ) >>> c.shape (2, 2, 3) >>> c[1,...] # same as c[1,:,:] or c[1] array([[100, 101, 102], [110, 112, 113]]) >>> c[...,2] # same as c[:,:,2] array([[ 2, 13], [102, 113]]) 

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

In [65]: for row in b:
    ...:     print(row) 
    ...:     
[0 1 2 3]
[10 11 12 13]
[20 21 22 23]
[30 31 32 33]
[40 41 42 43]

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

In [67]: for element in b.flat:
    ...:     print(element)
    ...:      
0
1
2
3
10
11
12
13
20
21
22
23
30
31
32
33
40
41
42
43

更多[], …, newaxis, ndenumerate, indices, index exp 参考<a href=http://scipy.org/Numpy_Example_List a>[NumPy示例] </a>

形状操作

更改数组
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,898评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,401评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,058评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,539评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,382评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,319评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,706评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,370评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,664评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,715评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,476评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,326评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,730评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,003评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,275评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,683评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,877评论 2 335

推荐阅读更多精彩内容