一次性搞定NumPy入门基础知识

系列文章

一次性搞定NumPy入门基础知识
NumPy之操控ndarray的形状
NumPy之浅拷贝和深拷贝
NumPy之索引技巧

1. 基本数据结构

NumPy最核心的数据结构就是所谓的多维数组(ndarray, n-dimensional array)。这里,所谓的“维度”,指的是数据嵌套的层数,每一层叫做一个axis。

例如:

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

这个ndarray嵌套了两层,所以这个ndarray有两个axis,第一个axis的length是2(因为这一个axis有两个元素,分别是[1., 0., 0.][0., 1., 2.]),第二个axis的length是3(因为[1., 0., 0.][0., 1., 2.]均分别有三个元素。

下面的例子显示了NumPy数据结构的几个重要属性:

>>> import numpy as np
>>> a = np.arange(15).reshape(3, 5)
>>>a
array([[ 0,  1,  2,  3,  4], 
          [ 5,  6,  7,  8,  9],       
          [10, 11, 12, 13, 14]])
 >>> a.shape
 (3, 5)
 >>> a.ndim
 2
 >>> a.dtype.name
 'int64'
 >>> a.itemsize
 8
 >>> a.size
 15
 >>> type(a)
 <type 'numpy.ndarray'>
 
 >>> b = np.array([6, 7, 8])
 >>> b
 array([6, 7, 8])
 >>> type(b)
 <type 'numpy.ndarray'>

1.1 ndarray.ndim

ndarray的维数,也就是axis的数量,上述例子中是2

1.2 ndarray.shape

这是一个tuple类型的数据,每一个元素代表了每一个维度的长度。上述例子是(3, 5)

1.3 ndarray.size

ndarray里元素的总个数,上述例子是15

1.4 ndarray.dtype

ndarray里元素的数据类型,上述例子是int64

1.5 ndarray.itemsize

ndarray里每个元素占据的字节数,上述例子是8

2. 创建ndarray

通过np.array函数,可以创建一个ndarray结构,入参可以有多种形式,如下面各节所述。

2.1 从Python的list或tuple数据结构创建

如下例所示,从Python的list创建ndarray结构,并且NumPy可以自动判断数据类型:

>>> import numpy as np

>>> a = np.array([2,3,4])
>>> a
array([2, 3, 4])
>>> a.dtype
dtype('int64')

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

要注意的是,传递的是一个list或tuple,而不是数字参数,例如a = np.array(2,3,4)就是错误的。

通过传递嵌套的list结构,可以创建N维ndarray:

>>> b = np.array([(1.5,2,3), (4,5,6)])
>>> b
array([[ 1.5,  2. ,  3. ],
        [ 4. ,  5. ,  6. ]])

在创建ndarray时,可以显式地指定数据类型:


>>> c = np.array( [ [1,2], [3,4] ], dtype=complex )
>>> c
array([[ 1.+0.j,  2.+0.j],
        [ 3.+0.j,  4.+0.j]])

2.2 通过内建函数创建

内建ndarray创建函数可以为一些特定的场景提供方便。
zeros()函数创建一个全为0的ndarray,ones()创建一个全为1的ndarray,empty()创建一个内容随机的ndarray:

>>> np.zeros( (3,4) )
array([[ 0.,  0.,  0.,  0.],       
          [ 0.,  0.,  0.,  0.],       
          [ 0.,  0.,  0.,  0.]])

>>> np.ones( (2,3,4), dtype=np.int16 ) 
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)
          
>>> np.empty( (2,3) ) 
array([[  3.73603959e-262,   6.02658058e-154,   6.55490914e-260],      
           [  5.30498948e-313,   3.14673309e-307,   1.00000000e+000]])

NumPy提供arange()函数来创建数字序列,与Python的arange对比,NumPy提供的arange()函数可以用浮点数来表示间隔:


#arange()函数的参数分别为起始值、终值、步长
#生成的序列包括起始值,不包括终值
>>> np.arange( 10, 30, 5 )
array([10, 15, 20, 25])

>>> np.arange( 0, 2, 0.3 )
array([ 0. ,  0.3,  0.6,  0.9,  1.2,  1.5,  1.8])

arange()函数支持浮点,但这样做,由于精度的原因,难以预测最终的序列有多少个元素,这时候用linspace()函数更好,可以指定起止范围和序列的大小:

>>> from numpy import pi

#l inspcae参数分别为起始值、终值、序列长度
# 生成的序列默认包括起始值和终值
# 可以通过endpoint参数指定是否包含终值,默认值为True,即包含终值。
>>> np.linspace( 0, 2, 9 ) 
array([ 0.  ,  0.25,  0.5 ,  0.75,  1.  ,  1.25,  1.5 ,  1.75,  2.  ])

>>> x = np.linspace( 0, 2*pi, 100 ) 
>>> f = np.sin(x)

3. 打印ndarray

ndarray的打印符合如下原则:

  • 最后一个axis的内容从左到右打印
  • 倒数第二个axis的内容从上到下打印
  • 其他axis的内容也是从上到下打印,中间通过空行进行分隔

>>> a = np.arange(24).reshape(2,3,4)
>>> print(a)
[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]

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

如果ndarray内容太多,NumPy会自动省略中间的内容,只保留边角的内容


>>> print(np.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]]

如果想打印全部内容,可以通过下面的语句修改打印选项:

>>> np.set_printoptions(threshold=sys.maxsize)       # 需要引入sys模块

4. ndarray的基本操作

数学运算符是元素级的,两个ndarray进行运算,会产生一个新的ndarray。

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

要注意的是,在NumPy里,*是元素级的互相相乘。而矩阵乘法则需要使用@运算符。或者dot函数或方法。

>>> A = np.array( [[1,1],
...                          [0,1]] )
>>> B = np.array( [[2,0],
...                          [3,4]] )
>>> A * B                       # elementwise product
array([[2, 0],
       [0, 4]])
>>> A @ B                       # matrix product
array([[5, 4],
       [3, 4]])
>>> A.dot(B)                    # another matrix product
array([[5, 4],
       [3, 4]]) 

类似于+=*=这种运算符,可以直接修改现有的ndarray,而不是再新建一个。

>>> a = np.ones((2,3), dtype=int)
>>> b = np.random.random((2,3))
>>> a *= 3
>>> a
array([[3, 3, 3],
       [3, 3, 3]])
>>> b += a
>>> b
array([[ 3.417022  ,  3.72032449,  3.00011437],
       [ 3.30233257,  3.14675589,  3.09233859]])
>>> a += b                  # 注意,b的精度更高,无法累加到精度较低的ndarray a上
Traceback (most recent call last):
  ...
TypeError: Cannot cast ufunc add output from dtype('float64') to dtype('int64') with casting rule 'same_kind'    

如果两个不同精度的ndarray进行运算,得到的结果的类型与二者中精度更高的ndarray相同

>>> a = np.ones(3, dtype=np.int32)
>>> b = np.linspace(0,pi,3)
>>> b.dtype.name
'float64'
>>> c = a+b
>>> c
array([ 1.        ,  2.57079633,  4.14159265])
>>> c.dtype.name
'float64'

>>> d = np.exp(c*1j)
>>> d
array([ 0.54030231+0.84147098j, -0.84147098+0.54030231j,
       -0.54030231-0.84147098j])
>>> d.dtype.name
'complex128'    

NumPy支持一些单目运算符,单目运算符通常作为ndarray类的内建方法来使用:

>>> a = np.random.random((2,3))
>>> a
array([[ 0.18626021,  0.34556073,  0.39676747],
       [ 0.53881673,  0.41919451,  0.6852195 ]])
>>> a.sum()
2.5718191614547998
>>> a.min()
0.1862602113776709
>>> a.max()
0.6852195003967595   

上述操作默认是针对ndarray中的所有元素的,并不考虑ndarray的形状。如果指定axis参数,可以指定沿着哪个axis来进行运算。也就是说,保持其他axis不变,在这个axis上进行运算。

可以这么来理解axis参数的用法:以二维ndarray为例,由于axis代表嵌套的层数,假设ndarray的shape是(3, 4),那么可以将ndarray排布如下:

(a[0]0], a[0][1], a[0][2], a[0][3]
   a[1]0], a[1][1], a[1][2], a[1][3]
   a[2]0], a[2][1], a[2][2], a[2][3])

所谓沿着axis=0的方向进行sum运算,就是指沿着第一个索引的方向,分别做如下运算(保持第二个索引不变):

(a[0]0] + a[1][0] + a[2][0], a[0]1] + a[1][1] + a[2][1], a[0]2] + a[1][2] + a[2][2], a[0][3] + a[1][3] + a[2][3], )

下面是代码示例:

>>> b = np.arange(12).reshape(3,4)
>>> b
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
>>>
>>> b.sum(axis=0)                            # sum of each column
array([12, 15, 18, 21])
>>>
>>> b.min(axis=1)                            # min of each row
array([0, 4, 8])
>>>
>>> b.cumsum(axis=1)                         # cumulative sum along each row
array([[ 0,  1,  3,  6],
       [ 4,  9, 15, 22],
       [ 8, 17, 27, 38]])  

5. 通用函数(Universal Functions)

NumPy支持一些通用的数学函数,例如sin,cos,exp等等。这些函数叫做Universal Functions(ufunc)。这些函数都是元素级的,并会产生一个新的ndarray作为输出。

举例如下:

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

6.索引、切片与遍历

一维ndarray的相关操作和Python中的list数据结构相似:

>>> a = np.arange(10)**3
>>> a
array([  0,   1,   8,  27,  64, 125, 216, 343, 512, 729])
>>> a[2]
8
>>> a[2:5]
array([ 8, 27, 64])
>>> a[:6:2] = -1000    # 在0-6号元素中,循环地将每个排序为2的元素设置为-1000
>>> a
array([-1000,     1, -1000,    27, -1000,   125,   216,   343,   512,   729])
>>> a[ : :-1]    # 得到一个逆序的ndarray
array([  729,   512,   343,   216,   125, -1000,    27, -1000,     1, -1000])
>>> for i in a:
...     print(i**(1/3.))
...
nan
1.0
nan
3.0
nan
5.0
6.0
7.0
8.0
9.0 

多维ndarray每个axis都有一个独立的索引,把这些独立索引合成到一个tuple里,就可以对多维ndarray进行索引了。

>>> def f(x,y):
...     return 10*x+y
...
>>> b = np.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]                        
array([ 1, 11, 21, 31, 41])

>>> b[1:3, : ]                      
array([[10, 11, 12, 13],
       [20, 21, 22, 23]])  

下面这种写法,自动补全后面缺失的索引:


>>> b[-1]   #相当于b[-1, :]
array([40, 41, 42, 43])

可以用...来代替一系列的:
例如,假设x是一个由5个axis的ndarray,那么

  • x[1, 2, ...]等价于x[1, 2, :, : ,:]
  • x[..., 3]等价于[:, :, :, :, 3]
  • x[4, .., 5, :]等价于x[4, :, :, 5, :]
    举例:
>>> c = np.array( [[[  0,  1,  2],             
...                 [ 10, 12, 13]],
...                [[100,101,102],
...                 [110,112,113]]])
>>> c.shape
(2, 2, 3)
>>> c[1,...]                                   
array([[100, 101, 102],
       [110, 112, 113]])
>>> c[...,2]                                   
array([[  2,  13],
       [102, 113]]) 

多维ndarray的遍历时沿着第一个axis进行的:

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

推荐阅读更多精彩内容

  • 基础篇NumPy的主要对象是同种元素的多维数组。这是一个所有的元素都是一种类型、通过一个正整数元组索引的元素表格(...
    oyan99阅读 5,115评论 0 18
  • NumPy是Python中关于科学计算的一个类库,在这里简单介绍一下。 来源:https://docs.scipy...
    灰太狼_black阅读 1,224评论 0 5
  • 先决条件 在阅读这个教程之前,你多少需要知道点python。如果你想从新回忆下,请看看Python Tutoria...
    舒map阅读 2,570评论 1 13
  • 一、numpy概述 numpy(Numerical Python)提供了python对多维数组对象的支持:ndar...
    L_steven的猫阅读 3,461评论 1 24
  • Numpy的组成与功能 Numpy(Numeric Python)可以被理解为一个用python实现的科学计算包,...
    不做大哥好多年阅读 4,276评论 0 10