深度學習基礎之Numpy教程

Numpy是專門為科學計算設計的Python核心庫。它提供了高性能的多維數組對象以及相關工具。它的實現更接近於底層,所以效率很高。

Numpy數組---Array

Numpy的主要對象是多維數組。它是一個由元素(通常是數字)構成的表,所有元素的類型相同。維度的數量稱為數組的階(rank),數組的大小是一個由整型數構成的元組,可以描述數組不同維度上的大小。

Numpy的數組類叫做ndarray,別名是array。先來舉一個例子,涉及的具體函數後面我們都會講到。

import numpy as np nna = np.array([0, 1, 2, 3]) # 創建一個一維數組nprint(type(a)) # 列印 "<class numpy.ndarray>"n

數組的屬性

  • ndarray.ndim:數組的維度數
  • ndarray.shape:數組每個維度的大小
  • ndarray.size:數組中元素的總個數
  • ndarray.dtype: 數組中元素的類型
  • ndarray.itemsize: 數組中每個元素所佔的位元組數
  • ndarray.data: 包含真實數組元素的緩衝區

再舉一個例子。

import numpy as np nna = np.array([[0.,1.,2.],[3.,4.,5.]]) # 創建一個2維數組 nprint(a) # 列印 "[[ 0. 1. 2.]n # [ 3. 4. 5.]]"nprint(a.ndim) # 列印 "2"nprint(a.shape) # 列印 "(2, 3)"nprint(a.size) # 列印 "6"nprint(a.dtype) # 列印 "float64"nprint(a.itemsize) # 列印 "8" (64/8=8)nprint(a.data) # 列印 "<memory at 0x7f18400ae3a8>"n

創建數組

手動創建數組

可以利用array函數從python的列表或元組創建一個數組。

  • 1維數組

import numpy as np # 導入Numpy的推薦方式nna = np.array([0, 1, 2, 3]) # 創建一維數組nprint(a) # 列印 "[1 2 3 4]"nprint(a.ndim) # 列印 "1"nprint(a.shape) # 列印 "(4,)"nprint(len(a)) # 列印 "4"n

  • 2維及多維數組

import numpy as npnnb = np.array([[0, 1, 2],[3, 4, 5]]) # 創建2維數組nprint(b) # 列印 "[[0 1 2]n # [3 4 5]]"nprint(b.ndim) # 列印 "2"nprint(b.shape) # 列印 "(2, 3)"nprint(len(b)) # 列印 "2"nnc = np.array([[[1], [2]], [[3], [4]]]) # 創建3維數組nprint(c) # 列印 "[[[1]n # [2]]n # (注意,列印時這裡有一個空行)n # [[3]n # [4]]]"nprint(c.shape) # 列印 "(2, 2, 1)"n

注意:當你列印數組時,Numpy和嵌套列表以相似的方式顯示,但是具有結構:

  • 最後一維從左到右列印
  • 倒數第二維從上到下列印
  • 其餘的維度也是從上到下列印,每一項之間都會有一個空行。

用函數創建數組

Numpy還提供了很多用函數創建數組的方法:

  • arange:等間距分布的數組

import numpy as npnna = np.arange(10) # 0,1,..n-1nprint(a) # 列印 "[0 1 2 3 4 5 6 7 8 9]"nb = np.arange(1, 9, 2) # start, end(不包含),stepnprint(b) # 列印 "[1 3 5 7]"nc = np.arange(0, 2.5, 0.4) # 參數可以是浮點數nprint(c) # 列印 "[ 0. 0.4 0.8 1.2 1.6 2. 2.4]"n

  • linspace:指定數量(長度)的數組:

import numpy as npnnd = np.linspace(0, 1, 6) # start,end, num-pointsnprint(d) # 列印 "[ 0. 0.2 0.4 0.6 0.8 1. ]"ne = np.linspace(0, 1, 5, endpoint=False) # 可以顯示的指定不包括最後一個點nprint(d) # 列印 "[ 0. 0.2 0.4 0.6 0.8]"n

  • 常用數組

