python數據分析之numpy、matplotlib的使用

5.3 Python的科學計算包 - Numpy

numpy(Numerical Python extensions)是一個第三方的Python包,用於科學計算。這個庫的前身是1995年就開始開發的一個用於數組運算的庫。通過了長時間的發展,基本上成了絕大部分Python科學計算的基礎包,固然也包括全部提供Python接口的深度學習框架。html

numpy在Linux下的安裝已經在5.1.2中做爲例子講過,Windows下也能夠經過pip,或者到下面網址下載:python

Obtaining NumPy & SciPy librariesapi

5.3.1 基本類型(array)

array,也就是數組,是numpy中最基礎的數據結構,最關鍵的屬性是維度和元素類型,在numpy中,能夠很是方便地建立各類不一樣類型的多維數組,而且執行一些基本基本操做,來看例子:數組

import numpy as np a = [1, 2, 3, 4] # b = np.array(a) # array([1, 2, 3, 4]) type(b) # <type 'numpy.ndarray'> b.shape # (4,) b.argmax() # 3 b.max() # 4 b.mean() # 2.5 c = [[1, 2], [3, 4]] # 二維列表 d = np.array(c) # 二維numpy數組 d.shape # (2, 2) d.size # 4 d.max(axis=0) # 找維度0,也就是最後一個維度上的最大值,array([3, 4]) d.max(axis=1) # 找維度1,也就是倒數第二個維度上的最大值,array([2, 4]) d.mean(axis=0) # 找維度0,也就是第一個維度上的均值,array([ 2., 3.]) d.flatten() # 展開一個numpy數組爲1維數組,array([1, 2, 3, 4]) np.ravel(c) # 展開一個能夠解析的結構爲1維數組,array([1, 2, 3, 4]) # 3x3的浮點型2維數組,而且初始化全部元素值爲1 e = np.ones((3, 3), dtype=np.float) # 建立一個一維數組,元素值是把3重複4次,array([3, 3, 3, 3]) f = np.repeat(3, 4) # 2x2x3的無符號8位整型3維數組,而且初始化全部元素值爲0 g = np.zeros((2, 2, 3), dtype=np.uint8) g.shape # (2, 2, 3) h = g.astype(np.float) # 用另外一種類型表示 l = np.arange(10) # 相似range,array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) m = np.linspace(0, 6, 5)# 等差數列,0到6之間5個取值,array([ 0., 1.5, 3., 4.5, 6.]) p = np.array( [[1, 2, 3, 4], [5, 6, 7, 8]] ) np.save('p.npy', p) # 保存到文件 q = np.load('p.npy') # 從文件讀取 

注意到在導入numpy的時候,咱們將np做爲numpy的別名。這是一種習慣性的用法,後面的章節中咱們也默認這麼使用。做爲一種多維數組結構,array的數組相關操做是很是豐富的:數據結構

import numpy as np ''' 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]]]) ''' a = np.arange(24).reshape((2, 3, 4)) b = a[1][1][1] # 17 ''' array([[ 8, 9, 10, 11],  [20, 21, 22, 23]]) ''' c = a[:, 2, :] ''' 用:表示當前維度上全部下標 array([[ 1, 5, 9],  [13, 17, 21]]) ''' d = a[:, :, 1] ''' 用...表示沒有明確指出的維度 array([[ 1, 5, 9],  [13, 17, 21]]) ''' e = a[..., 1] ''' array([[[ 5, 6],  [ 9, 10]],  [[17, 18],  [21, 22]]]) ''' f = a[:, 1:, 1:-1] ''' 平均分紅3份 [array([0, 1, 2]), array([3, 4, 5]), array([6, 7, 8])] ''' g = np.split(np.arange(9), 3) ''' 按照下標位置進行劃分 [array([0, 1]), array([2, 3, 4, 5]), array([6, 7, 8])] ''' h = np.split(np.arange(9), [2, -3]) l0 = np.arange(6).reshape((2, 3)) l1 = np.arange(6, 12).reshape((2, 3)) ''' vstack是指沿着縱軸拼接兩個array,vertical hstack是指沿着橫軸拼接兩個array,horizontal 更廣義的拼接用concatenate實現,horizontal後的兩句依次等效於vstack和hstack stack不是拼接而是在輸入array的基礎上增長一個新的維度 ''' m = np.vstack((l0, l1)) p = np.hstack((l0, l1)) q = np.concatenate((l0, l1)) r = np.concatenate((l0, l1), axis=-1) s = np.stack((l0, l1)) ''' 按指定軸進行轉置 array([[[ 0, 3], [ 6, 9]], [[ 1, 4], [ 7, 10]], [[ 2, 5], [ 8, 11]]]) ''' t = s.transpose((2, 0, 1)) ''' 默認轉置將維度倒序,對於2維就是橫縱軸互換 array([[ 0, 4, 8], [ 1, 5, 9], [ 2, 6, 10], [ 3, 7, 11]]) ''' u = a[0].transpose() # 或者u=a[0].T也是得到轉置 ''' 逆時針旋轉90度,第二個參數是旋轉次數 array([[ 3, 2, 1, 0], [ 7, 6, 5, 4], [11, 10, 9, 8]]) ''' v = np.rot90(u, 3) ''' 沿縱軸左右翻轉 array([[ 8, 4, 0], [ 9, 5, 1], [10, 6, 2], [11, 7, 3]]) ''' w = np.fliplr(u) ''' 沿水平軸上下翻轉 array([[ 3, 7, 11], [ 2, 6, 10], [ 1, 5, 9], [ 0, 4, 8]]) ''' x = np.flipud(u) ''' 按照一維順序滾動位移 array([[11, 0, 4], [ 8, 1, 5], [ 9, 2, 6], [10, 3, 7]]) ''' y = np.roll(u, 1) ''' 按照指定軸滾動位移 array([[ 8, 0, 4], [ 9, 1, 5], [10, 2, 6], [11, 3, 7]]) ''' z = np.roll(u, 1, axis=1) 

對於一維的array全部Python列表支持的下標相關的方法array也都支持,因此在此沒有特別列出。app

既然叫numerical python,基礎數學運算也是強大的:框架

import numpy as np # 絕對值,1 a = np.abs(-1) # sin函數,1.0 b = np.sin(np.pi/2) # tanh逆函數,0.50000107157840523 c = np.arctanh(0.462118) # e爲底的指數函數,20.085536923187668 d = np.exp(3) # 2的3次方,8 f = np.power(2, 3) # 點積,1*3+2*4=11 g = np.dot([1, 2], [3, 4]) # 開方,5 h = np.sqrt(25) # 求和,10 l = np.sum([1, 2, 3, 4]) # 平均值,5.5 m = np.mean([4, 5, 6, 7]) # 標準差,0.96824583655185426 p = np.std([1, 2, 3, 2, 1, 3, 2, 0]) 

對於array,默認執行對位運算。涉及到多個array的對位運算須要array的維度一致,若是一個array的維度和另外一個array的子維度一致,則在沒有對齊的維度上分別執行對位運算,這種機制叫作廣播(broadcasting),言語解釋比較難,仍是看例子理解:dom

import numpy as np a = np.array([ [1, 2, 3], [4, 5, 6] ]) b = np.array([ [1, 2, 3], [1, 2, 3] ]) ''' 維度同樣的array,對位計算 array([[2, 4, 6],  [5, 7, 9]]) ''' a + b ''' array([[0, 0, 0],  [3, 3, 3]]) ''' a - b ''' array([[ 1, 4, 9],  [ 4, 10, 18]]) ''' a * b ''' array([[1, 1, 1],  [4, 2, 2]]) ''' a / b ''' array([[ 1, 4, 9],  [16, 25, 36]]) ''' a ** 2 ''' array([[ 1, 4, 27],  [ 4, 25, 216]]) ''' a ** b c = np.array([ [1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12] ]) d = np.array([2, 2, 2]) ''' 廣播機制讓計算的表達式保持簡潔 d和c的每一行分別進行運算 array([[ 3, 4, 5],  [ 6, 7, 8],  [ 9, 10, 11],  [12, 13, 14]]) ''' c + d ''' array([[ 2, 4, 6],  [ 8, 10, 12],  [14, 16, 18],  [20, 22, 24]]) ''' c * d ''' 1和c的每一個元素分別進行運算 array([[ 0, 1, 2],  [ 3, 4, 5],  [ 6, 7, 8],  [ 9, 10, 11]]) ''' c - 1 

5.3.2 線性代數模塊(linalg)

在深度學習相關的數據處理和運算中,線性代數模塊(linalg)是最經常使用的之一。結合numpy提供的基本函數,能夠對向量,矩陣,或是說多維張量進行一些基本的運算:ide

import numpy as np a = np.array([3, 4]) np.linalg.norm(a) b = np.array([ [1, 2, 3], [4, 5, 6], [7, 8, 9] ]) c = np.array([1, 0, 1]) # 矩陣和向量之間的乘法 np.dot(b, c) # array([ 4, 10, 16]) np.dot(c, b.T) # array([ 4, 10, 16]) np.trace(b) # 求矩陣的跡,15 np.linalg.det(b) # 求矩陣的行列式值,0 np.linalg.matrix_rank(b) # 求矩陣的秩,2,不滿秩,由於行與行之間等差 d = np.array([ [2, 1], [1, 2] ]) ''' 對正定矩陣求本徵值和本徵向量 本徵值爲u,array([ 3., 1.]) 本徵向量構成的二維array爲v, array([[ 0.70710678, -0.70710678],  [ 0.70710678, 0.70710678]]) 是沿着45°方向 eig()是通常狀況的本徵值分解,對於更常見的對稱實數矩陣, eigh()更快且更穩定,不過輸出的值的順序和eig()是相反的 ''' u, v = np.linalg.eig(d) # Cholesky分解並重建 l = np.linalg.cholesky(d) ''' array([[ 2., 1.],  [ 1., 2.]]) ''' np.dot(l, l.T) e = np.array([ [1, 2], [3, 4] ]) # 對不鎮定矩陣,進行SVD分解並重建 U, s, V = np.linalg.svd(e) S = np.array([ [s[0], 0], [0, s[1]] ]) ''' array([[ 1., 2.], [ 3., 4.]]) ''' np.dot(U, np.dot(S, V)) 

5.3.3 隨機模塊(random)

隨機模塊包含了隨機數產生和統計分佈相關的基本函數,Python自己也有隨機模塊random,不過功能更豐富,仍是來看例子:函數

import numpy as np import numpy.random as random # 設置隨機數種子 random.seed(42) # 產生一個1x3,[0,1)之間的浮點型隨機數 # array([[ 0.37454012, 0.95071431, 0.73199394]]) # 後面的例子就不在註釋中給出具體結果了 random.rand(1, 3) # 產生一個[0,1)之間的浮點型隨機數 random.random() # 下邊4個沒有區別,都是按照指定大小產生[0,1)之間的浮點型隨機數array,不Pythonic… random.random((3, 3)) random.sample((3, 3)) random.random_sample((3, 3)) random.ranf((3, 3)) # 產生10個[1,6)之間的浮點型隨機數 5*random.random(10) + 1 random.uniform(1, 6, 10) # 產生10個[1,6)之間的整型隨機數 random.randint(1, 6, 10) # 產生2x5的標準正態分佈樣本 random.normal(size=(5, 2)) # 產生5個,n=5,p=0.5的二項分佈樣本 random.binomial(n=5, p=0.5, size=5) a = np.arange(10) # 從a中有回放的隨機採樣7個 random.choice(a, 7) # 從a中無回放的隨機採樣7個 random.choice(a, 7, replace=False) # 對a進行亂序並返回一個新的array b = random.permutation(a) # 對a進行in-place亂序 random.shuffle(a) # 生成一個長度爲9的隨機bytes序列並做爲str返回 # '\x96\x9d\xd1?\xe6\x18\xbb\x9a\xec' random.bytes(9) 

隨機模塊能夠很方便地讓咱們作一些快速模擬去驗證一些結論。好比來考慮一個很是違反直覺的機率題例子:一個選手去參加一個TV秀,有三扇門,其中一扇門後有獎品,這扇門只有主持人知道。選手先隨機選一扇門,但並不打開,主持人看到後,會打開其他兩扇門中沒有獎品的一扇門。而後,主持人問選手,是否要改變一開始的選擇?

這個問題的答案是應該改變一開始的選擇。在第一次選擇的時候,選錯的機率是2/3,選對的機率是1/3。第一次選擇以後,主持人至關於幫忙剔除了一個錯誤答案,因此若是一開始選的是錯的,這時候換掉就選對了;而若是一開始就選對,則這時候換掉就錯了。根據以上,一開始選錯的機率就是換掉以後選對的機率(2/3),這個機率大於一開始就選對的機率(1/3),因此應該換。雖然道理上是這樣,可是仍是有些繞,要是經過推理就是搞不明白怎麼辦,不要緊,用隨機模擬就能夠輕鬆獲得答案:

import numpy.random as random random.seed(42) # 作10000次實驗 n_tests = 10000 # 生成每次實驗的獎品所在的門的編號 # 0表示第一扇門,1表示第二扇門,2表示第三扇門 winning_doors = random.randint(0, 3, n_tests) # 記錄若是換門的中獎次數 change_mind_wins = 0 # 記錄若是堅持的中獎次數 insist_wins = 0 # winning_door就是獲勝門的編號 for winning_door in winning_doors: # 隨機挑了一扇門 first_try = random.randint(0, 3) # 其餘門的編號 remaining_choices = [i for i in range(3) if i != first_try] # 沒有獎品的門的編號,這個信息只有主持人知道 wrong_choices = [i for i in range(3) if i != winning_door] # 一開始選擇的門主持人無法打開,因此從主持人能夠打開的門中剔除 if first_try in wrong_choices: wrong_choices.remove(first_try) # 這時wrong_choices變量就是主持人能夠打開的門的編號 # 注意此時若是一開始選擇正確,則能夠打開的門是兩扇,主持人隨便開一扇門 # 若是一開始選到了空門,則主持人只能打開剩下一扇空門 screened_out = random.choice(wrong_choices) remaining_choices.remove(screened_out) # 因此雖然代碼寫了好些行,若是策略固定的話, # 改變主意的獲勝機率就是一開始選錯的機率,是2/3 # 而堅持選擇的獲勝機率就是一開始就選對的機率,是1/3 # 如今除了一開始選擇的編號,和主持人幫助剔除的錯誤編號,只剩下一扇門 # 若是要改變注意則這扇門就是最終的選擇 changed_mind_try = remaining_choices[0] # 結果揭曉,記錄下來 change_mind_wins += 1 if changed_mind_try == winning_door else 0 insist_wins += 1 if first_try == winning_door else 0 # 輸出10000次測試的最終結果,和推導的結果差很少: # You win 6616 out of 10000 tests if you changed your mind # You win 3384 out of 10000 tests if you insist on the initial choice print( 'You win {1} out of {0} tests if you changed your mind\n' 'You win {2} out of {0} tests if you insist on the initial choice'.format( n_tests, change_mind_wins, insist_wins ) ) 

5.4 Python的可視化包 – Matplotlib

Matplotlib是Python中最經常使用的可視化工具之一,能夠很是方便地建立海量類型地2D圖表和一些基本的3D圖表。Matplotlib最先是爲了可視化癲癇病人的腦皮層電圖相關的信號而研發,由於在函數的設計上參考了MATLAB,因此叫作Matplotlib。Matplotlib首次發表於2007年,在開源和社區的推進下,如今在基於Python的各個科學計算領域都獲得了普遍應用。Matplotlib的原做者John D. Hunter博士是一名神經生物學家,2012年不幸因癌症去世,感謝他建立了這樣一個偉大的庫。

安裝Matplotlib的方式和numpy很像,能夠直接經過Unix/Linux的軟件管理工具,好比Ubuntu 16.04 LTS下,輸入:

>> sudo apt install python-matplotlib

或者經過pip安裝:

>> pip install matplotlib

Windows下也能夠經過pip,或是到官網下載:

python plotting - Matplotlib 1.5.3 documentation

Matplotlib很是強大,不過在深度學習中經常使用的其實只有很基礎的一些功能,這節主要介紹2D圖表,3D圖表和圖像顯示。

5.4.1 2D圖表

Matplotlib中最基礎的模塊是pyplot。先從最簡單的點圖和線圖開始,好比咱們有一組數據,還有一個擬合模型,經過下面的代碼圖來可視化:

import numpy as np import matplotlib as mpl import matplotlib.pyplot as plt # 經過rcParams設置全局橫縱軸字體大小 mpl.rcParams['xtick.labelsize'] = 24 mpl.rcParams['ytick.labelsize'] = 24 np.random.seed(42) # x軸的採樣點 x = np.linspace(0, 5, 100) # 經過下面曲線加上噪聲生成數據,因此擬合模型就用y了…… y = 2*np.sin(x) + 0.3*x**2 y_data = y + np.random.normal(scale=0.3, size=100) # figure()指定圖表名稱 plt.figure('data') # '.'標明畫散點圖,每一個散點的形狀是個圓 plt.plot(x, y_data, '.') # 畫模型的圖,plot函數默認畫連線圖 plt.figure('model') plt.plot(x, y) # 兩個圖畫一塊兒 plt.figure('data & model') # 經過'k'指定線的顏色,lw指定線的寬度 # 第三個參數除了顏色也能夠指定線形,好比'r--'表示紅色虛線 # 更多屬性能夠參考官網:http://matplotlib.org/api/pyplot_api.html plt.plot(x, y, 'k', lw=3) # scatter能夠更容易地生成散點圖 plt.scatter(x, y_data) # 將當前figure的圖保存到文件result.png plt.savefig('result.png') # 必定要加上這句才能讓畫好的圖顯示在屏幕上 plt.show() 

matplotlib和pyplot的慣用別名分別是mpl和plt,上面代碼生成的圖像以下:

5.3 Python的科學計算包 - Numpy

numpy(Numerical Python extensions)是一個第三方的Python包,用於科學計算。這個庫的前身是1995年就開始開發的一個用於數組運算的庫。通過了長時間的發展,基本上成了絕大部分Python科學計算的基礎包,固然也包括全部提供Python接口的深度學習框架。

numpy在Linux下的安裝已經在5.1.2中做爲例子講過,Windows下也能夠經過pip,或者到下面網址下載:

Obtaining NumPy & SciPy libraries

5.3.1 基本類型(array)

array,也就是數組,是numpy中最基礎的數據結構,最關鍵的屬性是維度和元素類型,在numpy中,能夠很是方便地建立各類不一樣類型的多維數組,而且執行一些基本基本操做,來看例子:

import numpy as np a = [1, 2, 3, 4] # b = np.array(a) # array([1, 2, 3, 4]) type(b) # <type 'numpy.ndarray'> b.shape # (4,) b.argmax() # 3 b.max() # 4 b.mean() # 2.5 c = [[1, 2], [3, 4]] # 二維列表 d = np.array(c) # 二維numpy數組 d.shape # (2, 2) d.size # 4 d.max(axis=0) # 找維度0,也就是最後一個維度上的最大值,array([3, 4]) d.max(axis=1) # 找維度1,也就是倒數第二個維度上的最大值,array([2, 4]) d.mean(axis=0) # 找維度0,也就是第一個維度上的均值,array([ 2., 3.]) d.flatten() # 展開一個numpy數組爲1維數組,array([1, 2, 3, 4]) np.ravel(c) # 展開一個能夠解析的結構爲1維數組,array([1, 2, 3, 4]) # 3x3的浮點型2維數組,而且初始化全部元素值爲1 e = np.ones((3, 3), dtype=np.float) # 建立一個一維數組,元素值是把3重複4次,array([3, 3, 3, 3]) f = np.repeat(3, 4) # 2x2x3的無符號8位整型3維數組,而且初始化全部元素值爲0 g = np.zeros((2, 2, 3), dtype=np.uint8) g.shape # (2, 2, 3) h = g.astype(np.float) # 用另外一種類型表示 l = np.arange(10) # 相似range,array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) m = np.linspace(0, 6, 5)# 等差數列,0到6之間5個取值,array([ 0., 1.5, 3., 4.5, 6.]) p = np.array( [[1, 2, 3, 4], [5, 6, 7, 8]] ) np.save('p.npy', p) # 保存到文件 q = np.load('p.npy') # 從文件讀取 

