1. 程式人生 > >手把手教你學Numpy,搞定資料處理——收官篇

手把手教你學Numpy,搞定資料處理——收官篇

本文始發於個人公眾號:**TechFlow**,原創不易,求個關注

今天是Numpy專題第6篇文章,我們一起來看看Numpy庫當中剩餘的部分。

陣列的持久化

在我們做機器學習模型的研究或者是學習的時候,在完成了訓練之後,有時候會希望能夠將相應的引數儲存下來。否則的話,如果是在Notebook當中,當Notebook關閉的時候,這些值就丟失了。一般的解決方案是將我們需要的值或者是陣列“持久化”,通常的做法是儲存在磁碟上。

Python當中讀寫檔案稍稍有些麻煩,我們還需要建立檔案控制代碼,然後一行行寫入,寫入完成之後需要關閉控制代碼。即使是用with語句,也依然不夠簡便。針對這個問題,numpy當中自帶了寫入檔案的api,我們直接呼叫即可。

通過numpy當中save的檔案是二進位制格式的,所以我們是無法讀取其中內容的,即使強行開啟也會是亂碼。

以二進位制的形式儲存資料避免了資料型別轉化的過程,尤其是numpy底層的資料是以C++實現的,如果使用Python的檔案介面的話,勢必要先轉化成Python的格式,這會帶來大量開銷。既然可以儲存,自然也可以讀取,我們可以呼叫numpy的load函式將numpy檔案讀取進來。

要注意我們儲存的時候沒有新增檔案字尾,numpy會自動為我們新增字尾,但是讀取的時候必須要指定檔案的全名,否則會numpy無法找到,會引發報錯。

不僅如此,numpy還支援我們同時儲存多個數組進入一個檔案當中。

我們使用savez來完成,在這個api當中我們傳入了a=arr,b=arr,其實是以類似字典的形式傳入的。在檔案當中,numpy會將變數名和陣列的值對映起來。這樣我們在讀入的時候,就可以通過變數名訪問到對應的值了。

如果要儲存的資料非常大的話,我們還可以對資料進行壓縮,我們只需要更換savez成savez_compressed即可。

線性代數

Numpy除了科學計算之外,另外一大強大的功能就是支援矩陣運算,這也是它廣為流行並且在機器學習當中大受歡迎的原因之一。我們在之前的線性代數的文章當中曾經提到過Numpy這方面的一些應用,我們今天再在這篇文章當中彙總一些常用的線性代數的介面。

點乘

說起來矩陣點乘應該是最常用的線代api了,比如在神經網路當中,如果拋開啟用函式的話,一層神經元對於當前資料的影響,其實等價於特徵矩陣點乘了一個係數矩陣。再比如在邏輯迴歸當中,我們計算樣本的加權和的時候,也是通過矩陣點乘來實現的。

在Andrew的深度學習課上,他曾經做過這樣的實現,對於兩個巨大的矩陣進行矩陣相乘的運算。一次是通過Python的迴圈來實現,一次是通過Numpy的dot函式實現,兩者的時間開銷相差了足足上百倍。這當中的效率差距和Python語言的特性以及併發能力有關,所以在機器學習領域當中,我們總是將樣本向量化或者矩陣化,通過點乘來計算加權求和,或者是係數相乘。

在Numpy當中我們採用dot函式來計算兩個矩陣的點積,既可以寫成a.dot(b),也可以寫成np.dot(a, b)。一般來說我更加喜歡前者,因為寫起來更加方便清晰。如果你喜歡後者也問題不大,這個只是個人喜好。

注意不要寫成*,這個符號代表兩個矩陣元素兩兩相乘,而不是進行點積運算。它等價於np當中的multiply函式。

轉置與逆矩陣

轉置我們曾經在之前的文章當中提到過,可以通過.T或者是np.transpose來完成。

Numpy中還提供了求解逆矩陣的操作,這個函式在numpy的linalg路徑下,這個路徑下實現了許多常用的線性代數函式。根據線性代數當中的知識,只有滿秩的方陣才有逆矩陣。我們可以通過numpy.linalg.det先來計算行列式來判斷,否則如果直接呼叫的話,對於沒有逆矩陣的矩陣會報錯。

在這個例子當中,由於矩陣b的行列式為0,說明它並不是滿秩的,所以我們求它的逆矩陣會報錯。

除了這些函式之外,linalg當中還封裝了其他一些常用的函式。比如進行qr分解的qr函式,進行奇異值分解的svd函式,求解線性方程組的solve函式等。相比之下,這些函式的使用頻率相對不高,所以就不展開一一介紹了,我們可以用到的時候再去詳細研究。

隨機

Numpy當中另外一個常用的領域就是隨機數,我們經常使用Numpy來生成各種各樣的隨機數。這一塊在Numpy當中其實也有很多的api以及很複雜的用法,同樣,我們不過多深入,挑其中比較重要也是經常使用的和大家分享一下。

隨機數的所有函式都在numpy.random這個路徑下,我們為了簡化,就不寫完整的路徑了,大家記住就好。

randn

這個函式我們經常在程式碼當中看到,尤其是我們造資料的時候。它代表的是根據輸入的shape生成一批均值為0,標準差為1的正態分佈的隨機數。

要注意的是,我們傳入的shape不是一個元組,而是每一維的大小,這一點和其他地方的用法不太一樣,需要注意一下。除了正態分佈的randn之外,還有均勻分佈的uniform和Gamma分佈的gamma,卡方分佈的chisquare。

normal

normal其實也是生成正態分佈的樣本值,但不同的是,它支援我們指定樣本的均值和標準差。如果我們想要生成多個樣本,還可以在size引數當中傳入指定的shape。

randint

顧名思義,這個函式是用來生成隨機整數的。它接受傳入隨機數的上下界,最少也要傳入一個上界(預設下界是0)。

如果想要生成多個int,我們可以在size引數傳入一個shape,它會返回一個對應大小的陣列,這一點和uniform用法一樣。

shuffle

shuffle的功能是對一個數組進行亂序,返回亂序之後的結果。一般用在機器學習當中,如果存在樣本聚集的情況,我們一般會使用shuffle進行亂序,避免模型受到樣本分佈的影響。

shuffle是一個inplace的方法,它會在原本值上進行改動,而不會返回一個新值。

choice

這也是一個非常常用的api,它可以在資料當中抽取指定條資料。

但是它只支援一維的陣列,一般用在批量訓練的時候,我們通過choice取樣出樣本的下標,再通過陣列索引去找到這些樣本的值。比如這樣:

總結

今天我們一起研究了Numpy中資料持久化、線性代數、隨機數相關api的使用方法,由於篇幅的限制,我們只是選擇了其中比較常用,或者是比較重要的用法,還存在一些較為冷門的api和用法,大家感興趣的可以自行研究一下,一般來說文章當中提到的用法已經足夠了。

今天這篇是Numpy專題的最後一篇了,如果你堅持看完本專題所有的文章,那麼相信你對於Numpy包一定有了一個深入的理解和認識了,給自己鼓鼓掌吧。之後週四會開啟Pandas專題,敬請期待哦。

如果喜歡本文,可以的話,請點個關注,給我一點鼓勵,也方便獲取更多文章。

本文使用 mdnice 排版

![](https://user-gold-cdn.xitu.io/2020/6/21/172d7455f0020fa4?w=258&h=258&f=png&