NumPy

介紹

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]])
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章