import numpy as npnna = np.ones((1,2)) # 創建元素全為1的數組nprint(a) # 列印 "[[ 1. 1.]]"nnb = np.zeros((2,2)) # 創建元素全為0的數組nprint(b) # 列印 "[[ 0. 0.]n # [ 0. 0.]]"nnc = np.full((2,2), 7) # 創建一個用固定值填充的數組nprint(c) # 列印 "[[ 7. 7.]n # [ 7. 7.]]"nnd = np.eye(2) # 創建對角線為1,其它元素為0的2維數組nprint(d) # 列印 "[[ 1. 0.]n # [ 0. 1.]]"nne = np.diag(np.array([1,2,3])) # 從2維數組提取對角線,或從一維數組構建對角線矩陣nprint(e) # 列印 "[[1 0 0]n # [0 2 0]n # [0 0 3]]"nnf = np.empty((2,2)) # 創建隨機初始的數組nprint(f) # 列印 "[[ 4.94065646e-324 9.88131292e-324]n # [ 1.48219694e-323 1.97626258e-323]]"n

  • np.random: 隨機數數組

import numpy as npnna = np.random.rand(3) # [0, 1)均勻分布隨機值nprint(a) # 可能列印 "[ 0.14662351 0.9235998 0.80878827]"nnb = np.random.randn(2,2) # 標準正態分布隨機值nprint(b) # 可能列印 "[[ 1.03371837 0.26109287]n # [ 1.33813718 -0.85320254]]"nnnp.random.seed(1234) # 設定隨機數種子,產生可重複的結果n

基本數據類型

你可能注意到,某些數組元素後面會跟著一個小數點 (比如 2. vs 2)。這是由於不同的數據類型所致。Numpy可以從輸入自動推導出結果的數據類型:

import numpy as npnna = np.array([1, 2, 3, 4])nprint(a.dtype) # 列印 "int64"nnb = np.array([1., 2., 3., 4.]) # 列印 "float64"nprint(b.dtype)n

你也可以顯式的指定你想得到的數據類型:

c = np.array([1, 2, 3], dtype=float)nprint(c.dtype) # 列印 "float64"nnd = np.array([1.,2.,3.]).astype(int64)nprint(d.dtype) # 列印 "int64"n

默認的數據類型是浮點數

e = np.ones((3, 3))nprint(e.dtype) # 列印 "float64"n

Numpy還有一些其它的數據類型

e = np.array([1+2j, 3+4j, 5+6j]) # 複數nprint(e.dtype) # 列印 "complex128"nnf = np.array([True, False, False, True]) # 布爾值nprint(f.dtype) # 列印 "bool"nng = np.array([Bonjour, Hello, Hallo]) # 字元串nprint(g.dtype) # 列印 "<U7"n

索引、切片和迭代

索引

數組中的每一項可以像python的序列類型(如list)一樣被訪問和賦值

import numpy as npnn# 創建一個一維數組 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] na = np.arange(10)nprint(a[0], a[2], a[-1]) # 列印:0 2 9nprint(a[::-1]) # 列印 [9 8 7 6 5 4 3 2 1 0] (python中逆轉序列依舊適用)nn# 創建一個二維數組n# [[1 2 3]n# [4 5 6]n# [7 8 9]]nb = np.arange(1,10).reshape(3,3)nprint(b[1,1], b[2,1]) # 列印 "5 8"nn# 當提供的索引數小於維度數時,缺失的索引表示全部切片nprint(b[1]) # 列印 "[4 5 6]"nprint(b[1][2]) # 列印 "6"n

表達式b[i]被看做i後面跟著足夠多的 :來表示其餘的維度。Numpy也允許使用b[i,...]的形式。

dots (...)代表足夠多的冒號產生完整的索引元組。舉個例子,x是一個秩為5的數組:

  • x[1,2,...] is equivalent to x[1,2,:,:,:],
  • x[...,3] to x[:,:,:,:,3] and
  • x[4,...,5,:] to x[4,:,:,5,:].

切片

