天天看點

NumPy之:ndarray中的函數簡介簡單函數矢量化數組運算條件邏輯表達式統計方法布爾數組排序檔案線性代數随機數

簡介

在NumPy中,多元數組除了基本的算數運算之外,還内置了一些非常有用的函數,可以加快我們的科學計算的速度。

簡單函數

我們先看下比較常見的運算函數,在使用之前,我們先構造一個數組:

arr = np.arange(10)      
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])      

計算數組中元素的開方:

np.sqrt(arr)      
array([0.    , 1.    , 1.4142, 1.7321, 2.    , 2.2361, 2.4495, 2.6458,
       2.8284, 3.    ])      

自然常數e為底的指數函數:

np.exp(arr)      
array([   1.    ,    2.7183,    7.3891,   20.0855,   54.5982,  148.4132,
        403.4288, 1096.6332, 2980.958 , 8103.0839])      

取兩個數組的最大值,組成新的數組:

x = np.random.randn(8)
y = np.random.randn(8)
x,y      
(array([-2.3594, -0.1995, -1.542 , -0.9707, -1.307 ,  0.2863,  0.378 ,
        -0.7539]),
 array([ 0.3313,  1.3497,  0.0699,  0.2467, -0.0119,  1.0048,  1.3272,
        -0.9193]))      
np.maximum(x, y)      
array([ 0.3313,  1.3497,  0.0699,  0.2467, -0.0119,  1.0048,  1.3272,
       -0.7539])      

返 回浮點數數組的小數和整數部分:

arr = np.random.randn(7) * 5      
array([-7.7455,  0.1109,  3.7918, -3.3026,  4.3129, -0.0502,  0.25  ])      
remainder, whole_part = np.modf(arr)      
(array([-0.7455,  0.1109,  0.7918, -0.3026,  0.3129, -0.0502,  0.25  ]),
 array([-7.,  0.,  3., -3.,  4., -0.,  0.]))      

矢量化數組運算

如果要進行數組之間的運算,常用的方法就是進行循環周遊,但是這樣的效率會比較低。是以Numpy提供了數組之間的資料處理的方法。

先來講解一下 np.meshgrid 這個函數,這個函數是用來快速生成網格點坐标矩陣的。

先看一段坐标點的代碼:

import numpy as np
import matplotlib.pyplot as plt
x = np.array([[0, 1, 2], [0, 1, 2]])
y = np.array([[0, 0, 0], [1, 1, 1]])
plt.plot(x, y,
         color='green',
         marker='.',
         linestyle='')
plt.grid(True)
plt.show()      

上面的X是一個二維數組,表示的是坐标點的X軸的位置。

Y也是一個二維數組,表示的是坐标點的Y軸的位置。

看下畫出來的圖像:

上面畫出的就是使用X,Y矩陣組合出來的6個坐标點。

上面的X,Y的二維數組是我們手動輸入的,如果坐标上面有大量點的話,手動輸入肯定是不可取的。

于是有了np.meshgrid這個函數。這個函數可以接受兩個一維的數組,然後生成二維的X,Y坐标矩陣。

上面的例子可以改寫為:

x = np.array([0,1,2])
y = np.array([0,1])
xs, ys = np.meshgrid(x, y)
xs,ys
(array([[0, 1, 2],
        [0, 1, 2]]), 
 array([[0, 0, 0],
        [1, 1, 1]]))      

可以看到生成的xs和ys和手動輸入是一樣的。

有了網格坐标之後,我們就可以基于網格值來計算一些資料,比如:sqrt(x^2+y^2)sqrt(x2+y2) ,我們不用變量矩陣中所有的資料,隻需要直接使用數組進行運算即可:

np.sqrt(xs ** 2 + ys ** 2)      

結果:

array([[0.        , 1.        , 2.        ],
       [1.        , 1.41421356, 2.23606798]])      

因為xs 和ys本身就是2 * 3 的矩陣,是以結果也是 2 * 3 的矩陣。

條件邏輯表達式

我們可以在建構數組的時候使用條件邏輯表達式:

xarr = np.array([1.1, 1.2, 1.3, 1.4, 1.5])
yarr = np.array([2.1, 2.2, 2.3, 2.4, 2.5])
cond = np.array([True, False, True, True, False])      
result = [(x if c else y)
          for x, y, c in zip(xarr, yarr, cond)]
result      
[1.1, 2.2, 1.3, 1.4, 2.5]      

更簡單一點,我們可以使用where語句:

result = np.where(cond, xarr, yarr)
result      
array([1.1, 2.2, 1.3, 1.4, 2.5])      

我們還可以根據where的條件來修改數組的值:

arr = np.random.randn(4, 4)
arr
array([[ 0.7953,  0.1181, -0.7485,  0.585 ],
       [ 0.1527, -1.5657, -0.5625, -0.0327],
       [-0.929 , -0.4826, -0.0363,  1.0954],
       [ 0.9809, -0.5895,  1.5817, -0.5287]])      

上面我們建構了一個4 * 4 的數組。

我們可以在where中進行資料的比較,如果大于0,将資料修改成2 ,如果小于0,則将資料修該成-2 :

np.where(arr > 0, 2, -2)
array([[ 2,  2, -2,  2],
       [ 2, -2, -2, -2],
       [-2, -2, -2,  2],
       [ 2, -2,  2, -2]])      

統計方法

numpy提供了mean,sum等統計方法:

arr = np.random.randn(5, 4)
arr
arr.mean()
np.mean(arr)
arr.sum()      

還可以按次元來統計:

arr.mean(axis=1)
arr.sum(axis=0)      

cumsum進行累加計算:

arr = np.array([0, 1, 2, 3, 4, 5, 6, 7])
arr.cumsum()      
array([ 0,  1,  3,  6, 10, 15, 21, 28])      

cumprod進行累乘計算:

arr = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
arr
arr.cumsum(axis=0)      
array([[ 0,  1,  2],
       [ 3,  5,  7],
       [ 9, 12, 15]])      
arr.cumprod(axis=1)      
array([[  0,   0,   0],
       [  3,  12,  60],
       [  6,  42, 336]])      

布爾數組

any用于測試數組中是否存在一個或多個True,而all則檢查數組中所有值是否都是True:

bools = np.array([False, False, True, False])
bools.any()
True      
bools.all()
False      

排序

使用sort可以對數組進行排序,除了普通排序還可以按照特定的軸來進行排序:

arr = np.random.randn(6)
arr.sort()      
array([-2.5579, -1.2943, -0.2972, -0.1516,  0.0765,  0.1608])      
arr = np.random.randn(5, 3)
arr
arr.sort(1)
arr      
array([[-0.8852, -0.4936, -0.1875],
       [-0.3507, -0.1154,  0.0447],
       [-1.1512, -0.8978,  0.8909],
       [-2.6123, -0.8671,  1.1413],
       [-0.437 ,  0.3475,  0.3836]])      

sort(1)指的是按照第二個軸來排序。

檔案

可以友善的将數組寫入到檔案和從檔案中讀出:

arr = np.arange(10)
np.save('some_array', arr)      

會将數組存放到some_array.npy檔案中,我們可以這樣讀取:

np.load('some_array.npy')      

還可以以無壓縮的方式存入多個數組:

np.savez('array_archive.npz', a=arr, b=arr)      

讀取:

arch = np.load('array_archive.npz')
arch['b']      

如果想要壓縮,可以這樣:

np.savez_compressed('arrays_compressed.npz', a=arr, b=arr)      

線性代數

如果我們使用普通的算數符來進行矩陣的運算的話,隻是簡單的數組中對應的元素的算數運算。如果我們想做矩陣之間的乘法的時候,可以使用dot。

一個 2 * 3 的矩陣 dot 一個3*2 的矩陣,最終得到一個2 * 2 的矩陣。

x = np.array([[1., 2., 3.], [4., 5., 6.]])
y = np.array([[6., 23.], [-1, 7], [8, 9]])
x
y
x.dot(y)      
array([[ 28.,  64.],
       [ 67., 181.]])      

或者可以這樣寫:

np.dot(x, y)      
array([[ 28.,  64.],
       [ 67., 181.]])      

還可以使用 @ 符号:

x @ y      
array([[ 28.,  64.],
       [ 67., 181.]])      

我們看下都有哪些運算:

乘積運算:

操作符 描述
dot(a, b[, out]) 矩陣點積
linalg.multi_dot(arrays, *[, out]) 多個矩陣點積
vdot(a, b) 向量點積
inner(a, b) 兩個數組的内積
outer(a, b[, out]) 兩個向量的外積
matmul(x1, x2, /[, out, casting, order, …]) 兩個矩陣的對應位的乘積
tensordot(a, b[, axes]) 計算沿指定軸的張量點積
einsum(subscripts, *operands[, out, dtype, …]) 愛因斯坦求和約定
einsum_path(subscripts, *operands[, optimize]) 通過考慮中間數組的建立,評估einsum表達式的最低成本收縮順序。
linalg.matrix_power(a, n) 矩陣的幂運算
kron(a, b) 矩陣的Kronecker乘積

分解運算:

linalg.cholesky(a) Cholesky 分解
linalg.qr(a[, mode]) 計算矩陣的qr因式分解
linalg.svd(a[, full_matrices, compute_uv, …]) 奇異值分解

本征值和本征向量:

操作
linalg.eig(a) 計算方陣的特征值和右特征向量。
linalg.eigh(a[, UPLO]) 傳回複數Hermitian(共轭對稱)或實對稱矩陣的特征值和特征向量。
linalg.eigvals(a) 計算通用矩陣的特征值。
linalg.eigvalsh(a[, UPLO]) 計算複數Hermitian(共轭對稱)或實對稱矩陣的特征值。

基準值:

linalg.norm(x[, ord, axis, keepdims]) 矩陣或向量範數
linalg.cond(x[, p]) Compute the condition number of a matrix.
linalg.det(a) 矩陣行列式
linalg.matrix_rank(M[, tol, hermitian]) 使用SVD方法傳回數組的矩陣秩
linalg.slogdet(a) 計算數組行列式的符号和(自然)對數。
trace(a[, offset, axis1, axis2, dtype, out]) 傳回沿數組對角線的和。

求解和反轉:

linalg.solve(a, b) 求解線性矩陣方程或線性标量方程組。
linalg.tensorsolve(a, b[, axes]) 對x求解張量方程’a x = b’。
linalg.lstsq(a, b[, rcond]) 将最小二乘解傳回線性矩陣方程
linalg.inv(a) 計算矩陣的(乘法)逆。
linalg.pinv(a[, rcond, hermitian]) 計算矩陣的(Moore-Penrose)僞逆。
linalg.tensorinv(a[, ind]) 計算N維數組的“逆”。

随機數

很多時候我們都需要生成随機數,在NumPy中随機數的生成非常簡單:

samples = np.random.normal(size=(4, 4))
samples      
array([[-2.0016, -0.3718,  1.669 , -0.4386],
       [-0.5397,  0.477 ,  3.2489, -1.0212],
       [-0.5771,  0.1241,  0.3026,  0.5238],
       [ 0.0009,  1.3438, -0.7135, -0.8312]])      

上面用normal來得到一個标準正态分布的4×4樣本數組。

使用np.random要比使用Python自帶的随機數生成器要快得多。

np.random可以指定生成随機數的種子:

np.random.seed(1234)      

numpy.random的資料生成函數使用了全局的随機種子。要避免 全局狀态,你可以使用numpy.random.RandomState,建立一個 與其它隔離的随機數生成器:

rng = np.random.RandomState(1234)
rng.randn(10)      
本文已收錄于 http://www.flydean.com/10-python-numpy-func/

最通俗的解讀,最深刻的幹貨,最簡潔的教程,衆多你不知道的小技巧等你來發現!

歡迎關注我的公衆号:「程式那些事」,懂技術,更懂你!