1. 程式人生 > >Python資料處理 | (一)Numpy入門

Python資料處理 | (一)Numpy入門

本篇部落格所有示例使用Jupyter NoteBook演示。

示例程式碼下載:

一、NumPy簡介

本篇部落格將詳細的介紹NumPy。NumPy(Numerical Python)提供了 高效儲存和操作密集資料快取的介面。在某些方面,NumPy陣列與Python內建的列表型別非常相似。但是隨著陣列在維度上變大,NumPy陣列提供了更加高效的儲存和資料操作。NumPy陣列幾乎是整個Python資料科學工具生態系統的核心。因此,不管你對資料科學哪個方面感興趣,花點時間學習NumPy是值得的。

二、理解python中的資料型別

Python的易用性在於動態輸入。靜態型別的語言如C、Java,每一個變數都要明確的宣告他的型別,而動態語言Python不需要。例如用c和python分別實現100內的累加:

C:

int result = 0;
for(int i=0;i<100;i++)
{
result += i;
}

Python:

result = 0
for i in range(100):
    result += i

最大的不同在於,c語言中,每個變數的資料型別要被明確的宣告;而python中型別是動態推斷的,可以將任何型別的資料賦給任何變數:

x = 4
x = 'four'

但是這樣在C中,就會報錯:

int x = 4;
x = "four";  //編譯失敗

Python的這種靈活性指出了一個事實:Python變數不僅是它的值,還包含了關於值的型別的一些額外的資訊。

1.Python整型不僅僅是一個整型

標準的Python實現使用c語言編寫的。這就意味了每一個Python物件都是一個偽C語言結構體,該結構體不僅包含其值,還有其他資訊。

例如,我們在Python中定義一個整型:x=1000,x並不是一個“原生”整型,而是一個指標,指向一個C語言的複合結構體,裡面包含了一些值。

檢視Python3原始碼,可以發現整型的定義包含四部分,如下所示:

  • ob_refcnt是一個引用計數,幫助Python處理記憶體的分配和回收
  • ob_type將變數的型別編碼
  • ob_size指定接下來資料成員的大小
  • ob_digit包含我們希望Python變量表示的實際整型值

這意味著與C語言這樣的編譯語言中的整型相比,python中儲存一個整型會有一些開銷,如下圖所示:

Python中儲存整數1不僅要儲存其值,還要儲存型別等其他資訊(這裡的PyObject_HEAD是結構體中包含引用計數、型別編碼和其他之前提到的內容)。

C整型和Python整型的區別:

C語言整型本質上對應某個記憶體位置的標籤,裡面儲存的位元組會編碼成整型。而Python整型其實是一個指標,指向包含這個Python物件所有資訊的某個記憶體位置,其中包括可以轉換成整型的位元組。由於Python的整型結構體裡面包含了大量額外資訊,所以Python可以自由、動態的編碼。但是,Python型別中的額外資訊也會成為負擔,在多個物件組合的結構體中尤其明顯。

2.Python列表不僅僅是一個列表

在之前的部落格中我們曾經學習過Python列表型別,忘記的可以複習一下:列表簡介操作列表

  • 整型列表:

  • 字串列表:

  • 因為Python的動態型別特性,可以建立一個異構的列表 

但是Python的這種靈活性是要付出代價的,為了獲取靈活的型別,列表中的每一項必須包含各自的型別資訊,引用計數和其他資訊,每一項都是一個完整的Python物件。那麼如果列表中的所有變數都是同一型別,這時很多資訊都是多餘的。因此,將資料儲存在固定型別的陣列中會更高效。

動態型別的列表和固定型別的陣列(NumPy)的區別:

實現層面,陣列基本上包含一個指向連續資料塊的指標。Python列表包含一個指向指標塊的指標,其中的每一個指標對應一個完整的Python物件(前面看到的Python整型結構)。另外,列表優勢是靈活,每個列表元素是一個包含資料和型別資訊的完整結構體,因此列表可以用任意型別的資料填充。固定型別的NumPy陣列缺乏這種靈活性,但能更有效的儲存和操作資料。

NumPy陣列相當於C語言中的列表。

3.Python中的固定型別陣列

內建的陣列(array)模組可以用於建立統一型別的密集陣列:

這裡的‘i’是一個數據型別碼,表示資料為整型。

更實用的是NumPy包中的ndarray物件。Python的陣列物件提供了陣列型資料的有效儲存,而Numpy為該資料加上了高效的操作,之後會介紹。

4.從Python列表建立陣列

使用np.array().

注意,不同於Python列表,NumPy要求陣列必須包含同一型別的資料。如果型別不同,會自動向上轉換(可行的話).

比如:整型轉浮點型

如果希望明確設定陣列的資料型別,可用dtype:

不同於Python列表,NumPy陣列可以是多維的,用巢狀列表初始化多維陣列:

內層列表當作二維陣列的行。

5.從頭建立陣列

面對大型陣列時,用Numpy內建的方法建立陣列更高效。

6.NumPy標準資料型別

Numpy陣列包含同一型別的值,Numpy是基於c語言開發的。

建立陣列時可以用一個字串指定資料型別,或者用相關Numpy物件指定:

NumPy標準資料型別:

三、NumPy陣列基礎

1.NumPy陣列屬性

定義三個隨機陣列,分別是1維,2維和3維:

2.陣列索引:獲取單個元素

陣列的索引和Python列表一樣,都是用[]指定索引來獲取(從0開始):

多維陣列中用,分隔的元組作為索引(從0開始):

也可以通過索引來修改陣列的值:

注意:Numpy中元素型別是一樣的,如果你把一個浮點數插入整型陣列,浮點數會自動截斷,且不報錯

3.陣列切片:獲取子陣列

陣列切片的語法與Python列表切片一樣,切片用:表示。

語法:

x[start:stop:step]

開始索引:結束索引(不包括):步長,start預設為0,stop預設為陣列大小,step預設為1

  • 一維子陣列

步長可以為負數,start和stop引數此時預設為交換的,是一種逆序陣列的方法:

  • 多維子陣列

  • 獲取陣列的行和列

獲取陣列的單行或單列,可以將索引和切片結合來實現,:表示空切片

  • 非副本檢視的子陣列

陣列切片時原陣列的檢視,也就是說切片改變了,原始陣列對應位置也改變;和Python列表不一樣,列表切片是列表的一個副本,二者沒關係。

這種預設處理方式很有用:在處理大資料集時,可以獲取或處理資料集的切片,來完成對大資料集的處理,不用複製底層的資料快取。

  • 建立陣列副本

4.陣列的變型

5.陣列的拼接和分裂

  • 陣列的拼接

  • 陣列的分裂