注意到在導入numpy的時候,咱們將np做爲numpy的別名。這是一種習慣性的用法,後面的章節中咱們也默認這麼使用。做爲一種多維數組結構,array的數組相關操做是很是豐富的:

import numpy as np ''' 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]]]) ''' a = np.arange(24).reshape((2, 3, 4)) b = a[1][1][1] # 17 ''' array([[ 8, 9, 10, 11],  [20, 21, 22, 23]]) ''' c = a[:, 2, :] ''' 用:表示當前維度上全部下標 array([[ 1, 5, 9],  [13, 17, 21]]) ''' d = a[:, :, 1] ''' 用...表示沒有明確指出的維度 array([[ 1, 5, 9],  [13, 17, 21]]) ''' e = a[..., 1] ''' array([[[ 5, 6],  [ 9, 10]],  [[17, 18],  [21, 22]]]) ''' f = a[:, 1:, 1:-1] ''' 平均分紅3份 [array([0, 1, 2]), array([3, 4, 5]), array([6, 7, 8])] ''' g = np.split(np.arange(9), 3) ''' 按照下標位置進行劃分 [array([0, 1]), array([2, 3, 4, 5]), array([6, 7, 8])] ''' h = np.split(np.arange(9), [2, -3]) l0 = np.arange(6).reshape((2, 3)) l1 = np.arange(6, 12).reshape((2, 3)) ''' vstack是指沿着縱軸拼接兩個array,vertical hstack是指沿着橫軸拼接兩個array,horizontal 更廣義的拼接用concatenate實現,horizontal後的兩句依次等效於vstack和hstack stack不是拼接而是在輸入array的基礎上增長一個新的維度 ''' m = np.vstack((l0, l1)) p = np.hstack((l0, l1)) q = np.concatenate((l0, l1)) r = np.concatenate((l0, l1), axis=-1) s = np.stack((l0, l1)) ''' 按指定軸進行轉置 array([[[ 0, 3], [ 6, 9]], [[ 1, 4], [ 7, 10]], [[ 2, 5], [ 8, 11]]]) ''' t = s.transpose((2, 0, 1)) ''' 默認轉置將維度倒序,對於2維就是橫縱軸互換 array([[ 0, 4, 8], [ 1, 5, 9], [ 2, 6, 10], [ 3, 7, 11]]) ''' u = a[0].transpose() # 或者u=a[0].T也是得到轉置 ''' 逆時針旋轉90度,第二個參數是旋轉次數 array([[ 3, 2, 1, 0], [ 7, 6, 5, 4], [11, 10, 9, 8]]) ''' v = np.rot90(u, 3) ''' 沿縱軸左右翻轉 array([[ 8, 4, 0], [ 9, 5, 1], [10, 6, 2], [11, 7, 3]]) ''' w = np.fliplr(u) ''' 沿水平軸上下翻轉 array([[ 3, 7, 11], [ 2, 6, 10], [ 1, 5, 9], [ 0, 4, 8]]) ''' x = np.flipud(u) ''' 按照一維順序滾動位移 array([[11, 0, 4], [ 8, 1, 5], [ 9, 2, 6], [10, 3, 7]]) ''' y = np.roll(u, 1) ''' 按照指定軸滾動位移 array([[ 8, 0, 4], [ 9, 1, 5], [10, 2, 6], [11, 3, 7]]) ''' z = np.roll(u, 1, axis=1) 

對於一維的array全部Python列表支持的下標相關的方法array也都支持,因此在此沒有特別列出。

既然叫numerical python,基礎數學運算也是強大的:

import numpy as np # 絕對值,1 a = np.abs(-1) # sin函數,1.0 b = np.sin(np.pi/2) # tanh逆函數,0.50000107157840523 c = np.arctanh(0.462118) # e爲底的指數函數,20.085536923187668 d = np.exp(3) # 2的3次方,8 f = np.power(2, 3) # 點積,1*3+2*4=11 g = np.dot([1, 2], [3, 4]) # 開方,5 h = np.sqrt(25) # 求和,10 l = np.sum([1, 2, 3, 4]) # 平均值,5.5 m = np.mean([4, 5, 6, 7]) # 標準差,0.96824583655185426 p = np.std([1, 2, 3, 2, 1, 3, 2, 0]) 

對於array,默認執行對位運算。涉及到多個array的對位運算須要array的維度一致,若是一個array的維度和另外一個array的子維度一致,則在沒有對齊的維度上分別執行對位運算,這種機制叫作廣播(broadcasting),言語解釋比較難,仍是看例子理解:

import numpy as np a = np.array([ [1, 2, 3], [4, 5, 6] ]) b = np.array([ [1, 2, 3], [1, 2, 3] ]) ''' 維度同樣的array,對位計算 array([[2, 4, 6],  [5, 7, 9]]) ''' a + b ''' array([[0, 0, 0],  [3, 3, 3]]) ''' a - b ''' array([[ 1, 4, 9],  [ 4, 10, 18]]) ''' a * b ''' array([[1, 1, 1],  [4, 2, 2]]) ''' a / b ''' array([[ 1, 4, 9],  [16, 25, 36]]) ''' a ** 2 ''' array([[ 1, 4, 27],  [ 4, 25, 216]]) ''' a ** b c = np.array([ [1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12] ]) d = np.array([2, 2, 2]) ''' 廣播機制讓計算的表達式保持簡潔 d和c的每一行分別進行運算 array([[ 3, 4, 5],  [ 6, 7, 8],  [ 9, 10, 11],  [12, 13, 14]]) ''' c + d ''' array([[ 2, 4, 6],  [ 8, 10, 12],  [14, 16, 18],  [20, 22, 24]]) ''' c * d ''' 1和c的每一個元素分別進行運算 array([[ 0, 1, 2],  [ 3, 4, 5],  [ 6, 7, 8],  [ 9, 10, 11]]) ''' c - 1 

5.3.2 線性代數模塊(linalg)

在深度學習相關的數據處理和運算中,線性代數模塊(linalg)是最經常使用的之一。結合numpy提供的基本函數,能夠對向量,矩陣,或是說多維張量進行一些基本的運算:

