給深度學習入門者的Python快速教程 - numpy和Matplotlib篇

本篇部分代碼的下載地址:

github.com/frombeijingw

上篇:給深度學習入門者的Python快速教程 - 基礎篇

5.3 Python的科學計算包 - Numpy

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

numpy在Linux下的安裝已經在5.1.2中作為例子講過,Windows下也可以通過pip,或者到下面網址下載:

Obtaining NumPy & SciPy libraries

5.3.1n基本類型(array)

array,也就是數組,是numpy中最基礎的數據結構,最關鍵的屬性是維度和元素類型,在numpy中,可以非常方便地創建各種不同類型的多維數組,並且執行一些基本基本操作,來看例子:

import numpy as npnna = [1, 2, 3, 4] t#nb = np.array(a) t# array([1, 2, 3, 4])ntype(b) t# <type numpy.ndarray>nnb.shape t# (4,)nb.argmax() t# 3nb.max() t# 4nb.mean() t# 2.5nnc = [[1, 2], [3, 4]] t# 二維列表nd = np.array(c) t# 二維numpy數組nd.shape t# (2, 2)nd.size t# 4nd.max(axis=0) t# 找維度0,也就是最後一個維度上的最大值,array([3, 4])nd.max(axis=1) t# 找維度1,也就是倒數第二個維度上的最大值,array([2, 4])nd.mean(axis=0) t# 找維度0,也就是第一個維度上的均值,array([ 2., 3.])nd.flatten() t# 展開一個numpy數組為1維數組,array([1, 2, 3, 4])nnp.ravel(c) # 展開一個可以解析的結構為1維數組,array([1, 2, 3, 4])nn# 3x3的浮點型2維數組,並且初始化所有元素值為1ne = np.ones((3, 3), dtype=np.float)nn# 創建一個一維數組,元素值是把3重複4次,array([3, 3, 3, 3])nf = np.repeat(3, 4)nn# 2x2x3的無符號8位整型3維數組,並且初始化所有元素值為0ng = np.zeros((2, 2, 3), dtype=np.uint8)ng.shape # (2, 2, 3)nh = g.astype(np.float) # 用另一種類型表示nnl = np.arange(10) t# 類似range,array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])nm = np.linspace(0, 6, 5)# 等差數列,0到6之間5個取值,array([ 0., 1.5, 3., 4.5, 6.])nnp = np.array(n [[1, 2, 3, 4],n [5, 6, 7, 8]]n)nnnp.save(p.npy, p) # 保存到文件nq = np.load(p.npy) # 從文件讀取n

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

import numpy as npnnnarray([[[ 0, 1, 2, 3],n [ 4, 5, 6, 7],n [ 8, 9, 10, 11]],nn [[12, 13, 14, 15],n [16, 17, 18, 19],n [20, 21, 22, 23]]])nna = np.arange(24).reshape((2, 3, 4))nb = a[1][1][1] # 17nnnarray([[ 8, 9, 10, 11],n [20, 21, 22, 23]])nnc = a[:, 2, :]nn 用:表示當前維度上所有下標narray([[ 1, 5, 9],n [13, 17, 21]])nnd = a[:, :, 1]nn 用...表示沒有明確指出的維度narray([[ 1, 5, 9],n [13, 17, 21]])nne = a[..., 1]nnnarray([[[ 5, 6],n [ 9, 10]],nn [[17, 18],n [21, 22]]])nnf = a[:, 1:, 1:-1]nnn平均分成3份n[array([0, 1, 2]), array([3, 4, 5]), array([6, 7, 8])]nng = np.split(np.arange(9), 3)nnn按照下標位置進行劃分n[array([0, 1]), array([2, 3, 4, 5]), array([6, 7, 8])]nnh = np.split(np.arange(9), [2, -3])nnl0 = np.arange(6).reshape((2, 3))nl1 = np.arange(6, 12).reshape((2, 3))nnnvstack是指沿著縱軸拼接兩個array,verticalnhstack是指沿著橫軸拼接兩個array,horizontaln更廣義的拼接用concatenate實現,horizontal後的兩句依次等效於vstack和hstacknstack不是拼接而是在輸入array的基礎上增加一個新的維度nnm = np.vstack((l0, l1))np = np.hstack((l0, l1))nq = np.concatenate((l0, l1))nr = np.concatenate((l0, l1), axis=-1)ns = np.stack((l0, l1))nnn按指定軸進行轉置narray([[[ 0, 3],n [ 6, 9]],nn [[ 1, 4],n [ 7, 10]],nn [[ 2, 5],n [ 8, 11]]])nnt = s.transpose((2, 0, 1))nnn默認轉置將維度倒序,對於2維就是橫縱軸互換narray([[ 0, 4, 8],n [ 1, 5, 9],n [ 2, 6, 10],n [ 3, 7, 11]])nnu = a[0].transpose()t# 或者u=a[0].T也是獲得轉置nnn逆時針旋轉90度,第二個參數是旋轉次數narray([[ 3, 2, 1, 0],n [ 7, 6, 5, 4],n [11, 10, 9, 8]])nnv = np.rot90(u, 3)nnn沿縱軸左右翻轉narray([[ 8, 4, 0],n [ 9, 5, 1],n [10, 6, 2],n [11, 7, 3]])nnw = np.fliplr(u)nnn沿水平軸上下翻轉narray([[ 3, 7, 11],n [ 2, 6, 10],n [ 1, 5, 9],n [ 0, 4, 8]])nnx = np.flipud(u)nnn按照一維順序滾動位移narray([[11, 0, 4],n [ 8, 1, 5],n [ 9, 2, 6],n [10, 3, 7]])nny = np.roll(u, 1)nnn按照指定軸滾動位移narray([[ 8, 0, 4],n [ 9, 1, 5],n [10, 2, 6],n [11, 3, 7]])nnz = np.roll(u, 1, axis=1)n

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

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

import numpy as npnn# 絕對值,1na = np.abs(-1)nn# sin函數,1.0nb = np.sin(np.pi/2)nn# tanh逆函數,0.50000107157840523nc = np.arctanh(0.462118)nn# e為底的指數函數,20.085536923187668nd = np.exp(3)nn# 2的3次方,8nf = np.power(2, 3)nn# 點積,1*3+2*4=11ng = np.dot([1, 2], [3, 4])nn# 開方,5nh = np.sqrt(25)nn# 求和,10nl = np.sum([1, 2, 3, 4])nn# 平均值,5.5nm = np.mean([4, 5, 6, 7])nn# 標準差,0.96824583655185426np = np.std([1, 2, 3, 2, 1, 3, 2, 0])n

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

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

5.3.2n線性代數模塊(linalg)

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

import numpy as npnna = np.array([3, 4])nnp.linalg.norm(a)nnb = np.array([n [1, 2, 3],n [4, 5, 6],n [7, 8, 9]n])nc = np.array([1, 0, 1])nn# 矩陣和向量之間的乘法nnp.dot(b, c) tt# array([ 4, 10, 16])nnp.dot(c, b.T) tt# array([ 4, 10, 16])nnnp.trace(b) tt# 求矩陣的跡,15nnp.linalg.det(b) tt# 求矩陣的行列式值,0nnp.linalg.matrix_rank(b)t# 求矩陣的秩,2,不滿秩,因為行與行之間等差nnd = np.array([n [2, 1],n [1, 2]n])nnn對正定矩陣求本徵值和本徵向量n本徵值為u,array([ 3., 1.])n本徵向量構成的二維array為v,narray([[ 0.70710678, -0.70710678],n [ 0.70710678, 0.70710678]])n是沿著45°方向neig()是一般情況的本徵值分解,對於更常見的對稱實數矩陣,neigh()更快且更穩定,不過輸出的值的順序和eig()是相反的nnu, v = np.linalg.eig(d)nn# Cholesky分解並重建nl = np.linalg.cholesky(d)nnnarray([[ 2., 1.],n [ 1., 2.]])nnnp.dot(l, l.T)nne = np.array([n [1, 2],n [3, 4]n])nn# 對不鎮定矩陣,進行SVD分解並重建nU, s, V = np.linalg.svd(e)nnS = np.array([n [s[0], 0],n [0, s[1]]n])nnnarray([[ 1., 2.],n [ 3., 4.]])nnnp.dot(U, np.dot(S, V))n

5.3.3n隨機模塊(random)

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

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

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

這個問題的答案是應該改變一開始的選擇。在第一次選擇的時候,選錯的概率是2/3,選對的概率是1/3。第一次選擇之後,主持人相當於幫忙剔除了一個錯誤答案,所以如果一開始選的是錯的,這時候換掉就選對了;而如果一開始就選對,則這時候換掉就錯了。根據以上,一開始選錯的概率就是換掉之後選對的概率(2/3),這個概率大於一開始就選對的概率(1/3),所以應該換。雖然道理上是這樣,但是還是有些繞,要是通過推理就是搞不明白怎麼辦,沒關係,用隨機模擬就可以輕鬆得到答案:

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

5.4 Python的可視化包 –nMatplotlib

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

安裝Matplotlib的方式和numpy很像,可以直接通過Unix/Linux的軟體管理工具,比如Ubuntu 16.04 LTS下,輸入:

>>n sudo apt install python-matplotlib

或者通過pip安裝:

>> pip install matplotlib

Windows下也可以通過pip,或是到官網下載:

python plotting - Matplotlib 1.5.3 documentation

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

5.4.1n2D圖表

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

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

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

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

pyplot - Matplotlib 1.5.3 documentation

Customizing matplotlib

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

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

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

5.3.1n3D圖表

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

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

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

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

import matplotlib.pyplot as pltnimport numpy as npnnfrom mpl_toolkits.mplot3d import Axes3Dnnnp.random.seed(42)nn# 採樣個數500nn_samples = 500ndim = 3nn# 先生成一組3維正態分布數據,數據方向完全隨機nsamples = np.random.multivariate_normal(n np.zeros(dim),n np.eye(dim),n n_samplesn)nn# 通過把每個樣本到原點距離和均勻分布吻合得到球體內均勻分布的樣本nfor i in range(samples.shape[0]):n r = np.power(np.random.random(), 1.0/3.0)n samples[i] *= r / np.linalg.norm(samples[i])nnupper_samples = []nlower_samples = []nnfor x, y, z in samples:n # 3x+2y-z=1作為判別平面n if z > 3*x + 2*y - 1:n upper_samples.append((x, y, z))n else:n lower_samples.append((x, y, z))nnfig = plt.figure(3D scatter plot)nax = fig.add_subplot(111, projection=3d)nnuppers = np.array(upper_samples)nlowers = np.array(lower_samples)nn# 用不同顏色不同形狀的圖標表示平面上下的樣本n# 判別平面上半部分為紅色圓點,下半部分為綠色三角nax.scatter(uppers[:, 0], uppers[:, 1], uppers[:, 2], c=r, marker=o)nax.scatter(lowers[:, 0], lowers[:, 1], lowers[:, 2], c=g, marker=^)nnplt.show()n

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

5.3.1n圖像顯示

nnMatplotlib也支持圖像的存取和顯示,並且和OpenCV一類的介面比起來,對於一般的二維矩陣的可視化要方便很多,來看例子:

import matplotlib.pyplot as pltnn# 讀取一張小白狗的照片並顯示nplt.figure(A Little White Dog)nlittle_dog_img = plt.imread(little_white_dog.jpg)nplt.imshow(little_dog_img)nn# Z是上小節生成的隨機圖案,img0就是Z,img1是Z做了個簡單的變換nimg0 = Znimg1 = 3*Z + 4nn# cmap指定為gray用來顯示灰度圖nfig = plt.figure(Auto Normalized Visualization)nax0 = fig.add_subplot(121)nax0.imshow(img0, cmap=gray)nnax1 = fig.add_subplot(122)nax1.imshow(img1, cmap=gray)nnplt.show()n

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

只講到了最基本和常用的圖表及最簡單的例子,更多有趣精美的例子可以在Matplotlib的官網找到:

Thumbnail gallery - Matplotlib 1.5.3 documentation

上篇:給深度學習入門者的Python快速教程 - 基礎篇


推薦閱讀:

利用數組進行數據進行處理
np ufunc: reduce, accumulate, at; np.add, multiply, sum
數組數據類型轉換及算術運算
Python C Extesion (pyd)
復盤:隨機漫步

TAG:numpy | Matplotlib | Python入门 |