百度PaddlePaddle入門-5(Numpy,Random)


Numpy是Numerical Python的簡稱,是Python中高性能科學計算和數據分析的基礎包。Numpy提供了一個多維數組類型ndarray,它具有矢量算術運算和復雜廣播的能力,可以實現快速的計算並且能節省存儲空間。在使用Python調用飛槳API完成深度學習任務的過程中,通常會使用Numpy實現數據預處理和一些模型指標的計算,飛槳中的Tensor數據可以很方便的和ndarray數組進行相互轉換。

在這一節將介紹以下內容:

  • 基礎數據結構ndarray數組

  • 隨機數numpy.random

  • 線性代數numpy.linalg

  • Numpy保存和導入文件

  • 應用舉例


基礎數據結構ndarray數組

ndarray數組是Numpy中的基礎數據結構式,這一小節將從以下幾個方面展開進行介紹:

  • 為什么引入ndarray數組

  • 如何創建ndarray數組

  • ndarray數組的基本運算

  • ndarray數組的切片和索引

  • ndarray數組的統計運算

為什么引入ndarray數組

在Python中使用list列表可以非常靈活的處理多個元素的操作,但是其效率卻比較低。ndarray數組相比於Python中的list列表具有以下特點:

  • ndarray數組中所有元素的數據類型是相同的,數據地址是連續的,批量操作數組元素時速度更快;list列表中元素的數據類型可以不同,需要通過尋址方式找到下一個元素

  • ndarray數組中實現了比較成熟的廣播機制,矩陣運算時不需要寫for循環

  • Numpy底層是用c語言編寫的,內置了並行計算功能,運行速度高於純Python代碼

下面的代碼展示了使用ndarray數組和list列表完成相同的任務,ndarray數組的代碼看上去要更加簡潔而且易於理解。

ndarray數組和list列表分別完成對每個元素增加1的計算

 1 # Python原生的list
 2 # 假設有兩個list
 3 a = [1, 2, 3, 4, 5]
 4 b = [2, 3, 4, 5, 6]
 5 
 6 # 完成如下計算
 7 # 1 對a的每個元素 + 1
 8 # a = a + 1 不能這么寫,會報錯
 9 # a[:] = a[:] + 1 也不能這么寫,也會報錯
10 for i in range(5):
11     a[i] = a[i] + 1
12 a
[2, 3, 4, 5, 6]
1 # 使用ndarray
2 import numpy as np
3 a = np.array([1, 2, 3, 4, 5])
4 a = a + 1
5 a
array([2, 3, 4, 5, 6])

ndarray數組和list列表分別完成相加計算

1  2 計算 a和b中對應位置元素的和,是否可以這么寫?
2 a = [1, 2, 3, 4, 5]
3 b = [2, 3, 4, 5, 6]
4 c = a + b
5 # 檢查輸出發現,不是想要的結果
6 c
[1, 2, 3, 4, 5, 2, 3, 4, 5, 6]
1 # 使用for循環,完成兩個list對應位置元素相加
2 c = []
3 for i in range(5):
4     c.append(a[i] + b[i])
5 c
[3, 5, 7, 9, 11]
1 # 使用numpy中的ndarray完成兩個ndarray相加
2 import numpy as np
3 a = np.array([1, 2, 3, 4, 5])
4 b = np.array([2, 3, 4, 5, 6])
5 c = a + b 
6 c
array([ 3,  5,  7,  9, 11])
從上面的示例中可以看出,ndarray數組的矢量計算能力使得不需要寫for循環,就可以非常方便的完成數學計算,在操作矢量或者矩陣時,可以像操作普通的數值變量一樣編寫程序,使得代碼極其簡潔。另外,ndarray數組還提供了廣播機制,它會按一定規則自動對數組的維度進行擴展以完成計算,如下面例子所示,1維數組和2維數組進行相加操作,ndarray數組會自動擴展1維數組的維度,然后再對每個位置的元素分別相加。
 1 # 自動廣播機制,1維數組和2維數組相加
 2 
 3 # 二維數組維度 2x5
 4 # array([[ 1,  2,  3,  4,  5],
 5 #         [ 6,  7,  8,  9, 10]])
 6 d = np.array([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]])
 7 # c是一維數組,維度5
 8 # array([ 4,  6,  8, 10, 12])
 9 c = np.array([ 4,  6,  8, 10, 12])
10 e = d + c
11 e
array([[ 5,  8, 11, 14, 17],
       [10, 13, 16, 19, 22]])

如何創建ndarray數組

有如下幾種方式創建ndarray數組

  • 從list列表創建

  • 指定起止范圍及間隔創建

  • 創建值全為0的ndarray數組

  • 創建值全為1的ndarray數組

1 # 導入numpy
2 import numpy as np
3 
4 # 從list創建array
5 a = [1,2,3,4,5,6]
6 b = np.array(a)
7 b
array([1, 2, 3, 4, 5, 6])
1 # 通過np.arange創建
2 # 通過指定start, stop (不包括stop),interval來產生一個1維的ndarray
3 a = np.arange(0, 20, 2)
4 a
array([ 0,  2,  4,  6,  8, 10, 12, 14, 16, 18])
1 # 創建全0的ndarray
2 a = np.zeros([3,3])
3 a
array([[0., 0., 0.],
       [0., 0., 0.],
       [0., 0., 0.]])
1 # 創建全1的ndarray
2 a = np.ones([3,3])
3 a
array([[1., 1., 1.],
       [1., 1., 1.],
       [1., 1., 1.]])

查看ndarray數組的屬性

ndarray的屬性包括形狀shape、數據類型dtype、元素個數size和維度ndim等,下面的程序展示如何查看這些屬性

1  數組的數據類型 ndarray.dtype
2 # 數組的形狀 ndarray.shape,1維數組(N, ),二維數組(M, N),三維數組(M, N, K)
3 # 數組的維度大小,ndarray.ndim, 其大小等於ndarray.shape所包含元素的個數
4 # 數組中包含的元素個數 ndarray.size,其大小等於各個維度的長度的乘積
5 
6 a = np.ones([3, 3])
7 print('a, dtype: {}, shape: {}, size: {}, ndim: {}'.format(a.dtype, a.shape, a.size, a.ndim))
a, dtype: float64, shape: (3, 3), size: 9, ndim: 2
上面輸出結果中,shape就是一個元組;size=各維長度大小的乘積;ndim不是很好理解=shape中包含元素的個數。同時ones()函數輸出的默認類型就是float64.

改變ndarray數組的數據類型和形狀

創建ndarray之后,可以對其數據類型進行更改,或者對形狀進行調整,如下面的代碼所示

1 # 轉化數據類型
2 b = a.astype(np.int64)
3 print('b, dtype: {}, shape: {}'.format(b.dtype, b.shape))
4 
5 # 改變形狀
6 c = a.reshape([1, 9])
7 print('c, dtype: {}, shape: {}'.format(c.dtype, c.shape))
b, dtype: int64, shape: (3, 3)
c, dtype: float64, shape: (1, 9)

ndarray數組的基本運算

ndarray數組可以像普通的數值型變量一樣進行加減乘除操作,這一小節將介紹兩種形式的基本運算:

  • 標量和ndarray數組之間的運算

  • 兩個ndarray數組之間的運算

標量和ndarray數組之間的運算

1 # 標量除以數組,用標量除以數組的每一個元素
2 arr = np.array([[1., 2., 3.], [4., 5., 6.]])
3 1. / arr
array([[1.        , 0.5       , 0.33333333],
       [0.25      , 0.2       , 0.16666667]])
1 # 標量乘以數組,用標量乘以數組的每一個元素
2 arr = np.array([[1., 2., 3.], [4., 5., 6.]])
3 2.0 * arr
array([[ 2.,  4.,  6.],
       [ 8., 10., 12.]])
1 # 標量加上數組,用標量加上數組的每一個元素
2 arr = np.array([[1., 2., 3.], [4., 5., 6.]])
3 2.0 + arr
array([[3., 4., 5.],
       [6., 7., 8.]])
1 # 標量減去數組,用標量減去數組的每一個元素
2 arr = np.array([[1., 2., 3.], [4., 5., 6.]])
3 2.0 - arr
array([[ 1.,  0., -1.],
       [-2., -3., -4.]])

兩個ndarray數組之間的運算

1 # 數組 減去 數組, 用對應位置的元素相減
2 arr1 = np.array([[1., 2., 3.], [4., 5., 6.]])
3 arr2 = np.array([[11., 12., 13.], [21., 22., 23.]])
4 arr1 - arr2
array([[-10., -10., -10.],
       [-17., -17., -17.]])
1 # 數組 加上 數組, 用對應位置的元素相加
2 arr1 = np.array([[1., 2., 3.], [4., 5., 6.]])
3 arr2 = np.array([[11., 12., 13.], [21., 22., 23.]])
4 arr1 + arr2
array([[12., 14., 16.],
       [25., 27., 29.]])
1 # 數組 乘以 數組,用對應位置的元素相乘
2 arr1 * arr2
array([[ 11.,  24.,  39.],
       [ 84., 110., 138.]])
上面這個感覺有點難理解啊。
1 # 數組 除以 數組,用對應位置的元素相除
2 arr1 / arr2
array([[0.09090909, 0.16666667, 0.23076923],
       [0.19047619, 0.22727273, 0.26086957]])
1 # 數組開根號,將每個位置的元素都開根號
2 arr ** 0.5
array([[1.        , 1.41421356, 1.73205081],
       [2.        , 2.23606798, 2.44948974]])

ndarray數組的索引和切片

在程序中,通常需要訪問或者修改ndarray數組某個位置的元素,也就是要用到ndarray數組的索引;有些情況下可能需要訪問或者修改一些區域的元素,則需要使用數組的切片。索引和切片的使用方式與Python中的list類似,ndarray數組可以基於 -n ~ n-1 的下標進行索引,切片對象可以通過內置的 slice 函數,並設置 start, stop 及 step 參數進行,從原數組中切割出一個新數組。

1 # 1維數組索引和切片
2 a = np.arange(30)
3 a[10]
10
1 a = np.arange(30)
2 b = a[4:7]
3 b
array([4, 5, 6])
1 #將一個標量值賦值給一個切片時,該值會自動傳播到整個選區(如下圖所示)
2 a = np.arange(30)
3 a[4:7] = 10
4 a
array([ 0,  1,  2,  3, 10, 10, 10,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
       17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29])
1 # 數組切片是原始數組的視圖。這意味着數據不會被復制,
2 # 視圖上的任何修改都會直接反映到源數組上
3 a = np.arange(30)
4 arr_slice = a[4:7]
5 arr_slice[0] = 100
6 a, arr_slice
(array([  0,   1,   2,   3, 100,   5,   6,   7,   8,   9,  10,  11,  12,
         13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,
         26,  27,  28,  29]), array([100,   5,   6]))
1 # 通過copy給新數組創建不同的內存空間
2 a = np.arange(30)
3 arr_slice = a[4:7]
4 arr_slice = np.copy(arr_slice)  #自己給自己拷貝
5 arr_slice[0] = 100
6 a, arr_slice
(array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
        17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]),
 array([100,   5,   6]))
1 # 多維數組索引和切片
2 a = np.arange(30)
3 arr3d = a.reshape(5, 3, 2)
4 arr3d
array([[[ 0,  1],
        [ 2,  3],
        [ 4,  5]],

       [[ 6,  7],
        [ 8,  9],
        [10, 11]],

       [[12, 13],
        [14, 15],
        [16, 17]],

       [[18, 19],
        [20, 21],
        [22, 23]],

       [[24, 25],
        [26, 27],
        [28, 29]]])
1 # 只有一個索引指標時,會在第0維上索引,后面的維度保持不變
2 arr3d[0]
array([[0, 1],
       [2, 3],
       [4, 5]])
1 # 兩個索引指標
2 arr3d[0][1]
array([2, 3])
1 # 兩個索引指標,與上面等價
2 arr3d[0, 1]
array([2, 3])
1 # 使用python中的for語法對數組切片
2 
3 a = np.arange(24)
4 a
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
       17, 18, 19, 20, 21, 22, 23])
1 a = a.reshape([6, 4])
2 a
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15],
       [16, 17, 18, 19],
       [20, 21, 22, 23]])
1 # 使用for語句生成list
2 [k for k in range(0, 10, 2)]
[0, 2, 4, 6, 8]
 1 # 結合上面列出的for語句的用法
 2 # 使用for語句對數組進行切片
 3 # 下面的代碼會生成多個切片構成的list
 4 # k in range(0, 6, 2) 決定了k的取值可以是0, 2, 4
 5 # 產生的list的包含三個切片
 6 # 第一個元素是a[0 : 0+2],也就是a[0:2]
 7 # 第二個元素是a[2 : 2+2],也就是a[2:4]
 8 # 第三個元素是a[4 : 4+2],也就是a[4:6]
 9 slices = [a[k:k+2] for k in range(0, 6, 2)]
10 slices,a[0:2]
([array([[0, 1, 2, 3],
         [4, 5, 6, 7]]), array([[ 8,  9, 10, 11],
         [12, 13, 14, 15]]), array([[16, 17, 18, 19],
         [20, 21, 22, 23]])], array([[0, 1, 2, 3],
        [4, 5, 6, 7]]))
1 slices[1]
array([[ 8,  9, 10, 11],
       [12, 13, 14, 15]])

ndarray數組的統計運算

這一小節將介紹如何計算ndarray數組的各個統計量,包括以下幾項:

  • mean 均值
  • std 標准差
  • var 方差
  • sum 求和
  • max 最大值
  • min 最小值
1 # 計算均值,使用arr.mean() 或 np.mean(arr),二者是等價的
2 arr = np.array([[1,2,3], [4,5,6], [7,8,9]])
3 arr, arr.mean(), np.mean(arr)
(array([[1, 2, 3],
        [4, 5, 6],
        [7, 8, 9]]), 5.0, 5.0)
1 # 求和
2 arr.sum(), np.sum(arr)
(45, 45)
1 # 求最大值
2 arr.max(), np.max(arr)
(9, 9)
1 # 求最小值
2 arr.min(), np.min(arr)
(1, 1)
1 # 指定計算的維度
2 # 沿着第1維求平均,也就是將[1, 2, 3]取平均等於2,[4, 5, 6]取平均等於5,[7, 8, 9]取平均等於8
3 arr.mean(axis = 1)
array([2., 5., 8.])
1 # 沿着第0維求和,也就是將[1, 4, 7]求和等於12,[2, 5, 8]求和等於15,[3, 6, 9]求和等於18
2 arr.sum(axis=0)
array([12, 15, 18])
1 # 沿着第0維求最大值,也就是將[1, 4, 7]求最大值等於7,[2, 5, 8]求最大值等於8,[3, 6, 9]求最大值等於9
2 arr.max(axis=0) #axis=0,col; axis=1,row
array([7, 8, 9])
1 # 沿着第1維求最小值,也就是將[1, 2, 3]求最小值等於1,[4, 5, 6]求最小值等於4,[7, 8, 9]求最小值等於7
2 arr.min(axis=1)
array([1, 4, 7])
1 # 計算標准差
2 arr.std(),np.std(arr)
(2.581988897471611, 2.581988897471611)
1 # 計算方差
2 arr.var()
6.666666666666667
1 # 找出最大元素的索引
2 arr = np.array([[1,2,3], [4,15,6], [7,8,9]])
3 arr.argmax(), arr.argmax(axis=0), arr.argmax(axis=1),arr
(4, array([2, 1, 2]), array([2, 1, 2]), array([[ 1,  2,  3],
        [ 4, 15,  6],
        [ 7,  8,  9]]))
1 # 找出最小元素的索引
2 arr.argmin(), arr.argmin(axis=0), arr.argmin(axis=1)
(0, array([0, 0, 0]), array([0, 0, 0]))

隨機數np.random

  • 創建隨機ndarray數組

  • 設置隨機數種子

  • 隨機打亂順序

  • 隨機選取元素

創建隨機ndarray數組

1 # 生成均勻分布隨機數,隨機數取值范圍在[0, 1)之間
2 a = np.random.rand(3, 3)
3 a
array([[0.6420599 , 0.73651207, 0.66565759],
       [0.14290725, 0.81142629, 0.50289975],
       [0.13405143, 0.45266459, 0.68173151]])
1 # 生成均勻分布隨機數,指定隨機數取值范圍和數組形狀
2 a = np.random.uniform(low = -1.0, high = 1.0, size=(2,2))
3 a
array([[-0.67923749, -0.17730746],
       [ 0.12102881, -0.04428187]])
1 # 生成標准正態分布隨機數
2 a = np.random.randn(3, 3)
3 a
array([[ 0.25665606,  1.93389383, -1.70699442],
       [ 0.97149577, -0.92508515,  0.73949167],
       [ 2.43923963, -1.91191295, -0.74102035]])
1 # 生成正態分布隨機數,指定均值loc和方差scale
2 a = np.random.normal(loc = 1.0, scale = 1.0, size = (3,3))
3 a
array([[0.07006288, 1.45427367, 0.5653806 ],
       [1.33709714, 1.26909652, 2.58879916],
       [0.88281434, 0.93290283, 0.09127028]])

設置隨機數種子

1 # 可以多次運行,觀察程序輸出結果是否一致
2 # 如果不設置隨機數種子,觀察多次運行輸出結果是否一致
3 np.random.seed(10)  #設置隨機數種子,每次都產生同樣的隨機數
4 a = np.random.rand(3, 3)
5 a
array([[0.77132064, 0.02075195, 0.63364823],
       [0.74880388, 0.49850701, 0.22479665],
       [0.19806286, 0.76053071, 0.16911084]])

隨機打亂ndarray數組順序

1 # 生成一維數組
2 a = np.arange(0, 30)
3 # 打亂一維數組順序
4 print('before random shuffle: ', a)
5 np.random.shuffle(a)
6 print('after random shuffle: ', a)
('before random shuffle: ', array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
       17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]))
('after random shuffle: ', array([13, 26, 21,  3, 25, 28,  6, 20,  2, 10, 27, 19,  4,  5, 12,  8,  0,
        1, 29, 23, 14, 17, 11,  7, 22, 16, 18, 15,  9, 24]))
1 # 生成一維數組
2 a = np.arange(0, 30)
3 # 將一維數組轉化成2維數組
4 a = a.reshape(10, 3)
5 # 打亂一維數組順序
6 print('before random shuffle: \n{}'.format(a))
7 np.random.shuffle(a)
8 print('after random shuffle: \n{}'.format(a))
 
before random shuffle: 
[[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]
 [12 13 14]
 [15 16 17]
 [18 19 20]
 [21 22 23]
 [24 25 26]
 [27 28 29]]
after random shuffle: 
[[ 3  4  5]
 [24 25 26]
 [21 22 23]
 [12 13 14]
 [ 0  1  2]
 [ 9 10 11]
 [ 6  7  8]
 [15 16 17]
 [27 28 29]
 [18 19 20]]

隨機打亂1維數組順序時,發現所有元素位置都改變了;隨機打亂二維數組順序時,發現只有行的順序被打亂了,列的順序保持不變。

隨機選取元素

1 # 隨機選取一選部分元素
2 a = np.arange(30)
3 b = np.random.choice(a, size=50)    #size如果大於30,則有重復的數字
4 b
array([ 3,  3, 27, 18, 22, 13, 26, 11, 16, 21, 29, 13, 11, 17, 19, 22,  5,
       11, 21,  1, 11, 24,  0,  5,  9,  8,  5, 11, 11, 26,  7,  8, 21,  8,
       28, 13, 27, 25, 25, 14, 17, 21, 13,  9,  1,  4, 23, 28,  7, 27])


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM