numpy的介紹——總覽


為什么有numpy這個庫呢?

1. 准安裝的Python中用列表(list)保存一組值,可以用來當作數組使用,不過由於列表的元素可以是任何對象,因此列表中所保存的是對象的指針。這樣為了保存一個簡單的[1,2,3],需要有3個指針和三個整數對象。對於數值運算來說這種結構顯然比較浪費內存和CPU計算時間。

2. 此外Python還提供了一個array模塊,array對象和列表不同,它直接保存數值,和C語言的一維數組比較類似。但是由於它不支持多維,也沒有各種運算函數,因此也不適合做數值運算。

3. 所以numpy就這么登場了,NumPy是Python的一種開源的數值計算擴展。這種工具可用來存儲和處理大型矩陣,比Python自身的嵌套列表(nested list structure)結構要高效的多(該結構也可以用來表示矩陣(matrix))。 NumPy的主要對象是同種元素的多維數組。這是一個所有的元素都是一種類型、通過一個正整數元組索引的元素表格(通常是元素是數字)。在NumPy中維度(dimensions)叫做軸(axes),軸的個數叫做秩(rank)。

4. numpy的所有的函數docs 可以看:https://docs.scipy.org/doc/numpy/genindex.html

 

numpy 提供了兩個基本的對象: ndarray 和 ufunc.   ndarray是存儲數據的多維數組, 而 ufunc 是對數組進行處理的函數。

以下內容參考自:python科學計算 第二章的內容。

 

ndarray對象:

1. 如何創建一個ndarray對象——數組??

方法一: 使用 np.array()函數把 python傳入的序列對象創建成數組。   這個序列對象可以是用 []括起來的列表,也可以是用()括起來的元組。  多層序列嵌套使用 , 隔開。例子如下:

#使用列表作為參數:
>>> np.array([1, 2, 3])
array([1, 2, 3])
>>> np.array([[1, 2],[3, 4]])
array([[1, 2],
       [3, 4]])
#使用帶括號的元組作為參數
>>> np.array((4, 5, 6))
array([4, 5, 6])
>>> np.array(((4, 5),(5, 6)))
array([[4, 5],
       [5, 6]])

方法二:

np.arange()函數可以通過指定開始值、終值、步長來創建一個等差數列, 不包括終值;

np.linspace()函數可以通過指定開始值、終值、元素個數創建等差數列, 通過endpoint參數指定是否包括終值,默認包括;

np.logspace() 函數創建等比數列,具體用法使用help()查看。

zeros()、ones()和empty()函數可以創建指定的數組, 參數使用元組或列表, 大家一般都使用元組,例如:

>>> np.ones((2,2))
array([[ 1.,  1.],
       [ 1.,  1.]])
>>> np.zeros((2,2))
array([[ 0.,  0.],
       [ 0.,  0.]])
>>> np.empty((2,2))
array([[  1.25849429e-316,   4.71627160e-317],
       [  6.91798776e-310,   0.00000000e+000]])

zeros_like() 、 ones_like()和empty_like()創建與參數的數組相同形狀的數組;

frombuffer()、 fromstring()、 fromfile()等函數可以從字節序列或文件創建數組

使用: fromfunction()通過此函數創建數組, func的參數就是數組元素的索引。例如:

>>> def func(i):
...   return i * i
... 
>>> np.fromfunction(func, (9,))
array([  0.,   1.,   4.,   9.,  16.,  25.,  36.,  49.,  64.])

 

 

充小知識點:

1) 使用數組的 shape 屬性可以查看一個數組的形狀,它的返回值是一個元組

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

2)可以通過修改 shape的屬性來修改一個數組的元素, 但是它內存位置不變化 。 例如:

>>> a.shape = (4, 1)
>>> a
array([[1],
       [2],
       [3],
       [4]])
>>> a.shape = (4,)
>>> a
array([1, 2, 3, 4])
3) 還可以通過 reshape()方法,修改原數組的形狀來創建一個新數組, 特征注意: 新建的數組與原數組是共享內存空間的, 修改其中一個就會影響另一個!!!
>>> b = a.reshape((2,2))
>>> b
array([[1, 2],
       [3, 4]])

4) 當使用reshape()方法時, 如果其它一個軸的大小設置 為 –1, 則自動計算該軸的長度;

5) 數組元素的類型可以通過 dtype 獲得, 各個類型都存儲在 np.typeDict 字典里。

 

2. 讀取數組:

使用 [] 操作符對數組內的元素進行讀取 ,  那么下標都可以是什么呢?

1. 使用整數, 整數的下標是從0開始的; 如 a[0]等;

2. 使用切片, 切片的使用這里不多說明。只說明一點為: 切片得到的數組與原始數組共享內存單元。

3. 使用整數列表, 如:[1, 3, 5], 說明:使用它得到的新數組與原始的數組不共享內存單元。

4. 使用整數數組, 可以是多維的,  它同樣不會共享內存單元。     如:

>>> b
array([[1, 2, 3],
       [4, 5, 6]])
