官术网_书友最值得收藏!

1.2 NumPy

前面已經安裝了NumPy。現在我來介紹一下NumPy的一些基本概念和運算方法。你如果有興趣,也可以自行查找完整的技術手冊。

啟動Python,嘗試執行以下代碼:

>>> import numpy as np
>>> np.__version__
'1.16.2'

第一行代碼導入numpy模塊并將其重命名為np。這種用簡稱來重命名模塊的方式雖然不是必需的,卻幾乎成了通用做法。第二行代碼則輸出版本號,以確保安裝的NumPy版本滿足前面所說的最低要求。

1.2.1 定義數組

NumPy以數組為運算對象,它可以方便地將列表轉換為數組。想想看,與C和Java等語言中的數組類型相比,Python中的列表類型雖然使用起來非常優雅,但是當使用列表模擬數組進行科學計算的時候,效率還是非常低的。NumPy在這方面很有優勢,使用NumPy的數組類型時實際上效率很高。下面的例子首先把列表轉換為數組,然后展示了一些數組屬性:

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

上面的例子將一個包含4個元素的列表傳給了np.array函數,得到一個NumPy數組。數組最基本的屬性包括size和shape。這個數組的size屬性為4,表示包含4個元素;shape屬性則是包含4的一個元組,表示這是一個包含4個元素的一維數組或者說一維向量。如果數組是二維的,那么其shape屬性將包含兩個元素,分別對應每一維的大小。在下面的例子中,數組b的shape屬性為(2, 4),這表示它是一個2行4列的數組。

>>> b = np.array([[1,2,3,4],[5,6,7,8]])
>>> print(b)
[[1 2 3 4]
 [5 6 7 8]]
>>> b.shape
(2, 4)

1.2.2 數據類型

Python中的數據類型大體分為兩種:取值幾乎可以是任意大小的整型以及浮點型。NumPy數組則支持更多的數據類型。由于NumPy的底層是用C語言實現的,因此NumPy支持C語言中所有的數據類型。前面的例子向np.array函數傳入了一個各元素為整數的列表,結果得到一個各元素為64位有符號整數的數組。表1-1展示了NumPy支持的數據類型。我們既可以讓NumPy替我們選擇數據類型,也可以顯式指定數據類型。

表1-1 NumPy支持的數據類型,C語言中等價的數據類型以及取值范圍

我們來看一些為數組指定類型的例子:

>>> a = np.array([1,2,3,4], dtype="uint8")
>>> a.dtype
dtype('uint8')
>>> a = np.array([1,2,3,4], dtype="int16")
>>> a = np.array([1,2,3,4], dtype="uint32")
>>> b = np.array([1,2,3,4.0])
>>> b.dtype
dtype('float64')
>>> b = np.array([1,2,3,4.0], dtype="float32")
>>> c = np.array([111,222,333,444], dtype="uint8")
>>> c
array([111, 222, 77, 188], dtype=uint8)

在上面的例子中,數組a的元素為整型,而數組b的元素為浮點型。注意在第一個關于數組b的例子中,Python自動為數組b的元素選擇了64位浮點型。之所以會這樣,是因為輸入的列表里有一個浮點數4.0。

關于數組c的例子看起來似乎是錯誤的,其實不然。如果給定的數據超出指定類型的表示范圍,NumPy并不會報錯。在這個例子中,我們指定的8位整型只能表示[0, 255]取值范圍內的整數。前面的兩個數111和222屬于這個范圍;但后面兩個數333和444都太大,NumPy默認只保留這兩個數的最后8位,分別是77和188。NumPy用這個例子給我們上了一課,讓我們明白了該指定什么數據類型。雖然這類問題不常出現,但我們仍須牢記于心。

1.2.3 二維數組

如果說把列表轉換為數組后得到的是一維向量,那么我們可以猜測,如果把一個列表的列表轉換為數組,那么得到的將是一個二維向量。事實的確如此,我們猜對了。

>>> d = np.array([[1,2,3],[4,5,6],[7,8,9]])
>>> d.shape
(3, 3)
>>> d.size
9
>>> d
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

可以看到,一個由三個子列表構成的列表被映射成了一個3 × 3的向量(即矩陣)。由于NumPy數組從0開始對元素編號,因此引用d[1,2]返回的是6。

1.2.4 全0數組和全1數組

NumPy有兩個非常有用的函數:np.zeros和np.ones。它們都用于定義指定大小的數組。前者用0作為數組全部元素的初始值,而后者則將數組元素全部初始化為1。這是NumPy從頭創建數組的主要方式。

>>> a = np.zeros((3,4), dtype="uint32")
>>> a[0,3] = 42
>>> a[1,1] = 66
>>> a
array([[ 0,  0, 0, 42],
       [ 0, 66, 0,  0],
       [ 0,  0, 0,  0]], dtype=uint32)
>>> b = 11*np.ones((3,1))
>>> b
array([[11.],
       [11.],
       [11.]])

這兩個函數的第一個參數都是元組,用于指定各個維度的大小。如果傳入標量,那么默認定義的是一個一維向量。以數組b為例,它是初始值為1、大小為3 × 1的數組,通過與標量11相乘,可以使數組b的每個元素都為11。

1.2.5 高級索引

上面的例子介紹了訪問單個元素的簡單索引方式。NumPy支持更復雜的索引形式,常用的一種就是用單個索引查詢整個子數組,舉個例子:

>>> a = np.arange(12).reshape((3,4))
>>> a
array([[ 0, 1,  2,  3],
       [ 4, 5,  6,  7],
       [ 8, 9, 10, 11]])
>>> a[1]
array([4, 5, 6, 7])
>>> a[1] = [44,55,66,77]
>>> a
array([[ 0,  1,  2,  3],
       [44, 55, 66, 77],
       [ 8,  9, 10, 11]])

這個例子用到了np.arange函數,它等價于Python中的range函數。注意這里使用reshape方法將一個大小為12的一維向量轉換成了一個3 × 4的矩陣。另外請注意,a[1]返回的是整個子數組,索引是從第一維開始進行的。a[1]其實是a[1, :]的簡化形示,其中的“:”表示某一維的全部元素。這種簡化形式也可以用于賦值操作。

NumPy還支持Python列表的所有切片索引方式,繼續上面的例子:

>>> a[:2]
array([[ 0,  1,  2,  3],
       [44, 55, 66, 77]])
>>> a[:2,:]
array([[ 0,  1,  2,  3],
       [44, 55, 66, 77]])
>>> a[:2,:3]
array([[ 0,  1,  2],
       [44, 55, 66]])
>>> b = np.arange(12)
>>> b
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
>>> b[::2]
array([ 0, 2, 4, 6, 8, 10])
>>> b[::3]
array([0, 3, 6, 9])
>>> b[::-1]
array([11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0])

首先,a[:2]返回數組a中前兩行的全部元素,這里隱含了用“:”索引第二維元素,a[:2]與a[:2,:]等價。關于數組a的第三個例子對兩個維度都進行了索引,通過a[:2, :3]返回了數組a的前兩行和前三列元素。關于數組b的例子展示了如何每隔一個或兩個元素進行查詢。最后一個例子非常有用,這個例子使用一個負的增量實現了索引的倒序。當增量為?1時,表示對所有元素倒序排列。如果增量為?2,則表示以倒序每隔一個元素進行一次查詢。

NumPy使用“:”來表示查詢某一維的全部元素。NumPy還支持用英文省略號來表示“盡可能多的‘:’符號”。為了舉例說明,下面我們先定義一個三維數組:

>>> a = np.arange(24).reshape((4,3,2))
>>> a
array([[[ 0,  1],
        [ 2,  3],
        [ 4,  5]],
       [[ 6,  7],
        [ 8,  9],
        [10, 11]],
       [[12, 13],
        [14, 15],
        [16, 17]],
       [[18, 19],
        [20, 21],
        [22, 23]]])

可以把數組a看成4個3 × 2的子數組。如果要更新其中的第2個子數組,我們可以這么做:

>>> a[1,:,:] = [[11,22],[33,44],[55,66]]
>>> a
array([[[ 0,  1],
        [ 2,  3],
        [ 4,  5]],
       [[11, 22],
        [33, 44],
        [55, 66]],
       [[12, 13],
        [14, 15],
        [16, 17]],
       [[18, 19],
        [20, 21],
        [22, 23]]])

這里我們顯式地用“:”進行各個維度的索引,可以看到“:”的使用讓NumPy很有兼容性,NumPy能夠自動將列表的列表識別為數組并且執行相應的更新操作。接下來我們可以看到,用英文省略號也可以實現同樣的效果。

>>> a[2,...] = [[99,99],[99,99],[99,99]]
>>> a
array([[[ 0,  1],
        [ 2,  3],
        [ 4,  5]],
       [[11, 22],
        [33, 44],
        [55, 66]],
       [[99, 99],
        [99, 99],
        [99, 99]],
       [[18, 19],
        [20, 21],
        [22, 23]]])

這里對第3個3 × 2的子數組也進行了更新。

1.2.6 讀寫磁盤

NumPy數組可以通過調用np.save寫到磁盤上,并通過調用np.load從磁盤上加載,比如:

>>> a = np.random.randint(0,5,(3,4))
>>> a
array([[4, 2, 1, 3],
       [4, 0, 2, 4],
       [0, 4, 3, 1]])
>>> np.save("random.npy",a)
>>> b = np.load("random.npy")
>>> b
array([[4, 2, 1, 3],
       [4, 0, 2, 4],
       [0, 4, 3, 1]])

我們先用np.random.randint創建了一個大小為3 × 4,元素取值在0和5之間(包含0和5)的隨機整型數組(NumPy有很多關于隨機數的函數)。然后我們將該數組寫到磁盤上,命名為random.npy。數組文件必須以“.npy”為后綴,如果沒有指定,NumPy會自動添加該后綴。最后,我們通過調用np.load從磁盤上加載了保存的NumPy數組。

本書還會涉及其他的NumPy函數,我會在遇到時詳細介紹這些函數。接下來,我們快速了解一下SciPy。

主站蜘蛛池模板: 微博| 枝江市| 庆城县| 韩城市| 莆田市| 福建省| 延吉市| 唐河县| 安化县| 安岳县| 弥勒县| 鹤庆县| 常宁市| 丹棱县| 丁青县| 深圳市| 屯昌县| 那曲县| 太湖县| 阳城县| 深水埗区| 房山区| 鹤壁市| 南投县| 平阴县| 高阳县| 台江县| 兴海县| 会理县| 承德县| 景德镇市| 台北市| 锡林郭勒盟| 盖州市| 遵义市| 海淀区| 沛县| 绥德县| 广饶县| 清丰县| 柳江县|