和Python列表類似,numpy數組可以使用切片語法。因為數組可以是多維的,所以你必須為每個維度指定好切片。

import numpy as npnna = np.arange(10) # 創建數組 [0 1 2 3 4 5 6 7 8 9]nprint(a[2:9:3]) # 列印 [2 5 8]nprint(a[1:4]) # 列印 [1 2 3] (不包括最後一個索引)nn# 切片的三個參數都不是必須的,start默認是0,end默認是最後,step默認是1nprint(a[::2]) # 列印 [0 2 4 6 8]nprint(a[3:]) # 列印 [3 4 5 6 7 8 9] nn# 創建如下二維數組,shape=(3, 4)n# [[ 1 2 3 4]n# [ 5 6 7 8]n# [ 9 10 11 12]]nb = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])nn# 使用切片操作得到一個由a的前兩行和列1和列2組成的子數組cn# 數組c如下所示,shape=(2, 2)n# [[2 3]n# [6 7]]nc = b[:2, 1:3]nn# 數組的一個切片是相同數據上的一個視圖,共享內存內存地址,n# 因此修改切片數組會改變原始數組nprint(b[0, 1]) # 列印 "2"nc[0, 0] = 77 # b[0, 0]與a[0, 1]代表同一個數據nprint(b[0, 1]) # 列印 "77"n# 這種行為看起來很奇怪,但是可以幫助節省內存和時間開銷。n

你可以同時使用整型和切片語法來訪問數組。但是,這樣做會產生一個比原數組低階的新數組。需要注意的是,這裡和MATLAB中的情況是不同的:

import numpy as npnn# 創建一個二維數組,shape=(3, 4)n# [[ 1 2 3 4]n# [ 5 6 7 8]n# [ 9 10 11 12]]na = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])nn# 訪問數組中間行數據的兩種方式n# 混合使用整數索引和切片產生一個低階的數組n# 只使用切片產生和原始數組相同階的數組nrow_r1 = a[1, :] # a第二行的1維視圖 nrow_r2 = a[1:2, :] # a第二行的2維視圖nprint(row_r1, row_r1.shape) # 列印 "[5 6 7 8] (4,)"nprint(row_r2, row_r2.shape) # 列印 "[[5 6 7 8]] (1, 4)"nn# 當訪問數組的列時也會產生同樣的差別ncol_r1 = a[:, 1]ncol_r2 = a[:, 1:2]nprint(col_r1, col_r1.shape) # 列印 "[ 2 6 10] (3,)"nprint(col_r2, col_r2.shape) # 列印 "[[ 2]n # [ 6]n # [10]] (3, 1)"n

下圖是一個切片和索引操作的圖解。

你也可以將賦值和切片結合起來

import numpy as npnna = np.arange(10) # 創建數組 [0 1 2 3 4 5 6 7 8 9]na[5:] = 10nprint(a) # 列印 "[ 0 1 2 3 4 10 10 10 10 10]"nnb = np.arange(5) # 創建數組 [0 1 2 3 4]na[5:] = b[::-1] nprint(a) # 列印 "[0 1 2 3 4 4 3 2 1 0]"n

迭代

import numpy as npnn# 一維數組迭代na = np.arange(10)nfor i in a:n print(1+1, end= )n# 列印結果如下n# "1 2 3 4 5 6 7 8 9 10"nn# 二維及多維數組迭代n# 多維數組按第一維進行迭代nb = np.arange(0,10).reshape(5,2) nfor i in b:n print(i)n# 列印結果如下n# [0 1]n# [2 3]n# [4 5]n# [6 7]n# [8 9]nn# 如果想對數組中的每個元素執行一個操作,可以使用flat屬性,n# 它是一個數組中所有元素的迭代器nfor i in b.flat:n print(i,end= )n# 列印結果如下n# 0 1 2 3 4 5 6 7 8 9 n

Fancy indexing

Numpy提供了比常規python序列更多的索引方式。除了可以使用整數和切片索引,也可以使用布爾數組或者整數數組索引,這種方法叫做fancy indexing。它創建拷貝而不是視圖。

整型數組訪問:當我們使用切片語法訪問數組時,得到的總是原數組的一個子集。整型數組訪問允許我們利用其它數組的數據構建一個新的數組。當一個新數組是由整數數組索引創建的,新數組與這個整數數組的shape相同。

  • 被索引數組是一維數組

import numpy as npnna = np.arange(0, 100, 10) # 創建一維數組 [0 10 20 30 40 50 60 70 80 90]nn# 索引是一維數組,返回的數組shape=(5,),與索引數組i相同ni = np.array([1,1,3,8,5]) # 同一個索引值可以重複多次nprint(a[i]) # 列印 "[10 10 30 80 50]"nn# 索引也可以是列表nprint(a[[1,1,3,8,5]]) # 列印 "[10 10 30 80 50]" nn# 索引是二維數組。返回數組的shape=(2, 2),與索引數組j的shape相同。nj = np.array([ [ 3, 4], [ 9, 7 ] ]) # shape = (2, 2)nprint(a[j]) # 列印 "[[30 40]n [90 70]]"n

  • 被索引數組是多維數組

import numpy as npnn# 創建二維數組,shape=(3, 2)n# [[1 2]n# [3 4]n# [5 6]]na = np.array([[1,2], [3, 4], [5, 6]])nn# 當被索引數組是多維的時,單獨的一個索引數組代表源數組的第一個維度nidx = np.array([0,1])nprint(a[idx]) # 列印 "[[1 2]n [3 4]]" nn# 我們可以給定多於一個索引數組n# 為每一維指定的索引數組的shape要相同nprint(a[[0, 1, 2], [0, 1, 0]]) # 列印 "[1 4 5]"nn# 上面整數數組的索引的例子與下面等價:nprint(np.array([a[0, 0], a[1, 1], a[2, 0]])) # 列印 "[1 4 5]"nnidx1 = np.array([[0,1],[1,2]])nidx2 = np.array([[1,0],[0,1]])nprint(a[idx1,idx2]) # 列印 "[[2 3]n # [3 6]]"n

整型數組訪問語法還有個有用的技巧,可以用來選擇或者更改矩陣中每行中的一個元素:

import numpy as npnna = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])nprint(a) # prints "array([[ 1, 2, 3],n # [ 4, 5, 6],n # [ 7, 8, 9],n # [10, 11, 12]])"nn# 創建整數數組索引nb = np.array([0, 2, 0, 1])nn# 使用b中的索引值從每一列中選擇一個元素nprint(a[np.arange(4), b]) # Prints "[ 1 6 7 11]"nn# 索引b從每行中選擇的元素都加上10na[np.arange(4), b] += 10nnprint(a) # 列印 "array([[11, 2, 3],n # [ 4, 5, 16],n # [17, 8, 9],n # [10, 21, 12]])n

布爾型數組訪問

布爾型數組訪問可以讓你選擇數組中任意元素。

import numpy as npn#******************Example 1*****************************n#通常,這種訪問方式用於選取數組中滿足某些條件的元素:na = np.array([[1,2], [3, 4], [5, 6]])nbool_idx = (a > 2) # 找到比2大的所有元素;n # 這會返回一個與a形狀相同的布爾數組;n # 每一個位置的布爾值代表原數組中該位置的元素是否大於2nnprint(bool_idx) # 列印 "[[False False]n # [ True True]n # [ True True]]"nn# 我們可以使用布爾數組索引構建一個1維數組,包含bool_idx中True對應的元素。nprint(a[bool_idx]) # 列印 "[3 4 5 6]"nn# 我們可以使用一條簡明的語句完成以上所有操作nprint(a[a > 2]) # 列印 "[3 4 5 6]"nn# 我們也可以使用布爾數組索引對bool_idx中True對應的元素賦值na[a>2] = 2nprint(a) # 列印 "[[1 2]n [2 2]n [2 2]]"nn#**********************Example 2************************n#創建一個2維數組,shape=(3, 4)n# [[ 0 1 2 3]n# [ 4 5 6 7]n# [ 8 9 10 11]]na = np.arange(12).reshape(3,4)nnb1 = np.array([True, True, False]) # 第一維的選擇nb2 = np.array([True, False, True, False]) # 第二維的選擇nnprint(a[b1, :]) # 列印 "[[0 1 2 3]n # [4 5 6 7]]"nprint(a[:, b2]) # 列印 "[[ 0 2]n # [ 4 6]n # [ 8 10]]"nprint(a[b1, b2]) # 列印 "[0 6]"n

為了教程的簡介,有很多數組訪問的細節我們沒有詳細說明,可以查看文檔。

拷貝和視圖

當操作數組時,有時它們的數據會拷貝到一個新的數組,有時則不會。主要有以下幾種情況

沒有拷貝

簡單的賦值操作不會對數組對象或者它們的數據產生拷貝:

import numpy as npnna = np.arange(12)nb = a # 一個新的對象被創建n# a和b是同一個ndarray對象的2個名字nprint(b is a) # 列印 "True"n# 改變a的shape, b的shape自然也會改變nb.shape = 3,4 nprint(a.shape) # 列印 "(3, 4)"n

視圖或者淺拷貝

不同的array對象可以共享相同的數據。view方法創建了一個共享相同數據的新數組對象。

c = a.view() # 用view方法創建數組cnprint(c is a) # 列印 "False"nprint(c.base is a) # 列印 "True" nprint(c.flags.owndata) # 列印 "False"nnc.shape = 2,6 # a的shape不改變nprint(a.shape) # 列印 "(3, 4)"nnc[0,4] = 1234 # a的數據會改變nprint(a) # 列印 "[[ 0 1 2 3]n # [1234 5 6 7]n # [ 8 9 10 11]]"n

深拷貝

d = a.copy() # 創建一個擁有新數據的新數組,d和a不共享任何東西nprint(d is a) # 列印 "False"nprint(d.base is a) # 列印 "False"nnd[0,0] = 9999 # a的數據不會改變nprint(a) # 列印 "[[ 0 1 2 3]n [1234 5 6 7]n [ 8 9 10 11]]"n

基本運算

基本數學計算函數會對數組中元素逐個進行計算,既可以利用操作符重載,也可以使用函數方式:

import numpy as npnnx = np.array([[1,2],[3,4]], dtype=np.float64)ny = np.array([[5,6],[7,8]], dtype=np.float64)nn# 逐元素加法;都產生以下數組n# [[ 6.0 8.0]n# [10.0 12.0]]nprint(x + y)nprint(np.add(x, y))nn# 逐元素減法;都產生以下數組n# [[-4.0 -4.0]n# [-4.0 -4.0]]nprint(x - y)nprint(np.subtract(x, y))nn# 逐元素乘法;都產生以下數組n# [[ 5.0 12.0]n# [21.0 32.0]]nprint(x * y)nprint(np.multiply(x, y))nn# 逐元素除法;都產生以下數組n# [[ 0.2 0.33333333]n# [ 0.42857143 0.5 ]]nprint(x / y)nprint(np.divide(x, y))nn# 逐元素求平方根;產生以下數組n# [[ 1. 1.41421356]n# [ 1.73205081 2. ]]nprint(np.sqrt(x))nn# 邏輯運算na = np.array([1, 1, 0, 0], dtype=bool)nb = np.array([1, 0, 1, 0], dtype=bool)nn# 逐元素求邏輯與;都產生以下數組n# [ True False False False]nprint(a & b)nprint(np.logical_and(a,b))nn# 逐元素求邏輯或;都產生以下數組n# [ True True True False]nprint(a | b)nprint(np.logical_or(a, b))n

注意:*是數組乘法並非矩陣乘法。在Numpy中使用dot來進行矩陣乘法:

import numpy as npnnx = np.array([[1,2],[3,4]])ny = np.array([[5,6],[7,8]])nnv = np.array([9,10])nw = np.array([11, 12])nn# 向量的內積;結果都是219nprint(v.dot(w))nprint(np.dot(v, w))nn# 矩陣和向量的矩陣乘法;結果都是是1維數組[29 67]nprint(x.dot(v))nprint(np.dot(x, v))nn# 矩陣和矩陣的矩陣乘法;結果是2維數組n# [[19 22]n# [43 50]]nprint(x.dot(y))nprint(np.dot(x, y))n

一些操作,如+=*=,會原地更改一個已經存在的數組而不會創建一個新的數組。

import numpy as npnna = np.ones((2,3), dtype=int)na *= 3 # 原地操作nprint(a) # 列印 "[[3 3 3]n # [3 3 3]]"n

操作不同數據類型的數組時,結果數組的類型會與更精確的數組的類型一致。

import numpy as npnna = np.ones(3, dtype=np.int32) # dtype = int32nb = np.linspace(0,3,3)nnprint(b.dtype) # float64nc = a + bnprint(c.dtype) # float64n

超越函數

import numpy as npnnx = np.array([[1,2],[3,4]], dtype=np.float64)nn# 逐元素求對數;產生以下數組n# [[ 0. 0.69314718]n# [ 1.09861229 1.38629436]]nprint(np.log(x))nn# 逐元素求指數;產生以下數組n# [[ 2.71828183 7.3890561 ]n# [ 20.08553692 54.59815003]]nprint(np.exp(x))nn# 逐元素求sin;產生以下數組n# [[ 0.84147098 0.90929743]n [ 0.14112001 -0.7568025 ]]nprint(np.sin(x))n

比較操作

import numpy as npnna = np.array([1, 2 ,3, 4])nb = np.array([4, 2 ,2, 4])nc = np.array([1, 2, 3, 4])nn# 逐元素比較nprint(a == b) # 列印 "[False True False True]"nprint(a > b) # 列印 "[False False True False]"nn# 數組整體比較nprint(np.array_equal(a, b)) # 列印 "False"nprint(np.array_equal(a, c)) # 列印 "True"n

Basic reductions

默認情況下,這些操作會忽略數組的shape,將數組看做一個整體。然而,我們可以指定axis參數,你可以指定某個axis執行一個操作。

求和、求平均

import numpy as npnnx = np.array([[1,2],[3,4]])nn# 計算所有元素的和; 結果都是 "10"nprint(np.sum(x)) nprint(x.sum())nn# 計算每一列的和; 結果都是 "[4 6]"nprint(np.sum(x, axis=0)) nprint(x.sum(axis=0))nn# 計算每一行的和; 結果都是n# " [[3]n# [7]]"nprint(np.sum(x, axis=1,keepdims=True)) nprint(x.sum(axis=1,keepdims=True))nn# mean的用法和sum類似n# 計算整個數組平均值;結果是 "2.5"nprint(x.mean())n

求極值

格式與求和運算類似

import numpy as npnnx = np.array([[1,2],[3,4]])nnprint(x.max()) # 計算所有元素的最大值;結果是"4"nprint(x.min()) # 計算所有元素的最小值;結果是"1"nprint(x.argmax()) # 返回最大值索引;結果是"3"nprint(x.argmin()) # 返回最小值索引;結果是"0"n

邏輯運算

import numpy as npnprint(np.all([True, True, False])) # 列印 "False"nprint(np.any([True, True, False])) # 列印 "True"n

截斷操作

import numpy as npnna = np.arange(1,13).reshape(3,4)n# 將數組a中元素都截斷在[2,9]的範圍內n# "[2 2 3 4]n# [5 6 7 8]n# [9 9 9 9]]nprint(np.clip(a,2,9)) n

廣播

NumPy 數組的基本操作(比如加法)都是逐元素的(elementwise)。這當然要求進行運算的兩個數組大小(shape)相同。然而 ,不同大小(shape)的數組之間也可能進行運算。廣播是一種強有力的機制,它讓Numpy可以讓不同大小的矩陣在一起進行數學計算

最簡單的一種情況是一個數組和一個標量的操作

import numpy as npnn# 兩個shape相同的數組相乘na = np.array([1.0, 2.0, 3.0])nb = np.array([2.0, 2.0, 2.0])nprint(a * b) # 列印 "[ 2. 4. 6.]"nn# 一個數組和一個標量相乘na = np.array([1., 2., 3.])nb = 2.0nprint(a*b) # 列印 "[ 2. 4. 6.]"nnn這個結果和前面b是數組的例子的結果相同。我們可以認為b在運算中被擴展成了和a尺寸相同的數組,nb中新元素就是原來元素的拷貝。當然這個關於擴展的類別只是概念上的。Numpy是非常智能的,n可以只使用一個標量而不用拷貝來完成這個操作。所以廣播操作的內存和計算效率都是很高的。n第二個例子比第一個例子更高效,因為廣播在進行乘法操作時移動更少的內存。nn

一般的廣播規則

  1. 如果數組的秩不同,使用1來將秩較小的數組進行擴展,直到兩個數組的尺寸的長度都一樣。
  2. 如果兩個數組在某個維度上的長度是一樣的,或者其中一個數組在該維度上長度為1,那麼我們就說這兩個數組在該維度上是相容的。
  3. 如果兩個數組在所有維度上都是相容的,他們就能使用廣播。
  4. 如果兩個輸入數組的尺寸不同,那麼注意其中較大的那個尺寸。因為廣播之後,兩個數組的尺寸將和那個較大的尺寸一樣。
  5. 在任何一個維度上,如果一個數組的長度為1,另一個數組長度大於1,那麼在該維度上,就好像是對第一個數組進行了複製。

如果上述解釋看不明白,可以讀一讀文檔。

import numpy as npnn# 計算向量外積nv = np.array([1,2,3]) # v的shape= (3,)nw = np.array([4,5]) # w的shape= (2,)nn# 為了計算外積,我們先把v變成(3,1)的列向量;n# 結果如下n# [[ 4 5]n# [ 8 10]n# [12 15]]nprint np.reshape(v, (3, 1)) * wnn# 把向量加到矩陣的每一行nx = np.array([[1,2,3], [4,5,6]])nprint x + v # 列印 "[[2 4 6]n # [5 7 9]]"n

數組形狀操作

Flattening

import numpy as npnna = np.array([[1,2,3],[4,5,6]])n# 以下兩個函數都將多維數組變成一維數組n# 區別是 ravel 返回視圖;flatten 返回拷貝。n# 結果都是 "[1 2 3 4 5 6]"nprint(a.ravel()) nprint(a.flatten())n

Reshaping

import numpy as npnna = np.array([1,2,3,4,5,6])nprint(b.reshape(2,3)) # 列印 "[[1 2 3]n # [4 5 6]]"n

添加維度

使用np.newaxis對象允許我們為數組添加一個維度

import numpy as npnnz = np.array([1, 2, 3])nn# 數組 shape= (3, 1)n# 結果 "[[1]n# [2] n# [3]]"nprint(z[:,np.newaxis])nn# 數組 shape = (1, 3)n# 結果 " [[1 2 3]]"npirnt(z[np.newaxis,:]) n

Dimension shuffling

import numpy as npnna = np.arange(4*3*2).reshape(4,3,2)nprint(a.shape) # 列印 "(4, 3, 2)"nn# 將數組a的維度次序改變得到bn# 後兩個維度移到前兩個維度,第一個維度移到最後nb = a.transpose(1,2,0) # transpose得到的數組b是數組a的視圖nprint(b.shape) # 列印 "(3, 2, 4)"nprint(a[0,2,1] == b[2,1,0]) # 列印 "True"n

合併

import numpy as npnnA = np.array([1,1,1])nB = np.array([2,2,2])nn# 在豎直方向上疊加數組A,Bn# 結果如下n# [[1 1 1]n# [2 2 2]]nprint(np.vstack((A,B)))nn# 在水平方向上疊加數組A,Bn# 結果如下n# [1 1 1 2 2 2]nprint(np.hstack((A,B)))nn# 在不存在的維度上組合數組nprint(np.stack((A,B),axis=0)) # shape = (2, 3)n # [[1 1 1]n # [2 2 2]]nnprint(np.stack((A,B),axis=1)) # shape = (3, 2)n # [[1 2]n # [1 2]n # [1 2]]nn# 在存在的維度上組合數組nA = A[np.newaxis,:] # shape = (1,3)nB = B[np.newaxis,:] # shape = (1,3)nprint(np.concatenate((A,B),axis=0)) # shape = (2, 3)n # [[1 1 1]n # [2 2 2]]nprint(np.concatenate((A,B),axis=1)) # shape = (1, 6)n # [[1 1 1 2 2 2]]n

分割

split的第二個參數可以是整數或者一維數組。

  • 如果是整數。數組將被分為N個相等的數組。如果無法分成相等的數組,將會報錯。
  • 如果是一維數組。數組的每一個元素表明了在哪個位置分割數組。舉個例子:

[2, 3] ,當axis=0時,結果為:

- ary[:2]

- ary[2:3]

- ary[3:]

import numpy as npnn# 創建數組,shape = (3, 4)n# [[ 0 1 2 3]n# [ 4 5 6 7]n# [ 8 9 10 11]]nA = np.arange(12).reshape((3, 4))nn# 縱向分割n# 結果如下n# [array([[0, 1],n# [4, 5],n# [8, 9]]), array([[ 2, 3],n# [ 6, 7],n# [10, 11]])]nprint(np.split(A,2,axis=1))nn# 橫向分割n# 結果如下n# [array([[0, 1, 2, 3]]), array([[4, 5, 6, 7]]), array([[ 8, 9, 10, 11]])]nprint(np.split(A,3,axis=0))nn# split不均等分割n# 結果如下n# [array([[0, 1, 2, 3]]), array([[4, 5, 6, 7]]), array([[ 8, 9, 10, 11]])]nprint(np.split(A[1,2],axis=0))nn# array_split進行不等量分割n# array_split和split唯一的區別是:n# array_split允許indices_or_sections是一個將數組不等分的整數n# 結果如下n# [array([[0, 1, 2, 3],n# [4, 5, 6, 7]]), array([[ 8, 9, 10, 11]])]nprint(np.array_split(A, 2, axis=0))n

數據排序

import numpy as npnn# 創建2維數組,shape = (2, 3)n# [[4 3 5]n# [1 2 1]]na = np.array([[4, 3, 5], [1, 2, 1]])nn# 可以在數組的某一維排序n# 結果如下n# [[3 4 5]n# [1 1 2]]nprint(np.sort(a, axis=1)) nn# 原地(in-place)排序n# a本身會被排序,列印a結果如下n# [[3 4 5]n# [1 1 2]]na.sort(axis=1)nprint(a)nn# 排序與數組索引技巧結合:nb = np.array([4, 3, 1, 2])nj = np.argsort(a)nprint(j) # 列印 "[2 3 1 0]" 對應排序後元素原來的索引nprint(b[j]) # 列印 "[1 2 3 4]" 用數組j索引得到排序後的數組nn# 找出極大、極小值對應的元素索引nc = np.array([3, 4, 1, 2])nj_max = np.argmax(b)nj_min = np.argmin(b)nprint(j_max) # 最大值索引 "1"nprint(j_min) # 最小值索引 "2"n

Numpy文檔

這篇教程涉及了你需要了解的numpy中的一些重要內容,但是numpy遠不止如此。可以查閱官方文檔來學習更多。

參考

本文寫作時參考、借鑒了一下內容:

  1. 官方 Quickstart tutorial
  2. 智能單元專欄翻譯文章 Python Numpy教程
  3. Scipy lecture notes Numpy部分

寫在最後

萬丈高樓平地起,希望這個教程對剛入門深度學習的小夥伴們有一定的幫助。

推薦閱讀:

Abaqus中如何根據不同的材料來創建對應的set?
學習數據結構有什麼用?
python多進程進程間通信疑問,求大神指教?(主進程獲取不到子進程變數)
Python · 神經網路(五)· Cost & Optimizer
如何學好編程

TAG:Python | numpy | 深度学习DeepLearning |