本筆記來自于菜鳥教程,整理自己用到的部分,并更新一些例子。
Numpy 基本知識
NumPy(Numerical Python) 是 Python 語言的一個擴充程式庫,支援大量的次元數組與矩陣運算,此外也針對數組運算提供大量的數學函數庫,主要用于數組計算。
安裝
最簡單的是使用 Pip 安裝:
python -m pip install --user numpy
測試一下:
python -c "import numpy as np; print np.__version__"
列印出版本就沒問題了。
Ndarray
NumPy 最重要的一個特點是其 N 維數組對象 ndarray,它是一系列同類型資料的集合,以 0 下标為開始進行集合中元素的索引。ndarray 對象是用于存放同類型元素的多元數組。
numpy.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0)
其中:
- object: 數組或嵌套的數列
- dtype: 數組元素的資料類型,可選
- copy: 對象是否需要複制,可選
- order: 建立數組的樣式,C為行方向,F為列方向,A為任意方向(預設)
- subok: 預設傳回一個與基類類型一緻的數組
- ndmin: 指定生成數組的最小次元
一般情況下前兩個參數是必須有的,其餘參數較少使用。如:
import numpy as np
np.array([1, 2, 3], dtype=np.int8)
ndarray 的屬性
numpy 中比較重要的 ndarray 對象屬性有:
- ndarray.ndim: 秩,即軸的數量或次元的數量
- ndarray.shape: 數組的次元,對于矩陣,n 行 m 列
- ndarray.size: 數組元素的總個數,相當于 .shape 中 n*m 的值
- ndarray.dtype: ndarray 對象的元素類型
- ndarray.itemsize: ndarray 對象中每個元素的大小,以位元組為機關
- ndarray.flags: ndarray 對象的記憶體資訊
- ndarray.real: ndarray元素的實部
- ndarray.imag: ndarray 元素的虛部
- ndarray.data: 包含實際數組元素的緩沖區,由于一般通過數組的索引擷取元素,是以通常不需要使用這個屬性。
建立數組
常用建立數組的方式:
- 從已有數組建立: numpy.asarray(a, dtype = None, order = None)
- 未初始化數組:numpy.empty(shape, dtype = float, order = 'C')
- 全0數組:numpy.zeros(shape, dtype = float, order = 'C')
- 全1數組:numpy.ones(shape, dtype = None, order = 'C')
- 數值範圍數組:numpy.arange(start, stop, step, dtype)
- 等差序列數組:np.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)
- 等比序列數組:np.logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None)
- 對角數組:numpy.eye(N, M=None, k=0, dtype=, order='C')
其中: shape: 數組形狀
dtype: 資料類型 order: 有"C"和"F"兩個選項,分别代表,行優先和列優先,在計算機記憶體中的存儲元素的順序。
start: 起始值,預設為0 stop: 終止值(不包含)
step: 步長,預設為1 dtype: 傳回ndarray的資料類型,如果沒有提供,則會使用輸入資料的類型。
num: 要生成的等步長的樣本數量,預設為50
執行個體
numpy.asarray
# 後面預設引入 numpy
import numpy as np
x = [1, 2, 3]
a = np.asarray(x)
print a
x = [(1,2,3),(4,5)]
a = np.asarray(x, dtype = float)
print a
numpy.empty
numpy.empty(shape, dtype = float, order = 'C')
# empty 建立的數組未初始化,裡面的值是随機的
np.empty([3,2], dtype = int)
array([[ 0, 42832192],
[140268302237152, 9392928],
[140268278696400, 140268278694992]])
numpy.zeros
numpy.zeros(shape, dtype = float, order = 'C')
# 這裡比較好玩的是 shape 的 (5), (5,), [5] 得到的是一樣的
x = np.zeros((5,2), dtype = np.int)
print(x)
numpy.ones
x = np.ones([2,2], dtype = int)
print(x)
numpy.arange
x = np.arange(5, dtype = float)
print x
np.linspace
a = np.linspace(10, 20, 5, endpoint = False)
np.logspace
a = np.logspace(1.0, 2.0, num = 10)
numpy.eye
numpy.eye(N, M=None, k=0, dtype=, order='C')
# 正常的方陣對角矩陣
x = np.eye(2, dtype=int)
array([[1, 0],
[0, 1]])
# 生成非方陣
x = np.eye(2, 3, dtype=int)
array([[1, 0, 0],
[0, 1, 0]])
# 非主對角線的對角矩陣,通過 k 值進行調整,預設為0
np.eye(3, dtype=int, k=1)
array([[0, 1, 0],
[0, 0, 1],
[0, 0, 0]])
Numpy 索引
基本的切片與索引
ndarray對象的内容可以通過索引或切片來通路和修改,與 Python 中 list 的切片操作一樣。ndarray 數組可以基于 0 - n 的下标進行索引,切片對象可以通過内置的 slice 函數,并設定 start, stop 及 step 參數進行,從原數組中切割出一個新數組。
import numpy as np
# 切片
a = np.arange(10)
s = slice(2, 7, 2)
print a[s]
print a[2:7:2]
# 索引
print a[5]
進階索引
NumPy 比一般的 Python 序列提供更多的索引方式。除了之前看到的用整數和切片的索引外,數組可以由整數數組索引、布爾索引及花式索引。
整數數組索引
import numpy as np
x = np.array([[1, 2], [3, 4], [5, 6]])
# 取出索引(0,0), (1,1), (2,0) 三個位置的元素
y = x[[0,1,2], [0,1,0]]
print y
out: array([1, 4, 5])
# 更新版。。。
x = np.array([[ 0, 1, 2 ],[ 3, 4, 5 ],[ 6, 7, 8 ],[ 9, 10, 11 ]])
rows = np.array([[0,0],[3,3]])
cols = np.array([[0,2],[0,2]])
print x[rows, cols]
out: [[ 0 2 ]
[ 9 11 ]]
布爾索引
我們可以通過一個布爾數組來索引目标數組。而布爾數組可以通過布爾運算來擷取符合指定條件的元素的數組。
import numpy as np
x = np.array([[ 0, 1, 2 ],[ 3, 4, 5 ],[ 6, 7, 8 ],[ 9, 10, 11 ]])
# 擷取值大于5的元素
print (x[x > 5])
out: [ 6 7 8 9 10 11 ]
花式索引
花式索引指的是利用整數數組進行索引。花式索引根據索引數組的值作為目标數組的某個軸的下标來取值。對于使用一維整型數組作為索引,如果目标是一維數組,那麼索引的結果就是對應位置的元素;如果目标是二維數組,那麼就是對應下标的行。
花式索引跟切片不一樣,它總是将資料複制到新數組中。import numpy as np
x=np.arange(32).reshape((8,4))
# 順序數組
print (x[[4,2,1,7]])
# 倒序索引
print (x[[-4,-2,-1,-7]])
# 多個索引數組
print (x[np.ix_([1,5,7,2],[0,3,1,2])])
數組操作
正常操作
Numpy 中包含了一些函數用于處理數組,大概可分為以下幾類:
- 修改數組形狀
- reshape numpy.reshape(arr, newshape, order='C')
- flat
- flatten
- ravel
- 翻轉數組
- transpose
- ndarray.T
- rollaxis
- swapaxes
- 修改數組次元
- broadcast
- broadcast_to
- expand_dims
- squeeze
- 連接配接數組
- concatenate
- stack
- hstack
- vstack
- 分割數組
- split
- hsplit
- vsplit
- 數組元素的添加與删除
- resize
- append
- insert
- delete
- unique
修改數組形狀
reshape
numpy.reshape 函數可以在不改變資料的條件下修改形狀, numpy.reshape(arr, newshape, order='C')
import numpy as np
x = np.arange(8)
print x.shape, x
y = x.reshape(2,4)
print y.shape, y
numpy.ndarray.flat
numpy.ndarray.flat 是一個數組元素疊代器,
将數組轉換為1-D的疊代器. 執行個體如下:
import numpy as np
a = np.arange(9).reshape(3,3)
for row in a:
print row
out: [0 1 2]
[3 4 5]
[6 7 8]
# 如果用 flat
for ele in a.flat:
print ele
out :
0
1
2
3
4
5
6
7
8
numpy.ndarray.flatten
numpy.ndarray.flatten 将數組的副本轉換為一維,并傳回.傳回一份數組拷貝,對拷貝所做的修改不會影響原始數組,格式如下:
ndarray.flatten(order='C')
其中 order:'C' -- 按行,'F' -- 按列,'A' -- 原順序,'K' -- 元素在記憶體中的出現順序。這個也适用于上面的其他 order選項。
import numpy as np
a = np.arange(8).reshape(2,4)
print a.flatten()
# 可以看出,flat 傳回的是一個一維疊代器,而flatten傳回的是一個一維數組,并且是新的副本
out: [0 1 2 3 4 5 6 7]
numpy.ravel
numpy.ravel() 展平的數組元素,順序通常是"C風格",傳回的是數組視圖(view,有點類似 C/C++引用reference的意味),修改會影響原始數組。看起來它和 flatten很像。
首先聲明兩者所要實作的功能是一緻的(将多元數組降位一維)。這點從兩個單詞的意也可以看出來,ravel(散開,解開),flatten(變平)。兩者的差別在于傳回拷貝(copy)還是傳回視圖(view),numpy.flatten()傳回一份拷貝,對拷貝所做的修改不會影響(reflects)原始矩陣,而numpy.ravel()傳回的是視圖(view,也頗有幾分C/C++引用reference的意味),會影響(reflects)原始矩陣。
格式為 : numpy.ravel(a, order='C')
import numpy as np
a = np.arange(8).reshape(2,4)
b = a.flatten()
c = a.ravel()
print b
out: array([0, 1, 2, 3, 4, 5, 6, 7])
print c
out: array([0, 1, 2, 3, 4, 5, 6, 7])
c[0] = 1
print a
# 看到對c的修改,在a上也生效了,但是b沒變
out: array([[1, 1, 2, 3], [4, 5, 6, 7]])
print b
out: array([0, 1, 2, 3, 4, 5, 6, 7])
print c
out: array([1, 1, 2, 3, 4, 5, 6, 7])
翻轉數組
numpy.transpose 與 ndarray.T
numpy.transpose 函數用于對換數組的次元,如形狀 (2,3,4) transpose 後就變成 (4,3,2)。ndarray.T 和它的功能一緻。transpose的格式為:numpy.transpose(arr, axes)
import numpy as np
a = np.arange(120).reshape(2,3,4, 5)
b = np.transpose(a)
print b.shape
out: (5, 4, 3, 2)
c = a.T
print c.shape
numpy.swapaxes
numpy.swapaxes 函數用于交換數組的兩個軸,格式為:numpy.swapaxes(arr, axis1, axis2)
import numpy as np
a = np.arange(24).reshape(2,3,4)
b = np.swapaxes(a, 1, 2)
print b.shape
out: (2, 4, 3)
numpy.rollaxis
numpy.rollaxis 函數向後滾動特定的軸到一個特定位置,格式為:numpy.rollaxis(arr, axis, start)
mport numpy as np
a = np.arange(120).reshape(2,3,4, 5)
# 直覺上了解就是在形狀元組中的第二個次元4插入到指定位置(預設為0)。
b = np.rollaxis(a, 2)
print b.shape
out: (4, 2, 3, 5)
# 通過第三個參數指定插入的位置
b = np.rollaxis(a, 3, 1)
print b.shape
out: (2, 5, 3, 4)
修改數組的次元
numpy.broadcast
numpy.broadcast 用于模仿廣播的對象,它傳回一個對象,該對象封裝了将一個數組廣播到另一個數組的結果。該函數使用兩個數組作為輸入參數,如下執行個體:
import numpy as np
x = np.array([[1], [2], [3]])
y = np.array([4, 5, 6])
# 對y 廣播 x
b = np.broadcast(x,y)
print b
numpy.broadcast_to
numpy.broadcast_to 函數将數組廣播到新形狀。它在原始數組上傳回隻讀視圖。 它通常不連續。 如果新形狀不符合 NumPy 的廣播規則,該函數可能會抛出ValueError。格式為:numpy.broadcast_to(array, shape, subok)
import numpy as np
a = np.arange(4).reshape(1,4)
print (np.broadcast_to(a,(4,4)))
numpy.expand_dims
numpy.expand_dims 函數通過在指定位置插入新的軸來擴充數組形狀,函數格式: numpy.expand_dims(arr, axis)
import numpy as np
x = np.array(([1,2],[3,4]))
y = np.expand_dims(x, axis = 1)
print y.shape
out: (2, 1, 2)
numpy.squeeze
numpy.squeeze 函數從給定數組的形狀中删除一維的條目,函數格式:numpy.squeeze(arr, axis),預設删除全部。
import numpy as np
x = np.arange(9).reshape(1,1,3,3)
y = np.squeeze(x)
print y.shape
out: (3, 3)
y = np.squeeze(x, axis=0)
y.shape
out: (1, 3, 3)
連接配接數組
numpy.concatenate
numpy.concatenate 函數用于沿指定軸連接配接相同形狀的兩個或多個數組,格式如下: numpy.concatenate((a1, a2, ...), axis)
import numpy as np
a = np.array([[1,2],[3,4]])
b = np.array([[5,6],[7,8]])
print (np.concatenate((a,b), axis=0))
out: [[1 2]
[3 4]
[5 6]
[7 8]]
print (np.concatenate((a,b),axis = 1))
out: [[1 2 5 6]
[3 4 7 8]]
numpy.stack
numpy.stack 函數用于沿新軸連接配接數組序列,格式如下: numpy.stack(arrays, axis)
它與 numpy.concatenate 的差別主要是 stack 會增加一個次元,給我的感覺它就像把兩個數組堆疊在一起,而 concatenate 是連接配接構成一個新的數組。
import numpy as np
a = np.array([[1,2],[3,4]])
b = np.array([[5,6],[7,8]])
print (np.stack((a,b),0))
out: [[[1 2]
[3 4]]
[[5 6]
[7 8]]]
print (np.stack((a,b),1))
out: [[[1 2]
[5 6]]
[[3 4]
[7 8]]]
numpy.hstack
numpy.hstack 是 numpy.stack 函數的變體,它通過水準堆疊來生成數組。
import numpy as np
a = np.array([[1,2],[3,4]])
b = np.array([[5,6],[7,8]])
# 可以看到,這個的結果和 np.concatenate((a,b),axis = 1) 是一樣的
print np.hstack((a,b))
out: [[1 2 5 6]
[3 4 7 8]]
numpy.vstack
numpy.vstack 是 numpy.stack 函數的變體,它通過垂直堆疊來生成數組。
import numpy as np
a = np.array([[1,2],[3,4]])
b = np.array([[5,6],[7,8]])
# 和 np.concatenate((a,b),axis = 0) 一緻
print np.vstack((a,b))
out: [[1 2]
[3 4]
[5 6]
[7 8]]
分個數組
numpy.split
numpy.split 函數沿特定的軸将數組分割為子數組,格式如下:numpy.split(ary, indices_or_sections, axis)
import numpy as np
a = np.arange(9)
print np.split(a,3)
out: [array([0, 1, 2]), array([3, 4, 5]), array([6, 7, 8])]
# 通過數組指定切割位置
print np.split(a, [4, 7])
out: [array([0, 1, 2, 3]), array([4, 5, 6]), array([7, 8])]
numpy.hsplit
numpy.hsplit 函數用于水準分割數組,通過指定要傳回的相同形狀的數組數量來拆分原數組。
import numpy as np
a = np.arange(9)
np.hsplit(a, 2)
Out[121]: [array([0, 1, 2, 3]), array([4, 5, 6, 7])]
np.hsplit(a, 4)
out: [array([0, 1]), array([2, 3]), array([4, 5]), array([6, 7])]
numpy.vsplit
numpy.vsplit 沿着垂直軸分割,其分割方式與hsplit用法相同。
import numpy as np
a = np.arange(16).reshape(4,4)
print np.vsplit(a,2)
out: [array([[0, 1, 2, 3],
[4, 5, 6, 7]]),
array([[ 8, 9, 10, 11 ],
[12, 13, 14, 15]])]
數組元素的添加與删除
numpy.resize
numpy.resize 函數傳回指定大小的新數組。 如果新數組大小大于原始大小,則包含原始數組中的元素的副本。 格式為:numpy.resize(arr, shape)
import numpy as np
a = np.array([[1,2,3],[4,5,6]])
print np.resize(a, (3,2))
out: array([[1, 2],
[3, 4],
[5, 6]])
# 最後一行的 [1, 2, 3] 就是元素副本填充得到的
print np.resize(a,(3,3))
out: [[1 2 3]
[4 5 6]
[1 2 3]]
numpy.append
numpy.append 函數在數組的末尾添加值。 追加操作會配置設定整個數組,并把原來的數組複制到新數組中。 此外,輸入數組的次元必須比對否則将生成ValueError。
append 函數傳回的始終是一個一維數組。格式為:numpy.append(arr, values, axis=None)
import numpy as np
a = np.array([[1,2,3],[4,5,6]])
print np.append(a, [7,8,9])
out: array([1, 2, 3, 4, 5, 6, 7, 8, 9])
# 沿軸 0 添加元素
np.append(a, [[7,8,9]],axis = 0)
out: array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
# 軸 1
np.append(a, [[5,5,5],[7,8,9]],axis = 1)
out: array([[1, 2, 3, 5, 5, 5],
[4, 5, 6, 7, 8, 9]])
numpy.insert
numpy.insert 函數在給定索引之前,沿給定軸在輸入數組中插入值。 如果值的類型轉換為要插入,則它與輸入數組不同。 插入沒有原地的,函數會傳回一個新數組。 此外,如果未提供軸,則輸入數組會被展開。格式為:numpy.insert(arr, obj, values, axis)
import numpy as np
a = np.array([[1,2],[3,4],[5,6]])
np.insert(a,3,[11,12])
out: array([ 1, 2, 3, 11, 12, 4, 5, 6 ])
numpy.delete
numpy.delete 函數傳回從輸入數組中删除指定子數組的新數組。 與 insert() 函數的情況一樣,如果未提供軸參數,則輸入數組将展開。格式為:Numpy.delete(arr, obj, axis)
import numpy as np
a = np.arange(12).reshape(3,4)
np.delete(a,5)
out: [ 0 1 2 3 4 6 7 8 9 10 11 ]
numpy.unique
numpy.unique 函數用于去除數組中的重複元素。格式為:numpy.unique(arr, return_index, return_inverse, return_counts)
import numpy as np
a = np.array([5,2,6,2,7,5,6,8,2,9])
np.unique(a)
out: [2 5 6 7 8 9]
NumPy 線性代數
NumPy 提供了線性代數函數庫 linalg,該庫包含了線性代數所需的所有功能。除此之外,Numpy 空間下也有一些常見操作。
- numpy.dot() 兩個數組的點積,即元素對應相乘。
- vdot 兩個向量的點積
- inner 兩個數組的内積
- matmul 兩個數組的矩陣積
- determinant 數組的行列式
- solve 求解線性矩陣方程
- inv 計算矩陣的乘法逆矩陣
numpy.dot()
numpy.dot() 對于兩個一維的數組,計算的是這兩個數組對應下标元素的乘積和(數學上稱之為内積);對于二維數組,計算的是兩個數組的矩陣乘積。
import numpy as np
a = np.array([1,2])
b = np.array([3,4])
np.dot(a, b)
out: 11
a = np.array([[1,2],[3,4]])
b = np.array([[11,12],[13,14]])
np.dot(a,b)
out: [[37 40]
[85 92]]
numpy.vdot()
numpy.vdot() 函數是兩個向量的點積。 如果第一個參數是複數,那麼它的共轭複數會用于計算。 如果參數是多元數組,它會被展開。
import numpy as np
a = np.array([[1,2],[3,4]])
b = np.array([[11,12],[13,14]])
np.vdot(a,b)
out: 130
numpy.matmul
numpy.matmul 函數傳回兩個數組的矩陣乘積。 雖然它傳回二維數組的正常乘積,但如果任一參數的維數大于2,則将其視為存在于最後兩個索引的矩陣的棧,并進行相應廣播。另一方面,如果任一參數是一維數組,則通過在其次元上附加 1 來将其提升為矩陣,并在乘法之後被去除。對于二維數組,它就是矩陣乘法:
import numpy as np
a = [[1,0],[0,1]]
b = [[4,1],[2,2]]
np.matmul(a,b)
out: [[4 1]
[2 2]]