>>> a = np.arange(100,120,2)
>>> a
array([100, 102, 104, 106, 108, 110, 112, 114, 116, 118])
>>> a[b]
array([[102, 104, 106],
       [108, 110, 112]])

5.  使用布爾數組,  這個很有意思!!!, 它只保留是對應是 true 的元素。 布爾數組一般都是生成的,例如:

>>> x = np.random.rand(8)
>>> x
array([ 0.3179888 ,  0.44513988,  0.94475611,  0.8954217 ,  0.79704721,
        0.33844282,  0.56761519,  0.87936442])
>>> x > 0.5
array([False, False,  True,  True,  True, False,  True,  True], dtype=bool)
>>> x[x>0.5]
array([ 0.94475611,  0.8954217 ,  0.79704721,  0.56761519,  0.87936442])

 

3. 多維數組:

1. 在多維數組中,使用元組作為數組的下標, 元組的每一個元素與數組的每一個軸對應, 當元組中的元素個數少於少於數組的維數時,默認剩余的各軸為 :, 即表示所有。   a[1, 2] 與a[(1, 2)] 是一樣的;

2. 下標對象不是元組, NumPy 會首先把它轉換為元組。這種轉換可能會和用戶所希望的不一致,因此為了避免出現問題,請顯式地使用元組作為下標。

3.  元組中的每一個元素可以是一個整數, 也可以是一個列表,也可以又是一個元組,也可以是一個數組,也可以是一個布爾數組。  在最后, 這些經過各種轉換和添加“:”之后 ,

得到了一個標准的下標元組。它的各個元素有如下幾種類型:切片、整數、整數數組和布爾數組。如果元素不是這些類型,如列表或元組,就將其轉換成整數數組!!!!

4. 如果下標元組的所有元素都是切片,那么用它作為下標得到的是原始數組的一個視圖,即它和原始數組共享數據存儲空間。 可以使用 a.flags查看一下 OWNDATA字段,如果為False,則是共享的。

    當在下標中使用這些對象時,所獲得的數據是原始數據的副本,因此修改結果數組不會改變原始數。

>>> a
array([[10, 11, 12, 13, 14],
       [20, 21, 22, 23, 24],
       [30, 31, 32, 33, 34],
       [40, 41, 42, 43, 44]])
#使用列表作為元組的第一個元系,第二個元素省略;
>>> a[[1,2]]
array([[20, 21, 22, 23, 24],
       [30, 31, 32, 33, 34]])
# 使用兩個元組, 它值其實就是a[0,2]和a[1, 3]
>>> a[(0,1), (2,3)]
array([12, 23])
#使用一個二維數組作為元組中的第一個元素, 第十個元素省略, 這樣會得到一個三維的數組;
>>> a
array([[10, 11, 12, 13, 14],
       [20, 21, 22, 23, 24],
       [30, 31, 32, 33, 34],
       [40, 41, 42, 43, 44]])
>>> b
array([[1, 2],
       [3, 1]])
>>> b.shape
(2, 2)
>>> a[b]
array([[[20, 21, 22, 23, 24],
        [30, 31, 32, 33, 34]],

       [[40, 41, 42, 43, 44],
        [20, 21, 22, 23, 24]]])
>>> a[b].shape
(2, 2, 5)

 

4. 結構數組:

可以自行創建一個結構數組的類型. 然后,就可以使用這個結構類型創建結構數組了.   只舉一個簡單的例子:

# 創建一個結構體類型, 是一個字典類型,里面有names與formats的鍵, 鍵值為一個列表
persontype = np.dtype({ 
'names':['name', 'age', 'weight'],
'formats':['S32','i', 'f']}, align= True )

#使用結構類型創建結構數組
a = np.array([("Zhang",32,75.5),("Wang",24,65.2)], 
dtype=persontype)

其中:

'S32' :長度為 32 字節的字符串類型,由於結構中每個元素的大小必須固定,因此需要指定字符串的長度。
'i' : 32 bit 的整數類型,相當於 np.int32。
'f' : 32 bit 的單精度浮點數類型,相當於 np.float32。

 

5 內存結構

這一部分講明了為什么切片操作,可以是共享原始數據的內存,而不用復制的。

每一個數組都可以使用flags屬性查看相關的信息,如:

>>> a
array([[10, 11, 12, 13, 14],
       [20, 21, 22, 23, 24],
       [30, 31, 32, 33, 34],
       [40, 41, 42, 43, 44]])
>>> a.flags
  C_CONTIGUOUS : True
  F_CONTIGUOUS : False
  OWNDATA : True
  WRITEABLE : True
  ALIGNED : True
  UPDATEIFCOPY : False

 

ufunc運算

ufunc 是 universal function 的縮寫,它是一種能對數組中每個元素進行操作的函數。  NumPy內置的許多 ufunc 函數都是在 C 語言級別實現的,因此它們的計算速度非常快。

1. 四則運算

它提供了數組的四則運算的相關函數,  即可以通過函數調用進行四則運算,也可以直接使用 運算符進行計算。

image_thumb1

其中, 除號的意義根據是否激活 __future__.division 會有所不同:python 2 與 python3中的除法問題。

 

2.2 比較和布爾運算

1. 比較操作:

使用”==“、”>”等比較運算符對兩個數組進行比較, 將返回一個布爾數組,  它的每一個元素值都是兩個數組對應元素比較的結果。

image_thumb3

 

2. 布爾運算:

由於 Python 中的布爾運算使用 and、 or 和 not 等關鍵字,它們無法被重載,因此數組的布 爾運算只能通過相應的 ufunc 函數進行。這些函數名都以“logical_”開頭, 包括:

np.logical_and()、 np.logical_not()、  np.logical_or() 、 np.logical_xor()四個函數。 使用方法例如:

>>> a>b
array([False, False,  True,  True], dtype=bool)
>>> a<b
array([ True,  True, False, False], dtype=bool)
>>> np.logical_or(a>b, a<b)
array([ True,  True,  True,  True], dtype=bool)

 

注意: 當我們對布爾數組使用 python的邏輯運算符 and ,or, not 操作時,會提示錯誤,原因在於,它們只能比較單個的布爾值,不能比較多個。

>>> a>b or a<b
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

 

3. 比特運算函數:

以“bitwise_”開頭的函數是比特運算函數,包括 bitwise_and、 bitwise_not、 bitwise_or 和 bitwise_xor 等。也可以使用"&"、 "~"、 "|"和"^"等操作符進行計算。 對於布爾數組來說,位運算和布爾運算的結果相同。

 

4. 廣播

什么意思呢?當兩個數組的維度不對應是,如何進行四則運算呢???這時候,數組就會被擴展處理(廣播處理):

原則(抄書上寫的):

(1) 讓所有輸入數組都向其中維數最多的數組看齊, shape 屬性中不足的部分都通過在前面加 1 補齊。
(2) 輸出數組的 shape 屬性是輸入數組的 shape 屬性在各個軸上的最大值。
(3) 如果輸入數組的某個軸長度為 1 或與輸出數組對應軸的長度相同,這個數組就能夠用來計算,否則出錯。 (意思就是說為1時,可以進行擴展了)
(4) 當輸入數組的某個軸長度為 1 時,沿着此軸運算時都用此軸上的第一組值。

舉例說明:

#創建一個二維數組 a,其形狀為(6,1):
>>> a = np.arange(0, 60, 10).reshape(-1, 1)
>>> a
array([[ 0], [10], [20], [30], [40], [50]])
>>> a.shape
(6, 1)
#再創建一維數組 b,其形狀為(5,):
>>> b = np.arange(0, 5)
>>> b
array([0, 1, 2, 3, 4])
>>> b.shape
(5,)
#計算數組 a 和 b 的和,得到一個加法表,它相當於計算兩個數組中所有元素組的和,得到一個形狀為(6,5)的數組
>>> c = a + b
>>> c
array([[ 0, 1, 2, 3, 4],
[10, 11, 12, 13, 14],
[20, 21, 22, 23, 24],
[30, 31, 32, 33, 34],
[40, 41, 42, 43, 44],
[50, 51, 52, 53, 54]])
>>> c.shape
(6, 5)

#驚訝了嗎??,下面解釋一下:

#由於數組 a 和 b 的維數不同,根據規則(1),需要讓數組 b 的 shape 屬性向數組 a 對齊,於是將數組 b 的 shape 屬性前面加 1,補齊為(1,5)。相當於做了如下計算
>>> b.shape=1,5
>>> b
array([[0, 1, 2, 3, 4]])
#根據規則(2),輸出數組各個軸的長度為輸入數組各個軸長度的最大值,可知輸出數組的 shape 屬性為(6,5)。
#由於數組 b 第 0 軸的長度為 1,而數組 a 第 0 軸的長度為 6,因此為了讓它們在第 0 軸上能夠相加,根據(4)需要將數組 b 第 0 軸的長度擴展為 6,這相當於:
>>> 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]])
# 數組a 同理,作相同的操作:
>>> 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]])

#經過上述處理之后,數組 a 和 b 就可以按對應元素進行相加運算了。

 

另外, np.ogrid提供了可以快速產生能夠進行廣播運算的數組。 np.mgrid對象與ogrid類似,它的返回值是進行廣播擴展之后的數組。其切片下標有兩種形式:
● 開始值:結束值:步長,和“np.arange(開始值, 結束值, 步長)”類似。
● 開始值:結束值:長度 j,當第三個參數為虛數時,它表示所返回數組的長度,其和“np.linspace(開始值, 結束值, 長度)”類似

例如:

>> x, y = np.ogrid[:4, :4]
>>> x
array([[0],
       [1],
       [2],
       [3]])
>>> y
array([[0, 1, 2, 3]])

>>> x, y = np.mgrid[:4, :4]
>>> x
array([[0, 0, 0, 0],
       [1, 1, 1, 1],
       [2, 2, 2, 2],
       [3, 3, 3, 3]])
>>> y
array([[0, 1, 2, 3],
       [0, 1, 2, 3],
       [0, 1, 2, 3],
       [0, 1, 2, 3]])

 

(以上內容寫於:2017年11月3日)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM