目錄
Numpy基礎
引文
Python本身含有列表(list)和數組(array),但對於大數據來說,這些結構是有很多不足的。
list的元素可以是任何對象,因此列表中所保存的是對象的指針。
array對象可以直接保存數值,但是由於它不支持多維,在上面的函數也不多,因此也不適合做數值運算。
Numpy提供了兩種基本的對象:
- ndarray(N-dimensional Array Object)
- ufunc(Universal Function Object)
ndarray是存儲單一數據類型的多維數組,而ufunc則是能夠對數組進行處理的函數。
Numpy的主要特點
- ndarray,快速節省空間的多維數組,提供數組化的算術運算和高級的廣播功能。
- 使用標準數學函數對整個數組的數據進行快速運算,且不需要編寫循環。
- 讀取/寫入磁盤上的陣列數據和操作存儲器映像文件的工具。
- 線性代數、隨機數生成和傅里葉變換的能力。
Numpy主要內容
- 如何生成Numpy數組。
- 如何存取元素。
- Numpy的算術運算。
- 數組變形。
- 批量處理。
- Numpy的通用函數。
- Numpy的廣播機制。
生成Numpy數組
從已有數據中創建數組
直接對Python的基礎數據類型(如列表、元組等)進行轉換來生成ndarray:
1)將列表轉換成ndarray:
import numpy as np
list1 = [2, 3, 4, 5]
nd1 = np.array(list1)
2)嵌套列表可以轉換成多維ndarray:
import numpy as np
list2 = [[2, 3, 4, 5], [6, 7, 8, 9]]
nd2 = np.array(list2)
把上面示例中的列表換成元組也同樣適用。
利用random模塊生成數組
np.random 模塊常用函數:
函數 | 描述 |
---|---|
np.random.random | 0到1之間隨機數 |
np.random.uniform | 均勻分佈的隨機數 |
np.random.randn | 標準正態分佈的隨機數 |
np.random.normal | 正態分佈 |
np.random.randint | 隨機整數 |
np.random.shuffle | 隨機打亂順序 |
np.random.seed | 設置隨機數種子 |
random_sample | 生成隨機的浮點數 |
創建特定形狀的多維數組
參數初始化時,有時需要生成一些特殊矩陣,如全是0或1的數組或矩陣,這時我們可以利用np.zeros、np.ones、np.diag來實現。
函數 | 描述 |
---|---|
np.zeros((3,4)) | 創建3 x 4的元素全爲0的數組 |
np.ones((3,4)) | 創建3 x 4的元素全爲1的數組 |
np.empty((2,3)) | 創建2 x 3的空數組,但是空數據中的值不是0,是未初始化的垃圾值 |
np.zeros_like(ndarr) | 以ndarr 相同維度創建元素全爲0數組 |
np.ones_like(ndarr) | 以ndarr 相同維度創建元素全爲1數組 |
np.empty_like(ndarr) | 以ndarr 相同維度創建空數組 |
np.eye(5) | 創建一個5 x 5矩陣,對角線爲1,其餘爲0 |
np.full((3,5), 666) | 創建3 x 5的元素全爲666的數組 |
將數據保存起來,再讀取:
nd = np.random.random([5, 5])
np.savetxt(X = nd, fname = './test.txt')
nd1 = np.loadtxt('./test.txt')
利用arange、linspace函數生成數組
# arange([start,] stop[, step,], dtype=None)
print(np.arange(1, 4, 0.5))
# [1. 1.5 2. 2.5 3. 3.5]
start, stop指定範圍; stop設定步長。start默認爲0, step可以使小數。
np.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)
linspace根據輸入的指定數據範圍和等份數量,自動生成一個線性等分向量。
如果retstep=True,會返回帶步長的ndarray。
linspace必定會包含數據起點和重點。
獲取元素
通過指定索引標籤
np.random.seed(2020)
nd = np.random.random([10])
nd[3]
nd[3:6]
nd[1:6:2] # 截取固定間隔數據
nd[::-2] # 倒序取數
# 截取一個多維數組的一個區域內數據
nd2 = np.arange(25).reshape([5,5])
nd2[1:3,1:3]
# 截取一個多維數組中,數值在一個值域之內的數據
nd2[(nd2>3)&(nd2<10)]
# 截取多維數組中指定的行,如2,3行
nd2[[1,2]] # nd2[1:3,:]
# 截取多爲數組中指定的列
nd2[:,1:3]
通過函數
如random.choice從指定樣本中隨機抽取數據。
from numpy import random as nr
a = np.arange(1,25,dtype=float)
# 隨機可重複抽取
c1 = nr.choice(a, size=(3,4))
# 隨機不重複抽取
c2 = nr.choice(a, size=(3,4),replace=False) #replace默認爲True,可重複抽取
#隨機按制度概率抽取
c3 = nr.choice(a, size=(3,4), p=a/np.sum(a))
算數運算
- 矩陣的對應元素相乘
np.multiply(A, B)
# 或者A*B
A, B之間的對應元素相乘遵守廣播規則。
由此,數組通過一些激活函數後,輸出與輸入的形式一致。
x = np.random.rand(2,3)
def softmoid(x):
return 1/(1 + np.exp(-x))
def relu(x):
return np.maximum(0, x)
def softmax(x):
return np.exp(x)/np.sum(np.exp(x))
- 點積運算(內積)
np.dot(x1, x2)
x1, x2對應維度的元素個數必須保持一致。
數組變形
在矩陣或者數組的運算中,經常會遇到需要把多個向量或矩陣按某軸方向合併,或展平(如在卷積或循環神經網絡中,在全連接層之前,需要把矩陣展平)的情況。
- 改變數組的形狀
numpy中改變向量形狀的一些函數:
函數 | 描述 |
---|---|
arr.reshape | 改變向量維度,不改變向量本身 |
arr.resize | 改變向量維度,改變向量本身 |
arr.T | 對向量進行轉置 |
arr.ravel | 對向量展平,即將多維數組變成1維,不會產生原數組的副本 |
arr.flatten | 對向量展平,即將多維數組變成1維,返回原數組的副本 |
arr.squeeze | **只能對維數爲1的維度降維。**對多維數組使用不會產生影響 |
arr.transpose | 對高維矩陣隊形軸兌換 |
注意:
reshape: 指定維度時可以只指定一個,其他用-1代替
ravel:arr.ravel(‘F’) 按照列優先展平,否則默認按行優先
flatten:把矩陣轉換爲向量,這種需求經常出現在卷積網絡和全連接層之間。
squeeze:比如(3,1)——> (3, ) ,(3, 1, 2, 1)——> (3,2)
transpose:對高維矩陣進行軸對換,在深度學習中常使用,比如講圖片RGB順序改成GBR。
arr = np.arange(24).reshape(2,3,4)
print(arr.shape) # (2,3,4)
print(arr.transpose(1,2,0).shape) # (3,4,2)
- 合併數組
函數 | 描述 |
---|---|
np.append | 內存佔用大 |
np.concatenate | 沒有內存問題 |
np.stack | 沿着新的軸加入一系列數組 |
np.hstack | 堆棧數組垂直順序(行) |
np.vstack | 堆棧數組垂直順序(列) |
np.dstack | 堆棧數組按順序深入(沿第3維) |
np.vsplit | 將數組分解成垂直的多個子數組的列表 |
注意:
- append,concatenate以及stack都有一個axis參數,用於控制數組的合併方式是按行還是按列。
- 對於append和concatenate,待合併的數組必須有相同的行數或列數。
- stack,hstack,dstack要求待合併的數組要有相同形狀。
示例:
- append
- 合併一維數組:
a = np.array([1,2,3])
b = np.array([4,5,6])
c = np.append(a, b)
print(c)
# [1 2 3 4 5 6]
- 合併多維數組
a = np.arange(4).reshape(2,2)
b = np.arange(4).reshape(2,2)
# 按行合併
c = np.append(a, b, axis=0)
print(c)
'''[[0 1]
[2 3]
[0 1]
[2 3]]
'''
d = np.append(a, b, axis=1)
print(d)
'''[[0 1 0 1]
[2 3 2 3]]
'''
- concatenate
- 沿指定軸連接數組或矩陣
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6]])
c = np.concatenate((a, b), axis=0)
print(c)
d = np.concatenate((a, b.T), axis=1)
print(d)
'''
[[1 2]
[3 4]
[5 6]]
[[1 2 5]
[3 4 6]]
'''
- stack
沿指定軸堆疊數組或矩陣:
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])
c = np.stack((a, b), axis=0)
print(c)
print(c.shape)
'''
[[[1 2]
[3 4]]
[[5 6]
[7 8]]]
(2, 2, 2)
'''
批量處理
在深度學習中,由於源數據都比較大,所以通常需要用到批處理。如利用批量來計算梯度的隨機梯度法(SGD)就是一個典型應用。
一次處理一條記錄無法充分發揮GPU、Numpy的平行處理優勢。因此,在實際使用中往往採用 批量處理(Mini-Batch) 的方法。
如何把大數據拆分成多個批次呢?
1. 得到數據集
2. 隨機打亂數據
3. 定義批大小
4. 批處理數據集
示例:
# 生成10000個形狀爲2*3的矩陣
data = np.random.randn(10000, 2 , 3)
# 3維矩陣,第1個維度是樣本數,後兩個是數據形狀
print(data.shape)
# (10000, 2, 3)
# 打亂數據
np.random.shuffle(data)
# 定義批量大小
batch_size = 100
# 進行批處理
for i in range(0, len(data), batch_size):
x_batch_sum = np.sum(data[i:i+batch_size])
print(f"第{i}批次,該批次的數據之和爲{x_batch_sum}.")
批次從0開始,最後5行結果如下:
# 第9500批次,該批次的數據之和爲14.58947150077857.
# 第9600批次,該批次的數據之和爲42.03495509156134.
# 第9700批次,該批次的數據之和爲28.81790516315437.
# 第9800批次,該批次的數據之和爲20.004793932616554.
# 第9900批次,該批次的數據之和爲9.329281850375956.
通用函數
Numpy的另一個對象通用函數(ufunc,universal function),它是一種能對數組的每個元素進行操作的函數。
許多ufunc函數都是用C語言級別實現的,因此它們的計算速度非常快。
此外,它們比math模塊中的函數更靈活。math模塊的輸入一般是標量,但Numpy中的函數可以是向量或矩陣,而利用向量或矩陣可以避免使用循環語句,這點在機器學習、深度學習中非常重要。下表爲Numpy中常用的幾個通用函數。
函數 | 使用方法 |
---|---|
sqrt | 計算序列化數據的平方根 |
sin, cos | 三角函數 |
abs | 絕對值 |
dot | 矩陣運算 |
log, log10, log2 | 對數 |
exp | 指數 |
cumsum, cumproduct | 累計求和、求積 |
sum | 求和 |
mean | 求均值 |
median | 求中位數 |
std | 求標準差 |
var | 求方差 |
corrcoef | 求相關係數 |
充分使用Python的Numpy庫中的內建函數(Built-in Function)來實現計算的向量化,可大大地提高運行速度。Numpy庫中的內建函數使用了SIMD指令。
如果使用GPU,其性能將更強大,不過Numpy不支持GPU。PyTorch支持GPU。在深度學習算法中,一般都使用向量化矩陣進行運算。
廣播機制
Numpy的Universal functions中要求輸入的數組shape是一致的,當數組的shape不相等時,則會使用廣播機制。
可歸納爲以下4條規則:
- 讓所有輸入數組都向其中shape最長的數組看齊,不足的部分則通過在前面加1補齊。
如:a:2×3×2,b:3×2,則b向a看齊,在b的前面加1,變爲:1×3×2 - 輸出數組的shape是輸入數組shape的各個軸上的最大值;
- 如果輸入數組的某個軸和輸出數組的對應軸的長度相同或者某個軸的長度爲1時,這個數組能被用來計算,否則出錯;
- 當輸入數組的某個軸的長度爲1時,沿着此軸運算時都用(或複製)此軸上的第1組值。
示例:
目的:A+B,其中A爲4×1矩陣,B爲一維向量(3,)。
- 由規則1,B要變成(1,3)
- 由規則2,輸出結果爲各個軸上的最大值,則輸出結果應該是(4,3)矩陣
- 由規則4,用此軸上的第一組值進行復制(不是真的複製,費內存)
如下圖所示:
A = np.arange(0, 40, 10).reshape(4,1) # A.shape: (4,1)
B = np.arange(0, 3) # B.shape: (3,)
C = A + B
print(C)
print(C.shape)
'''
[[0 1 2]
[10 11 12]
[20 21 22]
[30 31 32]]
'''
想了解更多內容,可登錄Numpy官網(http://www.Numpy.org/)查看更多內容。
本文根據《Python深度學習:基於PyTorch》第一章內容總結。
一起加油鴨ヾ(◍°∇°◍)ノ゙