import numpy as np a = np.array([3, 4]) np.linalg.norm(a) b = np.array([ [1, 2, 3], [4, 5, 6], [7, 8, 9] ]) c = np.array([1, 0, 1]) # 矩陣和向量之間的乘法 np.dot(b, c) # array([ 4, 10, 16]) np.dot(c, b.T) # array([ 4, 10, 16]) np.trace(b) # 求矩陣的跡,15 np.linalg.det(b) # 求矩陣的行列式值,0 np.linalg.matrix_rank(b) # 求矩陣的秩,2,不滿秩,由於行與行之間等差 d = np.array([ [2, 1], [1, 2] ]) ''' 對正定矩陣求本徵值和本徵向量 本徵值爲u,array([ 3., 1.]) 本徵向量構成的二維array爲v, array([[ 0.70710678, -0.70710678],  [ 0.70710678, 0.70710678]]) 是沿着45°方向 eig()是通常狀況的本徵值分解,對於更常見的對稱實數矩陣, eigh()更快且更穩定,不過輸出的值的順序和eig()是相反的 ''' u, v = np.linalg.eig(d) # Cholesky分解並重建 l = np.linalg.cholesky(d) ''' array([[ 2., 1.],  [ 1., 2.]]) ''' np.dot(l, l.T) e = np.array([ [1, 2], [3, 4] ]) # 對不鎮定矩陣,進行SVD分解並重建 U, s, V = np.linalg.svd(e) S = np.array([ [s[0], 0], [0, s[1]] ]) ''' array([[ 1., 2.], [ 3., 4.]]) ''' np.dot(U, np.dot(S, V)) 

5.3.3 隨機模塊(random)

隨機模塊包含了隨機數產生和統計分佈相關的基本函數,Python自己也有隨機模塊random,不過功能更豐富,仍是來看例子:

import numpy as np import numpy.random as random # 設置隨機數種子 random.seed(42) # 產生一個1x3,[0,1)之間的浮點型隨機數 # array([[ 0.37454012, 0.95071431, 0.73199394]]) # 後面的例子就不在註釋中給出具體結果了 random.rand(1, 3) # 產生一個[0,1)之間的浮點型隨機數 random.random() # 下邊4個沒有區別,都是按照指定大小產生[0,1)之間的浮點型隨機數array,不Pythonic… random.random((3, 3)) random.sample((3, 3)) random.random_sample((3, 3)) random.ranf((3, 3)) # 產生10個[1,6)之間的浮點型隨機數 5*random.random(10) + 1 random.uniform(1, 6, 10) # 產生10個[1,6)之間的整型隨機數 random.randint(1, 6, 10) # 產生2x5的標準正態分佈樣本 random.normal(size=(5, 2)) # 產生5個,n=5,p=0.5的二項分佈樣本 random.binomial(n=5, p=0.5, size=5) a = np.arange(10) # 從a中有回放的隨機採樣7個 random.choice(a, 7) # 從a中無回放的隨機採樣7個 random.choice(a, 7, replace=False) # 對a進行亂序並返回一個新的array b = random.permutation(a) # 對a進行in-place亂序 random.shuffle(a) # 生成一個長度爲9的隨機bytes序列並做爲str返回 # '\x96\x9d\xd1?\xe6\x18\xbb\x9a\xec' random.bytes(9) 

隨機模塊能夠很方便地讓咱們作一些快速模擬去驗證一些結論。好比來考慮一個很是違反直覺的機率題例子:一個選手去參加一個TV秀,有三扇門,其中一扇門後有獎品,這扇門只有主持人知道。選手先隨機選一扇門,但並不打開,主持人看到後,會打開其他兩扇門中沒有獎品的一扇門。而後,主持人問選手,是否要改變一開始的選擇?

這個問題的答案是應該改變一開始的選擇。在第一次選擇的時候,選錯的機率是2/3,選對的機率是1/3。第一次選擇以後,主持人至關於幫忙剔除了一個錯誤答案,因此若是一開始選的是錯的,這時候換掉就選對了;而若是一開始就選對,則這時候換掉就錯了。根據以上,一開始選錯的機率就是換掉以後選對的機率(2/3),這個機率大於一開始就選對的機率(1/3),因此應該換。雖然道理上是這樣,可是仍是有些繞,要是經過推理就是搞不明白怎麼辦,不要緊,用隨機模擬就能夠輕鬆獲得答案:

import numpy.random as random random.seed(42) # 作10000次實驗 n_tests = 10000 # 生成每次實驗的獎品所在的門的編號 # 0表示第一扇門,1表示第二扇門,2表示第三扇門 winning_doors = random.randint(0, 3, n_tests) # 記錄若是換門的中獎次數 change_mind_wins = 0 # 記錄若是堅持的中獎次數 insist_wins = 0 # winning_door就是獲勝門的編號 for winning_door in winning_doors: # 隨機挑了一扇門 first_try = random.randint(0, 3) # 其餘門的編號 remaining_choices = [i for i in range(3) if i != first_try] # 沒有獎品的門的編號,這個信息只有主持人知道 wrong_choices = [i for i in range(3) if i != winning_door] # 一開始選擇的門主持人無法打開,因此從主持人能夠打開的門中剔除 if first_try in wrong_choices: wrong_choices.remove(first_try) # 這時wrong_choices變量就是主持人能夠打開的門的編號 # 注意此時若是一開始選擇正確,則能夠打開的門是兩扇,主持人隨便開一扇門 # 若是一開始選到了空門,則主持人只能打開剩下一扇空門 screened_out = random.choice(wrong_choices) remaining_choices.remove(screened_out) # 因此雖然代碼寫了好些行,若是策略固定的話, # 改變主意的獲勝機率就是一開始選錯的機率,是2/3 # 而堅持選擇的獲勝機率就是一開始就選對的機率,是1/3 # 如今除了一開始選擇的編號,和主持人幫助剔除的錯誤編號,只剩下一扇門 # 若是要改變注意則這扇門就是最終的選擇 changed_mind_try = remaining_choices[0] # 結果揭曉,記錄下來 change_mind_wins += 1 if changed_mind_try == winning_door else 0 insist_wins += 1 if first_try == winning_door else 0 # 輸出10000次測試的最終結果,和推導的結果差很少: # You win 6616 out of 10000 tests if you changed your mind # You win 3384 out of 10000 tests if you insist on the initial choice print( 'You win {1} out of {0} tests if you changed your mind\n' 'You win {2} out of {0} tests if you insist on the initial choice'.format( n_tests, change_mind_wins, insist_wins ) ) 

5.4 Python的可視化包 – Matplotlib

Matplotlib是Python中最經常使用的可視化工具之一,能夠很是方便地建立海量類型地2D圖表和一些基本的3D圖表。Matplotlib最先是爲了可視化癲癇病人的腦皮層電圖相關的信號而研發,由於在函數的設計上參考了MATLAB,因此叫作Matplotlib。Matplotlib首次發表於2007年,在開源和社區的推進下,如今在基於Python的各個科學計算領域都獲得了普遍應用。Matplotlib的原做者John D. Hunter博士是一名神經生物學家,2012年不幸因癌症去世,感謝他建立了這樣一個偉大的庫。

安裝Matplotlib的方式和numpy很像,能夠直接經過Unix/Linux的軟件管理工具,好比Ubuntu 16.04 LTS下,輸入:

>> sudo apt install python-matplotlib

或者經過pip安裝:

>> pip install matplotlib

Windows下也能夠經過pip,或是到官網下載:

python plotting - Matplotlib 1.5.3 documentation

Matplotlib很是強大,不過在深度學習中經常使用的其實只有很基礎的一些功能,這節主要介紹2D圖表,3D圖表和圖像顯示。

5.4.1 2D圖表

Matplotlib中最基礎的模塊是pyplot。先從最簡單的點圖和線圖開始,好比咱們有一組數據,還有一個擬合模型,經過下面的代碼圖來可視化:

import numpy as np import matplotlib as mpl import matplotlib.pyplot as plt # 經過rcParams設置全局橫縱軸字體大小 mpl.rcParams['xtick.labelsize'] = 24 mpl.rcParams['ytick.labelsize'] = 24 np.random.seed(42) # x軸的採樣點 x = np.linspace(0, 5, 100) # 經過下面曲線加上噪聲生成數據,因此擬合模型就用y了…… y = 2*np.sin(x) + 0.3*x**2 y_data = y + np.random.normal(scale=0.3, size=100) # figure()指定圖表名稱 plt.figure('data') # '.'標明畫散點圖,每一個散點的形狀是個圓 plt.plot(x, y_data, '.') # 畫模型的圖,plot函數默認畫連線圖 plt.figure('model') plt.plot(x, y) # 兩個圖畫一塊兒 plt.figure('data & model') # 經過'k'指定線的顏色,lw指定線的寬度 # 第三個參數除了顏色也能夠指定線形,好比'r--'表示紅色虛線 # 更多屬性能夠參考官網:http://matplotlib.org/api/pyplot_api.html plt.plot(x, y, 'k', lw=3) # scatter能夠更容易地生成散點圖 plt.scatter(x, y_data) # 將當前figure的圖保存到文件result.png plt.savefig('result.png') # 必定要加上這句才能讓畫好的圖顯示在屏幕上 plt.show() 

matplotlib和pyplot的慣用別名分別是mpl和plt,上面代碼生成的圖像以下:

基本的畫圖方法就是這麼簡單,若是想了解更多pyplot的屬性和方法來畫出風格多樣的圖像,能夠參考官網:

pyplot - Matplotlib 1.5.3 documentation

Customizing matplotlib

點和線圖表只是最基本的用法,有的時候咱們獲取了分組數據要作對比,柱狀或餅狀類型的圖或許更合適:

import numpy as np import matplotlib as mpl import matplotlib.pyplot as plt mpl.rcParams['axes.titlesize'] = 20 mpl.rcParams['xtick.labelsize'] = 16 mpl.rcParams['ytick.labelsize'] = 16 mpl.rcParams['axes.labelsize'] = 16 mpl.rcParams['xtick.major.size'] = 0 mpl.rcParams['ytick.major.size'] = 0 # 包含了狗,貓和獵豹的最高奔跑速度,還有對應的可視化顏色 speed_map = { 'dog': (48, '#7199cf'), 'cat': (45, '#4fc4aa'), 'cheetah': (120, '#e1a7a2') } # 總體圖的標題 fig = plt.figure('Bar chart & Pie chart') # 在整張圖上加入一個子圖,121的意思是在一個1行2列的子圖中的第一張 ax = fig.add_subplot(121) ax.set_title('Running speed - bar chart') # 生成x軸每一個元素的位置 xticks = np.arange(3) # 定義柱狀圖每一個柱的寬度 bar_width = 0.5 # 動物名稱 animals = speed_map.keys() # 奔跑速度 speeds = [x[0] for x in speed_map.values()] # 對應顏色 colors = [x[1] for x in speed_map.values()] # 畫柱狀圖,橫軸是動物標籤的位置,縱軸是速度,定義柱的寬度,同時設置柱的邊緣爲透明 bars = ax.bar(xticks, speeds, width=bar_width, edgecolor='none') # 設置y軸的標題 ax.set_ylabel('Speed(km/h)') # x軸每一個標籤的具體位置,設置爲每一個柱的中央 ax.set_xticks(xticks+bar_width/2) # 設置每一個標籤的名字 ax.set_xticklabels(animals) # 設置x軸的範圍 ax.set_xlim([bar_width/2-0.5, 3-bar_width/2]) # 設置y軸的範圍 ax.set_ylim([0, 125]) # 給每一個bar分配指定的顏色 for bar, color in zip(bars, colors): bar.set_color(color) # 在122位置加入新的圖 ax = fig.add_subplot(122) ax.set_title('Running speed - pie chart') # 生成同時包含名稱和速度的標籤 labels = ['{}\n{} km/h'.format(animal, speed) for animal, speed in zip(animals, speeds)] # 畫餅狀圖,並指定標籤和對應顏色 ax.pie(speeds, labels=labels, colors=colors) plt.show() 

在這段代碼中又出現了一個新的東西叫作,一個用ax命名的對象。在Matplotlib中,畫圖時有兩個經常使用概念,一個是平時畫圖蹦出的一個窗口,這叫一個figure。Figure至關於一個大的畫布,在每一個figure中,又能夠存在多個子圖,這種子圖叫作axes。顧名思義,有了橫縱軸就是一幅簡單的圖表。在上面代碼中,先把figure定義成了一個一行兩列的大畫布,而後經過fig.add_subplot()加入兩個新的子圖。subplot的定義格式頗有趣,數字的前兩位分別定義行數和列數,最後一位定義新加入子圖的所處順序,固然想寫明確些也沒問題,用逗號分開便可。。上面這段代碼產生的圖像以下:

5.3.1 3D圖表

Matplotlib中也能支持一些基礎的3D圖表,好比曲面圖,散點圖和柱狀圖。這些3D圖表須要使用mpl_toolkits模塊,先來看一個簡單的曲面圖的例子:

import matplotlib.pyplot as plt import numpy as np # 3D圖標必須的模塊,project='3d'的定義 from mpl_toolkits.mplot3d import Axes3D np.random.seed(42) n_grids = 51 # x-y平面的格點數 c = n_grids / 2 # 中心位置 nf = 2 # 低頻成分的個數 # 生成格點 x = np.linspace(0, 1, n_grids) y = np.linspace(0, 1, n_grids) # x和y是長度爲n_grids的array # meshgrid會把x和y組合成n_grids*n_grids的array,X和Y對應位置就是全部格點的座標 X, Y = np.meshgrid(x, y) # 生成一個0值的傅里葉譜 spectrum = np.zeros((n_grids, n_grids), dtype=np.complex) # 生成一段噪音,長度是(2*nf+1)**2/2 noise = [np.complex(x, y) for x, y in np.random.uniform(-1,1,((2*nf+1)**2/2, 2))] # 傅里葉頻譜的每一項和其共軛關於中心對稱 noisy_block = np.concatenate((noise, [0j], np.conjugate(noise[::-1]))) # 將生成的頻譜做爲低頻成分 spectrum[c-nf:c+nf+1, c-nf:c+nf+1] = noisy_block.reshape((2*nf+1, 2*nf+1)) # 進行反傅里葉變換 Z = np.real(np.fft.ifft2(np.fft.ifftshift(spectrum))) # 建立圖表 fig = plt.figure('3D surface & wire') # 第一個子圖,surface圖 ax = fig.add_subplot(1, 2, 1, projection='3d') # alpha定義透明度,cmap是color map # rstride和cstride是兩個方向上的採樣,越小越精細,lw是線寬 ax.plot_surface(X, Y, Z, alpha=0.7, cmap='jet', rstride=1, cstride=1, lw=0) # 第二個子圖,網線圖 ax = fig.add_subplot(1, 2, 2, projection='3d') ax.plot_wireframe(X, Y, Z, rstride=3, cstride=3, lw=0.5) plt.show() 

這個例子中先生成一個全部值均爲0的複數array做爲初始頻譜,而後把頻譜中央部分用隨機生成,但同時共軛關於中心對稱的子矩陣進行填充。這至關於只有低頻成分的一個隨機頻譜。最後進行反傅里葉變換就獲得一個隨機波動的曲面,圖像以下:

3D的散點圖也是經常用來查看空間樣本分佈的一種手段,而且畫起來比表面圖和網線圖更加簡單,來看例子:

import matplotlib.pyplot as plt import numpy as np from mpl_toolkits.mplot3d import Axes3D np.random.seed(42) # 採樣個數500 n_samples = 500 dim = 3 # 先生成一組3維正態分佈數據,數據方向徹底隨機 samples = np.random.multivariate_normal( np.zeros(dim), np.eye(dim), n_samples ) # 經過把每一個樣本到原點距離和均勻分佈吻合獲得球體內均勻分佈的樣本 for i in range(samples.shape[0]): r = np.power(np.random.random(), 1.0/3.0) samples[i] *= r / np.linalg.norm(samples[i]) upper_samples = [] lower_samples = [] for x, y, z in samples: # 3x+2y-z=1做爲判別平面 if z > 3*x + 2*y - 1: upper_samples.append((x, y, z)) else: lower_samples.append((x, y, z)) fig = plt.figure('3D scatter plot') ax = fig.add_subplot(111, projection='3d') uppers = np.array(upper_samples) lowers = np.array(lower_samples) # 用不一樣顏色不一樣形狀的圖標表示平面上下的樣本 # 判別平面上半部分爲紅色圓點,下半部分爲綠色三角 ax.scatter(uppers[:, 0], uppers[:, 1], uppers[:, 2], c='r', marker='o') ax.scatter(lowers[:, 0], lowers[:, 1], lowers[:, 2], c='g', marker='^') plt.show() 

這個例子中,爲了方便,直接先採樣了一堆3維的正態分佈樣本,保證方向上的均勻性。而後歸一化,讓每一個樣本到原點的距離爲1,至關於獲得了一個均勻分佈在球面上的樣本。再接着把每一個樣本都乘上一個均勻分佈隨機數的開3次方,這樣就獲得了在球體內均勻分佈的樣本,最後根據判別平面3x+2y-z-1=0對平面兩側樣本用不一樣的形狀和顏色畫出,圖像以下:

5.3.1 圖像顯示

Matplotlib也支持圖像的存取和顯示,而且和OpenCV一類的接口比起來,對於通常的二維矩陣的可視化要方便不少,來看例子:

import matplotlib.pyplot as plt # 讀取一張小白狗的照片並顯示 plt.figure('A Little White Dog') little_dog_img = plt.imread('little_white_dog.jpg') plt.imshow(little_dog_img) # Z是上小節生成的隨機圖案,img0就是Z,img1是Z作了個簡單的變換 img0 = Z img1 = 3*Z + 4 # cmap指定爲'gray'用來顯示灰度圖 fig = plt.figure('Auto Normalized Visualization') ax0 = fig.add_subplot(121) ax0.imshow(img0, cmap='gray') ax1 = fig.add_subplot(122) ax1.imshow(img1, cmap='gray') plt.show() 

這段代碼中第一個例子是讀取一個本地圖片並顯示,第二個例子中直接把上小節中反傅里葉變換生成的矩陣做爲圖像拿過來,原圖和通過乘以3再加4變換的圖直接繪製了兩個形狀同樣,可是值的範圍不同的圖案。顯示的時候imshow會自動進行歸一化,把最亮的值顯示爲純白,最暗的值顯示爲純黑。這是一種很是方便的設定,尤爲是查看深度學習中某個卷積層的響應圖時。獲得圖像以下:

 

 

 

基本的畫圖方法就是這麼簡單,若是想了解更多pyplot的屬性和方法來畫出風格多樣的圖像,能夠參考官網:

pyplot - Matplotlib 1.5.3 documentation

Customizing matplotlib

點和線圖表只是最基本的用法,有的時候咱們獲取了分組數據要作對比,柱狀或餅狀類型的圖或許更合適:

import numpy as np import matplotlib as mpl import matplotlib.pyplot as plt mpl.rcParams['axes.titlesize'] = 20 mpl.rcParams['xtick.labelsize'] = 16 mpl.rcParams['ytick.labelsize'] = 16 mpl.rcParams['axes.labelsize'] = 16 mpl.rcParams['xtick.major.size'] = 0 mpl.rcParams['ytick.major.size'] = 0 # 包含了狗,貓和獵豹的最高奔跑速度,還有對應的可視化顏色 speed_map = { 'dog': (48, '#7199cf'), 'cat': (45, '#4fc4aa'), 'cheetah': (120, '#e1a7a2') } # 總體圖的標題 fig = plt.figure('Bar chart & Pie chart') # 在整張圖上加入一個子圖,121的意思是在一個1行2列的子圖中的第一張 ax = fig.add_subplot(121) ax.set_title('Running speed - bar chart') # 生成x軸每一個元素的位置 xticks = np.arange(3) # 定義柱狀圖每一個柱的寬度 bar_width = 0.5 # 動物名稱 animals = speed_map.keys() # 奔跑速度 speeds = [x[0] for x in speed_map.values()] # 對應顏色 colors = [x[1] for x in speed_map.values()] # 畫柱狀圖,橫軸是動物標籤的位置,縱軸是速度,定義柱的寬度,同時設置柱的邊緣爲透明 bars = ax.bar(xticks, speeds, width=bar_width, edgecolor='none') # 設置y軸的標題 ax.set_ylabel('Speed(km/h)') # x軸每一個標籤的具體位置,設置爲每一個柱的中央 ax.set_xticks(xticks+bar_width/2) # 設置每一個標籤的名字 ax.set_xticklabels(animals) # 設置x軸的範圍 ax.set_xlim([bar_width/2-0.5, 3-bar_width/2]) # 設置y軸的範圍 ax.set_ylim([0, 125]) # 給每一個bar分配指定的顏色 for bar, color in zip(bars, colors): bar.set_color(color) # 在122位置加入新的圖 ax = fig.add_subplot(122) ax.set_title('Running speed - pie chart') # 生成同時包含名稱和速度的標籤 labels = ['{}\n{} km/h'.format(animal, speed) for animal, speed in zip(animals, speeds)] # 畫餅狀圖,並指定標籤和對應顏色 ax.pie(speeds, labels=labels, colors=colors) plt.show() 

