【python】Numpy基礎:數組與向量化計算

本文所有內容均總結自《利用python進行數據分析》。這本書太無趣了,如果不自己做一點筆記的話,根本讀不下去。於是有了這些文章。

一、Numpy概述

Numpy是目前Python數值計算中最爲重要的基礎包,大多數計算包都提供了基於Numpy的科學函數功能,將Numpy的數組對象作爲數據交換的通用語。簡而言之,Numpy提供的數組太好用了,大家都喜歡。

我們將使用Numpy的以下幾方面功能:

①、ndarry,一種高效的多維數組,提供了基於數組的便攜算數操作以及靈活的廣播功能。

②、對所有數據進行快速的矩陣計算,無需編寫循環程序。

③、對硬盤中的數組數據進行讀寫的工具,並對內存映射文件進行操作。

④、線性代數、隨機數生成以及傅里葉變換。

⑤、用於連接Numpy到C、C++和FORTRAN語言類庫的C語言API。

在naive的我看來,這個Numpy庫就是把一部分的matlab功能移植到python中。

二、Numpy ndarry:多維數組對象

1、ndarray簡介

這是Numpy的核心特徵之一,nd就是n維,array就是數組。

它的第一大特徵就是可以進行對數組整體進行操作。注意不是矩陣操作。因爲數組乘法是對應元素相乘,而不是矩陣乘法。如下:

使用np.random.rand(a,b)可以返回一個a行b列,元素是隨機數的矩陣,目測這個隨機數的範圍是(0,1),保存在data中。

這個data的數據類型就是ndarray。

data*2就是數組中所有元素乘二,data+data就是對應元素相加。相乘用data比較難看出來,所以另外開兩個數組:

看,也是對應的元素相乘。也就是說,對array進行計算,相當於對它的每一個元素分別計算,省去了循環的麻煩。

array既然是多維數組,那麼就需要知道它的維度。使用a.shape就能夠返回a在各個維度上的元素個數啦。比如上面的a,是一個二維數組,shape如下:

這說明a在第一維上有兩個元素,在第二維上有三個元素。shape描繪數組的形狀,“2”行“2”列。返回的元組的元素個數就是維數。對於維度,也可以用ndim來確定。

知道了維數,多維數組還有一個屬性,就是元素的類型。使用a.dtype就可以知道。

2、ndarray生成

生成一個數組主要有以下幾種方法:

np.array(a)
np.zeros(10)
np.ones((2,3))
np.empty((2,3,2))
np.full((2,3),1)

如圖,對於np.array()方法,無論輸入的是元組還是列表,輸出的都是它們元素組成的array。

另外,如果輸入是二維數組,輸出自然也是二維數組。

我們有另外一個函數asarray,它與array的主要區別就在於,當輸入類型是array,對於array函數,它將複製數組中的所有元素,然後返回一個array;對於asarray,它首先判斷輸入是不是array,如果是,就直接返回,如果不是,再複製。

array有一個參數dtype,可以用它指定生成的數組中的元素類型。

下面的zeros、ones、empty的輸入參數就是數組在各個維度上的元素數量,比如說輸入(2,3)那麼zeros就返回一個2行3列元素爲0的數組,ones返回的是元素全爲1的數組,empty返回元素爲空的數組,表現出來也是元素爲0,但是並不安全,有時候會返回垃圾數值,因此要全0的最好還是用zero。

注意輸入的參數不止一個的時候,要把所有參數用元組包起來。

最後一個函數full,其輸入參數有兩個,第一個是一個元組,用於描述輸出數組的形狀,也就是各維度上元素個數;第二個是元素,full會輸出一個元素均是這個輸入的數組。如下:

另外還有函數eye,identity,用於生成一個對角線爲1,其餘元素爲0的數組。

3、ndarray的數據類型

數據類型和C差不多,有int有float,但是int裏面還分幾個小類int8,uint8什麼的。這個可以自己去看。

重要的一點是數據類型的轉換,在C中我們直接在前面加()就可以,但是python沒有數據類型這麼一說,所以需要藉助astype來實現。如下:

將一個字符串列表轉換爲一個數組,要求元素類型爲np.string_,這個類型要求等價於要求類型爲S或S4,即長度爲4的字符串類型,一定要小心使用,因爲python會不告訴你而擅自把列表中的所有元素切到四或四以下。如果我們要求類型爲S2,那麼則會切到只剩兩個字符,這樣就有精度損失了。

我覺得特別厲害的一點是astype可以把字符串格式的數字直接轉成真正的數字,如下:

注意轉換成int8還會報錯,轉換成float就不會,真是聰明。

4、numpy數組算數

之前說過,ndarray的一大優勢在於它可以批量對元素操作而不用循環,這被稱之爲向量化。

有三條原則:

①、等尺寸的數組之間操作爲逐元素操作,就是一一對應。

②、帶有標量計算的算數操作,會把計算參數傳遞給每一個元素。**表示乘方。

③、同尺寸數組間的比較,會生成一個布爾值數組,表明每個元素對應比較的真假。

另外,不同尺寸的數組比較,將會用到廣播特性。

5、基礎索引與切片

這部分的功能實際上就是讓你精確、直白、方便的在一個多維數組中選擇一些數據。

比較反直覺的一點在於,在選擇出這一些數據之後,對這部分數據進行改動會反應在原來的數組上,我們稱選擇的這部分數組是一個“視圖”,而不是原數據的複製。

如圖,arr1是一個數組,arr2是arr1的一個切片,當我更改arr2中的元素,arr1也同步更新。

那問題來了,我要想對數組中某一部分元素進行更改,但不想影響原數組怎麼辦?使用copy函數。

如圖,arr3由555變成了666,但arr1沒變。

接下來有點複雜了。由於數組維數可以比二大,我們想要表達某一個元素或者某幾個元素會變得困難。

比如說一個三維數組arr3d:

這個高維數組,維數越高越難理解。如果非得把它們映射成線啊面啊體啊,就有點難。我現在用這種方法來定位高維數組中的元素:

比如說arr3d[0,1,2],第一個0,表示要在[ 1, 2, 3], [ 4, 5, 6]裏面找,第二個1,表示要在[ 4, 5, 6]裏面找,第三個2,表示找到元素6。要是說第一個0表示0號面,第二個1表示第1行,第三個2表示第2列,這就不好解釋了。

同樣的,我們想選擇[4,5,6]這個一維子數組,我們輸入arr3d[0,1]即可。同理,選擇[ 1, 2, 3], [ 4, 5, 6],輸入arr3d[0]即可。

那我們想要[2,5,8,11]怎麼辦?就是每一個一維子數組的第一個?輸入arr3d[:,:,1]即可。

注意,這裏的2,5,8,11是一個2*2矩陣,而不是一個4*1向量。

想要[2,5,8]呢?這個做不到。因爲這橫跨了兩個二維子數組,而且不是對稱的,沒法一次切片得到。可以兩次切片,第一次2,5,8,11,第二次2,5,8。

想要[2,3,5,6]是可以的,arr3d[:1,1,1:]即可。第一個:1表示“到1之前”,第三個1:表示“從1開始”。

6、布爾索引

布爾索引即是將布爾表達式當做下標,返回對應的數據。原理就是布爾表達式是通過判斷得到的,會返回一個元素爲True或False的數組,根據這個數組,返回元素爲True的部分。

例如,我們現在有一個1*7的人名數組names:

又有一個7*7的隨機數數組rand:

其中每一行對應一個人名,那麼我想選擇名字爲XueChengfei對應的一行該怎麼辦?

使用rand[names=="XueChengfei"]即可。

我們來看看names=='XueChengfei'這一句返回了什麼。

看,返回了一個數組,只有XueChengfei對應的一行爲True,於是可以返回該行數據。那麼要是人名對應的不是行而是列呢?

很簡單,將rand轉置轉即可。

不能將names=='XueChengfei'返回的數組轉置,因爲這個數組是一維的,轉置並不會由1*7變成7*1,它不變。

我們也可以使用多個條件:

注意各個條件要用括號括起來。

或用~,且用&,非用|。

另外特別重要的一點,布爾索引返回的是拷貝,而不是視圖。

7、神奇索引

神奇索引是通過輸入“座標”來選擇原數組中一些元素的方法,相比於基礎索引,它更靈活,但也更復雜。

我們以二維數組爲例:

現在我們想要返回一個數組,由arr的第4,3,0,6行組成,這用基礎索引是無法實現的,但是用神奇索引可以很容易實現:輸入[4,3,0,6]即可。

如果使用負的索引,將從尾部進行選擇。

注意,-1是最後一行。

如果我們輸入多個數組,那麼這多個數組必定長度相同,每個數組對應位置的元素合起來組成一個座標,比如說[3,4,5,6],[1,2,3,1]就意味着我需要第3行第1個,第4行第2個,第5行第3個和第6行第1個。

要想選擇子集呢?比如說我想選擇上面1,2;1,3;4,2;4,3四個元素作爲四個角所形成的矩形中的所有元素,可以輸入[3,4,5,6],1:4。

8、數組轉置和換軸

超過二維數組的轉置就叫換軸,我覺得好難理解,先不用了。二維轉置使用arr.T即可。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章