介紹
NumPy 是一個運行速度非常快的數學庫,主要用於數組計算,包含:
- 一個強大的N維數組對象 ndarray
- 廣播功能函數
- 整合 C/C++/Fortran 代碼的工具
- 線性代數、傅里葉變換、隨機數生成等功能
另外,NumPy 還會經常與 SciPy(Scientific Python)和 Matplotlib(繪圖庫)一起使用。
安裝
pip安裝:
pip install numpy
導入模塊
導入之後通常會取個別名:
import numpy as np
數組
數組是一個值網格,所有類型都是相同類型的。和原生的列表(list)比較,列表裏的每個元素可以是不同的類型。
原生數組
python也是有數組的:
>>> import array # 導入模塊
>>> a1 = array.array('i') # 創建了一個數組,類型是i,就是int
>>> a1.append(1) # 添加一個元素
>>> a1.append(2)
>>> a1
array('i', [1, 2])
>>> len(a1)
2
這部分不是重點,就提一下。
創建數組
從列表生成數組
>>> l1 = [1, 2, 3, 4, 5]
>>> l2 = np.array(l1)
>>> l2
array([1, 2, 3, 4, 5])
>>> type(l1)
<class 'list'>
>>> type(l2)
<class 'numpy.ndarray'>
全0的數組
>>> np.zeros(3)
array([ 0., 0., 0.])
>>> np.zeros(3, dtype=int) # 默認是浮點數,可以指定類型
array([0, 0, 0])
全1的數組
>>> np.ones(3, int)
array([1, 1, 1])
多維數組
生成數組時,第一個參數,是可以指定維度的:
>>> np.ones((2, 4), int)
array([[1, 1, 1, 1],
[1, 1, 1, 1]])
>>> np.ones((3, 3), int)
array([[1, 1, 1],
[1, 1, 1],
[1, 1, 1]])
>>>
創建時填充其他值
>>> np.full((2,3), 'x')
array([['x', 'x', 'x'],
['x', 'x', 'x']],
dtype='<U1')
>>>
按一個數組爲模板創建數組
維度和元素類型都是一樣的,所以1.23被自動轉成了整數:
>>> t1 = np.zeros((3, 2), int) # 3*2 的int類型的數組
>>> np.full_like(t1, 1.23)
array([[1, 1],
[1, 1],
[1, 1]])
>>>
生成單位矩陣
>>> np.eye(3, dtype=int)
array([[1, 0, 0],
[0, 1, 0],
[0, 0, 1]])
>>> np.eye(3, k=1, dtype=int)
array([[0, 1, 0],
[0, 0, 1],
[0, 0, 0]])
>>> np.eye(3, 2, dtype=int)
array([[1, 0],
[0, 1],
[0, 0]])
在次對角線上生成全1的矩陣:
>>> np.eye(3, dtype=int)[::-1]
array([[0, 0, 1],
[0, 1, 0],
[1, 0, 0]])
隨機數數組
原生的random庫也能生成隨機數,不過NumPy庫的隨機數功能更強大
原生random模塊
>>> random.random() # 原生函數沒有參數,只能生成1個數
0.3145225040001337
>>> np.random.random(3) # 生成隨機數組
array([ 0.5298384 , 0.34748761, 0.52159409])
生成隨機數數組
隨機整數
>>> np.random.randint(1, 100, 2)
array([99, 77])
指定維度
>>> np.random.random((3, 3))
array([[ 0.72420303, 0.31726755, 0.39925357],
[ 0.57047567, 0.96920481, 0.06743519],
[ 0.76589897, 0.9075956 , 0.22296356]])
>>> np.random.randint(1, 10, (2, 5))
array([[7, 5, 2, 4, 6],
[2, 8, 3, 6, 8]])
取值範圍
np.arange
與原生的range差不多,可以指定起始、結束、步長,三個參數:
>>> np.arange(2)
array([0, 1])
>>> np.arange(3)
array([0, 1, 2])
>>> np.arange(1, 9)
array([1, 2, 3, 4, 5, 6, 7, 8])
>>> np.arange(1, 9, 3)
array([1, 4, 7])
>>> np.arange(1.0, 5.0, 0.7)
array([ 1. , 1.7, 2.4, 3.1, 3.8, 4.5])
np.linspace
給定起始和結束的值,自動計算中間的間隔,默認生成50個數:
>>> np.linspace(1, 2)
array([ 1. , 1.02040816, 1.04081633, 1.06122449, 1.08163265,
1.10204082, 1.12244898, 1.14285714, 1.16326531, 1.18367347,
1.20408163, 1.2244898 , 1.24489796, 1.26530612, 1.28571429,
1.30612245, 1.32653061, 1.34693878, 1.36734694, 1.3877551 ,
1.40816327, 1.42857143, 1.44897959, 1.46938776, 1.48979592,
1.51020408, 1.53061224, 1.55102041, 1.57142857, 1.59183673,
1.6122449 , 1.63265306, 1.65306122, 1.67346939, 1.69387755,
1.71428571, 1.73469388, 1.75510204, 1.7755102 , 1.79591837,
1.81632653, 1.83673469, 1.85714286, 1.87755102, 1.89795918,
1.91836735, 1.93877551, 1.95918367, 1.97959184, 2. ])
指定總數:
>>> np.linspace(1, 10, 5, dtype=int)
array([ 1, 3, 5, 7, 10])
不包括結尾的數:
>>> np.linspace(1, 10, 5, endpoint=True, dtype=int)
array([ 1, 3, 5, 7, 10])
>>> np.linspace(1, 10, 5, endpoint=False, dtype=int)
array([1, 2, 4, 6, 8])
顯示步長:
>>> np.linspace(1, 10, 5, retstep=True)
(array([ 1. , 3.25, 5.5 , 7.75, 10. ]), 2.25)
下面先設置了輸出小數和輸出精度,然後計算了將一個圓周切分n份的橫座標(sin值)和縱座標(cos值),最後再把之前的設置調回默認值:
>>> np.set_printoptions(precision=3, suppress=True)
>>> np.sin(np.linspace(0, np.pi*2, 8, endpoint=False))
array([ 0. , 0.707, 1. , 0.707, 0. , -0.707, -1. , -0.707])
>>> np.cos(np.linspace(0, np.pi*2, 8, endpoint=False))
array([ 1. , 0.707, 0. , -0.707, -1. , -0.707, -0. , 0.707])
>>> np.set_printoptions(edgeitems=3,infstr='inf', linewidth=75, nanstr='nan', precision=8, suppress=False, threshold=1000, formatter=None)
操作數組
訪問元素
訪問元素可以使用傳統的多維數組訪問方式來訪問:
>>> a2 = np.zeros((3, 3))
>>> a2
array([[ 0., 0., 0.],
[ 0., 0., 0.],
[ 0., 0., 0.]])
>>> a2[0][0] = 2 # 傳統的訪問方式
>>> a2[0, 0] # 看着和上面一樣
2.0
不過上面 [0, 0] 這種形式的功能更加強大,因爲這樣支持數組切片:
>>> a2[1:,1:] = 5
>>> a2
array([[ 2., 0., 0.],
[ 0., 5., 5.],
[ 0., 5., 5.]])
比較一下兩個訪問形式在多維數組情況時的區別:
>>> a2[1:, 1:]
array([[ 5., 5.],
[ 5., 5.]])
>>> a2[1:][1:]
array([[ 0., 5., 5.]])
傳統的方式是一種鏈式操作,是在前一次切片的基礎上再執行切片:
>>> tmp = a2[1:]
>>> tmp[1:]
array([[ 0., 5., 5.]])
>>> a2[1:][1:]
array([[ 0., 5., 5.]])
數組屬性
維度
繼續使用上面的二維數組:
>>> a2.ndim
2
>>> a2[1].ndim # 取出其中一個值,就是個一維數組了
1
形狀
>>> a2.shape
(3, 3)
>>> a2[1:,].shape
(2, 3)
元素總數
>>> a2.size
9
>>> a2[1:, 1:].size
4
元素類型
>>> a2.dtype
dtype('float64')
佔用的字節數
>>> a2.itemsize # 每個用上佔用的字節數
8
>>> a2.nbytes # 整個數組佔用的字節數
72
float64類型,佔8字節。類型不同佔用的字節數就不一樣,另外字符串的情況還更復雜的樣子。不過主要用來做數學計算的:
>>> np.array([1, 2, 3]).itemsize
4
>>> np.array(['a']).itemsize
4
>>> np.array(['a', 'ij', 'xyz']).itemsize
12
>>> np.array(['a', 'ij', 'xyz']).nbytes
36
數組操作
變形
變形前後要求元素的總數size要一樣:
>>> np.eye(4 ,4)
array([[ 1., 0., 0., 0.],
[ 0., 1., 0., 0.],
[ 0., 0., 1., 0.],
[ 0., 0., 0., 1.]])
>>> np.eye(4, 4).reshape(2, 8)
array([[ 1., 0., 0., 0., 0., 1., 0., 0.],
[ 0., 0., 1., 0., 0., 0., 0., 1.]])
排序
>>> sort0 = np.random.randint(0, 10, (3, 3))
>>> sort0
array([[0, 5, 9],
[7, 7, 7],
[7, 3, 6]])
>>> np.sort(sort0) # 默認橫向排序
array([[0, 5, 9],
[7, 7, 7],
[3, 6, 7]])
>>> np.sort(sort0, axis=None)
array([0, 3, 5, 6, 7, 7, 7, 7, 9])
>>> np.sort(sort0, axis=0) # 0是縱向排序
array([[0, 3, 6],
[7, 5, 7],
[7, 7, 9]])
拼接
>>> c1 = np.array((1, 2, 3))
>>> c2 = np.array((9, 8, 7))
>>> np.concatenate((c1, c2, c1))
array([1, 2, 3, 9, 8, 7, 1, 2, 3])
axis只有在多維數組拼接時候可以設置爲1,拼接的效果也不同:
>>> c3 = [[1, 2], [3, 4]]
>>> c4 = [[5, 6], [7, 8]]
>>> np.concatenate((c3, c4), axis=0)
array([[1, 2],
[3, 4],
[5, 6],
[7, 8]])
>>> np.concatenate((c3, c4), axis=1)
array([[1, 2, 5, 6],
[3, 4, 7, 8]])
統計
簡單的求和,和原生數組沒差別:
>>> sum(np.arange(1, 101))
5050
以二維數組舉例,可以對橫向縱向每個維度進行求和:
>>> np.array([i+1 for i in range(9)]).reshape(3, 3)
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
>>> a3 = np.array([i+1 for i in range(9)]).reshape(3, 3)
>>> np.sum(a3)
45
>>> np.sum(a3, axis=0)
array([12, 15, 18])
>>> np.sum(a3, axis=1)
array([ 6, 15, 24])
轉置
>>> np.array(([1, 2, 3], [4, 5, 6]))
array([[1, 2, 3],
[4, 5, 6]])
>>> np.transpose(np.array(([1, 2, 3], [4, 5, 6])))
array([[1, 4],
[2, 5],
[3, 6]])
反轉
python的反轉很方便,所以沒有專門的方法:
>>> [1, 2, 3][::-1]
[3, 2, 1]
旋轉
配合轉置和反轉就可以實現:
>>> a4 = np.array([i+1 for i in range(12)]).reshape(3, 4)
>>> a4
array([[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12]])
>>> np.transpose(a4[::-1])
array([[ 9, 5, 1],
[10, 6, 2],
[11, 7, 3],
[12, 8, 4]])
>>> np.transpose(a4[:, ::-1])
array([[ 4, 8, 12],
[ 3, 7, 11],
[ 2, 6, 10],
[ 1, 5, 9]])