在這段代碼中又出現了一個新的東西叫作,一個用ax命名的對象。在Matplotlib中,畫圖時有兩個經常使用概念,一個是平時畫圖蹦出的一個窗口,這叫一個figure。Figure至關於一個大的畫布,在每一個figure中,又能夠存在多個子圖,這種子圖叫作axes。顧名思義,有了橫縱軸就是一幅簡單的圖表。在上面代碼中,先把figure定義成了一個一行兩列的大畫布,而後經過fig.add_subplot()加入兩個新的子圖。subplot的定義格式頗有趣,數字的前兩位分別定義行數和列數,最後一位定義新加入子圖的所處順序,固然想寫明確些也沒問題,用逗號分開便可。。上面這段代碼產生的圖像以下:

 

5.3.1 3D圖表

Matplotlib中也能支持一些基礎的3D圖表,好比曲面圖,散點圖和柱狀圖。這些3D圖表須要使用mpl_toolkits模塊,先來看一個簡單的曲面圖的例子:

import matplotlib.pyplot as plt import numpy as np # 3D圖標必須的模塊,project='3d'的定義 from mpl_toolkits.mplot3d import Axes3D np.random.seed(42) n_grids = 51 # x-y平面的格點數 c = n_grids / 2 # 中心位置 nf = 2 # 低頻成分的個數 # 生成格點 x = np.linspace(0, 1, n_grids) y = np.linspace(0, 1, n_grids) # x和y是長度爲n_grids的array # meshgrid會把x和y組合成n_grids*n_grids的array,X和Y對應位置就是全部格點的座標 X, Y = np.meshgrid(x, y) # 生成一個0值的傅里葉譜 spectrum = np.zeros((n_grids, n_grids), dtype=np.complex) # 生成一段噪音,長度是(2*nf+1)**2/2 noise = [np.complex(x, y) for x, y in np.random.uniform(-1,1,((2*nf+1)**2/2, 2))] # 傅里葉頻譜的每一項和其共軛關於中心對稱 noisy_block = np.concatenate((noise, [0j], np.conjugate(noise[::-1]))) # 將生成的頻譜做爲低頻成分 spectrum[c-nf:c+nf+1, c-nf:c+nf+1] = noisy_block.reshape((2*nf+1, 2*nf+1)) # 進行反傅里葉變換 Z = np.real(np.fft.ifft2(np.fft.ifftshift(spectrum))) # 建立圖表 fig = plt.figure('3D surface & wire') # 第一個子圖,surface圖 ax = fig.add_subplot(1, 2, 1, projection='3d') # alpha定義透明度,cmap是color map # rstride和cstride是兩個方向上的採樣,越小越精細,lw是線寬 ax.plot_surface(X, Y, Z, alpha=0.7, cmap='jet', rstride=1, cstride=1, lw=0) # 第二個子圖,網線圖 ax = fig.add_subplot(1, 2, 2, projection='3d') ax.plot_wireframe(X, Y, Z, rstride=3, cstride=3, lw=0.5) plt.show() 

這個例子中先生成一個全部值均爲0的複數array做爲初始頻譜,而後把頻譜中央部分用隨機生成,但同時共軛關於中心對稱的子矩陣進行填充。這至關於只有低頻成分的一個隨機頻譜。最後進行反傅里葉變換就獲得一個隨機波動的曲面,圖像以下:

 

3D的散點圖也是經常用來查看空間樣本分佈的一種手段,而且畫起來比表面圖和網線圖更加簡單,來看例子:

import matplotlib.pyplot as plt import numpy as np from mpl_toolkits.mplot3d import Axes3D np.random.seed(42) # 採樣個數500 n_samples = 500 dim = 3 # 先生成一組3維正態分佈數據,數據方向徹底隨機 samples = np.random.multivariate_normal( np.zeros(dim), np.eye(dim), n_samples ) # 經過把每一個樣本到原點距離和均勻分佈吻合獲得球體內均勻分佈的樣本 for i in range(samples.shape[0]): r = np.power(np.random.random(), 1.0/3.0) samples[i] *= r / np.linalg.norm(samples[i]) upper_samples = [] lower_samples = [] for x, y, z in samples: # 3x+2y-z=1做爲判別平面 if z > 3*x + 2*y - 1: upper_samples.append((x, y, z)) else: lower_samples.append((x, y, z)) fig = plt.figure('3D scatter plot') ax = fig.add_subplot(111, projection='3d') uppers = np.array(upper_samples) lowers = np.array(lower_samples) # 用不一樣顏色不一樣形狀的圖標表示平面上下的樣本 # 判別平面上半部分爲紅色圓點,下半部分爲綠色三角 ax.scatter(uppers[:, 0], uppers[:, 1], uppers[:, 2], c='r', marker='o') ax.scatter(lowers[:, 0], lowers[:, 1], lowers[:, 2], c='g', marker='^') plt.show() 

這個例子中,爲了方便,直接先採樣了一堆3維的正態分佈樣本,保證方向上的均勻性。而後歸一化,讓每一個樣本到原點的距離爲1,至關於獲得了一個均勻分佈在球面上的樣本。再接着把每一個樣本都乘上一個均勻分佈隨機數的開3次方,這樣就獲得了在球體內均勻分佈的樣本,最後根據判別平面3x+2y-z-1=0對平面兩側樣本用不一樣的形狀和顏色畫出,圖像以下:

 

5.3.1 圖像顯示

Matplotlib也支持圖像的存取和顯示,而且和OpenCV一類的接口比起來,對於通常的二維矩陣的可視化要方便不少,來看例子:

import matplotlib.pyplot as plt # 讀取一張小白狗的照片並顯示 plt.figure('A Little White Dog') little_dog_img = plt.imread('little_white_dog.jpg') plt.imshow(little_dog_img) # Z是上小節生成的隨機圖案,img0就是Z,img1是Z作了個簡單的變換 img0 = Z img1 = 3*Z + 4 # cmap指定爲'gray'用來顯示灰度圖 fig = plt.figure('Auto Normalized Visualization') ax0 = fig.add_subplot(121) ax0.imshow(img0, cmap='gray') ax1 = fig.add_subplot(122) ax1.imshow(img1, cmap='gray') plt.show() 

這段代碼中第一個例子是讀取一個本地圖片並顯示,第二個例子中直接把上小節中反傅里葉變換生成的矩陣做爲圖像拿過來,原圖和通過乘以3再加4變換的圖直接繪製了兩個形狀同樣,可是值的範圍不同的圖案。顯示的時候imshow會自動進行歸一化,把最亮的值顯示爲純白,最暗的值顯示爲純黑。這是一種很是方便的設定,尤爲是查看深度學習中某個卷積層的響應圖時。獲得圖像以下:

相關文章
相關標籤/搜索