文章目錄
[ NumPy version: 1.18.1 ]
import numpy as np
一、創建數組
# 1.從python列表創建數組
# 整型數組
np.array([1, 4, 2, 5, 3])
# 明確數據類型
np.array([1, 2, 3, 4], dtype='float32')
# 嵌套列表構成的多維數組
np.array([range(i, i + 3) for i in [2, 4, 6]])
# 2.從頭創建數組
np.zeros(10, dtype=int)
np.ones((2, 5), dtype=float)
np.full((3, 5), 3.14)
np.arange(0, 20, 2) #線性序列
np.linspace(0, 1, 5) #5個元素均勻分佈0~1(含1)
np.random.random((3, 3)) #3x3,0~1均勻分佈隨機數
np.random.normal(0, 1, (3, 3)) #3x3,均值0,標準差1的正態分佈隨機數
np.random.randint(0, 10, (3, 3)) #3x3,[0, 10)區間隨機整型數組
np.eye(3) #3x3單位矩陣
np.empty(3) #3個整型數的未初始化數組,值爲內存空間中任意值
np.random.seed(0) #設置隨機數種子
二、數組操作類型
1. 數組屬性
np數組屬性:ndim維度,shape維度大小,size數組總大小,dtype數據類型,itemsize元素字節大小,nbytes數組總字節大小 nbytes = itemsize x size
2. 數組索引:獲取單個元素
x[1]
x[2, -1]
3. 切片
數組切片 x[start:stop:step] 默認start=0, stop=維度大小, step=1
# 1.一維子數組
x = np.arange(10)
x[::-1]
x[5::-2] #從索引5開始到索引0結束,間隔1倒序
# 2.多維子數組
x2 = np.array([[12, 5, 2, 4], [7, 6, 8, 8], [1, 6, 7, 7]])
x2[:2, :3] #2行3列
x2[:3, ::2] #所有行隔一列
x2[::-1, ::-1] #行列均逆序
# 3.獲取數組行和列
x2[:, 0] #x2第1列
x2[0, :] #第1行
x2[0] #第1行,空切片:可省略
# 4.非副本視圖的子數組
#數組切片返回的是數組數據的視圖,不是數值數據的副本(python列表中切片是值的副本)。
#處理大數據集時可以獲取或處理這些數據集的片段而不用複製底層的數據緩存。
# 5.創建數組的副本
x2[:2, :2].copy()
4. 數組的變形
x = np.arange(1, 10).reshape((3, 3))
x.reshape((1, 3)) = x[np.newaxis, :] #通過newaxis獲取行向量
x.reshape((3, 1)) = x[:, np.newaxis] #獲取列向量
5. 數組拼接和分裂
# 1.拼接
x = np.array([1, 2, 3])
y = np.array([3, 2, 1])
np.concatenate([x, y])
np.concatenate([x, y, z])
np.concatenate([grid, grid]) #默認axis=0,沿第一個軸拼接
np.concatenate([grid, grid], axis=1) #沿第二個軸拼接
# 沿着固定維度處理數組
np.vstack([x, grid]) #垂直棧
np.hstack([grid, y]) #水平棧
np.dstack #沿第三個維度拼接數組
# 2.分裂
x1, x2, x3 = np.split(x, [3, 5]) #索引列表記錄的是分裂點位置索引,N分裂點會得到N+1個子數組
upper, lower = np.vsplit(grid, [2]) #上下分裂
left, right = np.hsplit(grid, [2]) #左右分裂
np.dsplit #第三維度分裂
三、數組計算:通用函數
# 算數運算符
np.add
np.substract
np.negtive #負數運算
np.multiply
np.divide
np.floor_divide #向下整除運算 3//2=1
np.power #指數運算 3^2
np.mod #模,餘數 %
# 絕對值
np.absolute(x) = np.abs(x)
# 三角函數
theta = np.linspace(0, np.pi, 3)
np.sin(theta)
np.cos(theta)
np.tan(theta)
# 逆三角函數
x = [-1, 0, 1]
np.arcsin(x)
np.arccos(x)
np.arctan(x)
# 指數和對數
np.exp(x) #e^x
np.exp2(x) #2^x
np.power(3, x) #3^x
np.log(x) #ln(x)
np.log2(x)
np.log10(x)
# x值很小時,下面函數的值更精確
np.expm1(x) #exp(x)-1
np.log1p(x) #log(1+x)
高級通用函數特性
- 指定輸出:制定一個用於存放運算結果的數組。對於較大數組,慎重使用out參數有效節約內存
x = np.arange(5)
y = np.empty(5)
np.multiple(x, 10, out=y)
z = np.zeros(10)
np.power(2, x, out=z[::2])
- 聚合
reduce方法對給定元素和操作重複執行至得到單個結果(np.sum, np.prod, np.cumsum, np.cumprod也可以實現reduce功能)
x = np.arange(1, 6)
np.add.reduce(x)
np.multiply.reduce(x)
# accumulate可以存儲每次計算的中間結果
np.add.accumulate(x)
- 外積:任何通用函數都可以用outer方法獲得兩個不同輸入數組所有元素對的函數運算結果(實現乘法表)
x = np.arange(1, 6)
np.multiply.outer(x, x)
四、聚合
# 聚合函數
np.sum #和
np.prod #積
np.mean #平均值
np.std #標準差
np.var #方差
np.min #最小值
np.max #最大值
np.argmin #找出最小值的索引
np.argmax #找出最大值的索引
np.median #中位數
np.percentile #計算基於元素排序的統計值
np.any #驗證是否存在元素爲真
np.all #驗證所有元素是否爲真
- 聚合函數參數axis用於指定沿着哪個軸的方向進行聚合。axis=0每列,axis=1每行
- 大多數聚合有對NaN值的安全處理策略(NaN-safe)(以上除any all均有,在方法前加nan,如np.nansum),計算時忽略所有的缺失值。(NumPy1.8版本後可用)
五、數組計算:廣播
廣播(broadcast):可將二元運算符用於不同大小的數組。(如標量與數組相加)
廣播規則(適用任意二進制通用函數):
- 如果兩個數組的維度數不相同,那麼小維度數組的形狀將會在最左邊補1。
- 如果兩個數組的形狀在任何一個維度上都不匹配,那麼數組的形狀會沿着維度爲1的維度擴展以匹配另外一個數組的形狀。
- 如果兩個數組的形狀在任何一個維度上都不匹配並且沒有任何一個維度等於1,那麼會引發異常。
# 標量與一維數組
a = np.array([0, 1, 2])
a + 5
# 一維數組與二維數組
M = np.ones((3, 3))
M + a #一維數組被廣播,沿第二維度擴展到匹配M數組的形狀
# 兩個數組同時廣播
b = np.arange(3)[:, np.newaxis]
a + b #a,b同時擴展匹配至公共形狀
解讀:
# 一維數組 + 二維數組
一維數組 a.shape -> (n,)
二維數組 b.shape -> (m, n)
第一步 a.shape -> (n,)補足爲(1, n)
第二步 a.shape -> (1, n)擴展(m, n) -> a,b形狀匹配開始運算
如果b.shape爲(m, k)任何維度均不匹配,會引發異常ValueError
例:
a.shape (3, 1)
b.shape (3,) ->(1, 3)
a.shape ->(3, 3)
b.shape ->(3, 3)
如果a.shape爲(3, 2),b擴展後依然不匹配,就會引發異常
廣播的應用:
- 數組歸一化
- 二維函數可視化
六、比較、掩碼和布爾邏輯
1. 比較
比較運算通用函數適用任意形狀、大小的數組。結果輸出爲布爾數組。
# 通用函數 # 運算符
np.equal # ==
np.not_equal # !=
np.less # <
np.less_equal # <=
np.greater # >
np.greater_equal # >=
rng = np.random.RandomState(0)
x = rng.randint(10, size=(3, 4))
x < 6
2. 操作布爾數組
- 統計記錄的個數
np.count_nonzero(x < 6) #統計True的個數
np.sum(x < 6) #False=0,True=1
np.sum(x < 6, axis=1) #sum()函數可以沿特定軸進行
# 快速檢查任意或所有值是否爲True(結果返回True或False)
np.any(x > 8)
np.all(x == 8)
np.any(x < 0, axis=1) #any(), all()也可沿軸進行
- 布爾運算符(數組的逐位運算)
# 通用函數 # 運算符
np.bitwise_and # & # 交集
np.bitwise_or # | # 並集
np.bitwise_xor # ^ # 異或
np.bitwise_not # ~ # 非
# 複合表達式
np.sum((x > 1) & (x < 5))
# A AND B 等價於 NOT(NOT A OR NOT B)
np.sum(~((x <= 5) | (x >= 1)))
3. 將布爾數組作爲掩碼
# 利用比較運算符得到布爾數組,通過索引將特定值選出,即掩碼操作
x < 5 #輸出布爾數組
x[x < 5] #輸出滿足條件的值
# 構建掩碼
rainy = (inches > 0)
# 布爾操作、掩碼操作和聚合結合
np.median(inches[rainy])
七、花哨索引
- 花哨索引(fancy indexing):傳遞一個索引數組來一次性獲得多個數組元素。
rand = np.random.RandomState(42) #使用RandomState獲得隨機數生成器,42爲隨機種子數
x = rand.randint(100, size=10)
# 方法一
[x[3], x[7], x[2]]
# 方法二:通過傳遞索引的單個列表或數組來獲得同樣的結果
ind = [3, 7, 4]
x[ind]
# 利用花哨索引使結果的形狀與索引數組形狀一致,而不是與被索引數組形狀一致
ind = np.array([[3, 7], [4, 5]])
x[ind]
# 適用多維度數組
X = np.arange(12).reshape((3, 4))
row = np.array([0, 1, 2])
col = np.array([2, 1, 3])
X[row, col] #第一個索引指行,第二個索引指列,即[0,2],[1,1],[2,3]
X[row[:, np.newaxis], col] #矩陣運算邏輯取行列索引
row[:, np.newaxis] * col #矩陣運算
- 組合索引:花哨索引與其他索引結合
# 與簡單索引組合
X[2, [2, 0, 1]]
# 與切片組合
X[1:, [2, 0, 1]] #行索引可分別取1,2
# 與掩碼組合
mask = np.array([1, 0, 1, 0], dtype=bool)
X[row[:, np.newaxis], mask]
- 花哨索引應用
- 用於獲取部分數組:從一個矩陣中選擇行的子集。快速分割數據(需要分割訓練/測試數據集以驗證統計模型)
- 用於修改部分數組
# 索引值重複次數累加 at()函數
x = np.zeros(10)
i = [2, 3, 3, 4, 4, 4]
np.add.at(x, i, 1) #輸出x:[0. 0. 1. 2. 3. 0. 0. 0. 0. 0.],內含3個重複值
# at()函數在這裏對給定的操作,給定的索引,給定的值執行就地操作
# 類似方法:reduceat()函數
八、數組的排序
- 快速排序
# 算法複雜度O[NlogN]
# 不修改原始數組的基礎上返回一個排好序的數組
np.sort(x)
# 用排好序的數組替代原始數組
x.sort()
# 函數argsort返回的是原始數組排好序的索引值
i = np.argsort(x)
# 索引值可用於通過花哨索引創建有序數組
x[i] #結果等同np.sort(x)
# 沿着多維數組的行或列排序(將行或列作爲獨立數組,行列值之間的關係將丟失)
np.sort(X, axis=0) #對X的每一列排序
np.sort(X, axis=1) #每一行排序
- 部分排序:分隔
不對整個數組進行排序,只需找到數組中第K小的值。
np.partition函數的輸入是數組和數字K,輸出一個新數組,最左邊K個數是最小的K個值,往右是原始數組剩下的值,在這兩個分隔區間中元素都是任意排列的。
x = np.array([7, 2, 3, 1, 6, 5, 4])
np.partition(x, 3)
# 可以沿着多維數組任意軸進行分隔
np.partition(X, 2, axis=1)
總結自《Python數據科學手冊》