Python數據分析之numpy數組全解析

1 什麼是numpy

numpy是一個在Python中作科學計算的基礎庫,重在數值計算,也是大部分Python科學計算庫的基礎庫,多用於大型、多維數據上執行數值計算。數組

在NumPy 中,最重要的對象是稱爲 ndarray 的N維數組類型,它是描述相同類型的元素集合,numpy全部功能幾乎都以ndarray爲核心展開。ndarray 中的每一個元素都是數據類型對象(dtype)的對象。ndarray 中的每一個元素在內存中使用相同大小的塊less

2 numpy數組建立

建立Numpy數組通常有三種方法:dom

(1)經過傳入可待跌對象建立,我將之稱爲基本方法函數

(2)使用Numpy內部功能函數,內部方法spa

(3)使用特殊的庫函數,特殊方法code

2.1 基本方法:np.array()

基本方法是經過給numpy提供的一些函數中傳入可迭代對象來建立數組,這種方法一般是在已知全部元素的狀況下使用。numpy中實現這種功能的函數包括:np.array()、np.arange()、np.line(),:orm

>>> np.array([0, 1, 2, 3, 4]) # 接收一個list做爲參數
array([0, 1, 2, 3, 4])
>>> np.array([[11, 12, 13],[21, 22, 23]]) # 建立一個2*3的數組
array([[11, 12, 13],
[21, 22, 23]])
>>> np.array((0, 1, 2, 3, 4)) # 接收一個tuple做爲參數
array([0, 1, 2, 3, 4])
np.array()方法能夠在建立數組的同時指定數據類型:
>>> np.array([0, 1, 2, 3, 4], dtype=float)
array([0., 1., 2., 3., 4.])

甚至還能夠接受range()返回的可迭代對象做爲參數:對象

>>> np.array(range(5))
array([0, 1, 2, 3, 4])
>>> np.array(range(10, 20, 2))
array([10, 12, 14, 16, 18])

2.2 通用方法:np.ones()、np.zeros()、np.eye()

通用方法指的是numpy中提供的arange()、ones()、zeros()、eye()、full()等方法,這些方法能夠按照某種規則生成一個數組,並不須要傳入已知的可迭代對象。blog

(1)np.arange()索引

上面咱們將range()函數結果傳遞給np.array(),np.arange()實現的就是這個功能,因此說,np.arange()就是numpy中的range()方法。

>>> np.arange(5)
array([0, 1, 2, 3, 4])
>>> np.arange(10, 20, 2)
array([10, 12, 14, 16, 18])

(2)np.linspace()

np.linspace()方法以等間距的形式對給定的兩數進行劃分來建立數組:

>>> np.linspace(10, 20, 5) # 將10到20間的數等距取5個
array([10. , 12.5, 15. , 17.5, 20. ])

(3)np.ones()

建立一個元素值全爲1的數組,接收一個list或者tuple做爲參數

>>> np.ones([2]) # 建立一個一維數組
array([1., 1.])
>>> np.ones([2, 2]) # 建立一個2維數組
array([[1., 1.],
[1., 1.]])
>>> np.ones([2, 2, 2])
array([[[1., 1.],
[1., 1.]],
 
[[1., 1.],
[1., 1.]]])

(4)np.zeros()

建立一個元素值全爲0的數組,接收一個list或者tuple做爲參數

>>> np.zeros([3])
array([0., 0., 0.])
>>> np.zeros([3, 3])
array([[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]])

(5)np.random.random()

建立一個元素爲0到1之間隨機數的數組,接收一個list或者tuple做爲參數:

>>> np.random.random((3, 3))
array([[0.19414645, 0.2306415 , 0.08072019],
[0.68814308, 0.48019088, 0.61438206],
[0.5361477 , 0.33779769, 0.38549407]])

既然有random()方法,那麼就會有randint()方法,也就是取隨機整數的方法,不過這個randint()方法參數形式更random()不太同樣,具體請看下面實例:

>>> np.random.randint(1, 10, 3) # 從1到10之間隨機取3個整數建立數組
array([6, 4, 6])

(6)np.eye()

建立一個從左上角到右下角的對角線上全爲1,其他元素全爲0的數組(單位矩陣)。注意,np.eye()的參數可再也不是list或者tuple了。

>>> np.eye(3, 3)
array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])

(7) np.full()

np.full()函數能夠建立一個填充給定數值的數組,第一個參數是定義數組形狀的list或tuple,第2個參數是須要填充的數值:

>>> np.full((2, 3), 3) # 建立一個2*3的數組,全部元素都填充3
array([[3, 3, 3],
[3, 3, 3]])

2.3 讀取外部數據

numpy也支持從外部讀取數據來建立數組,例如從硬盤中讀取csv、txt等文件來建立數組。np.genfromtxt()是numpy中讀取文件的一個方法,例如在當前目錄下有一個data.csv文件,文件內容爲:

id,height,length

1,100,101

2,200,230

3,300,350

經過numpy讀取:

>>> np.genfromtxt('data.csv',delimiter=',',skip_header=1)
array([[ 1., 100., 101.],
[ 2., 200., 230.],
[ 3., 300., 350.]])

讀取外部數據的方法不止np.genfromtxt(),還有np.load(等,但numpy讀取外部數據的應用狀況其實並很少,這裏再也不細說。

 3 numpy中數組的數據類型

做爲一個強大的科學計算庫,numpy中支持的數據類型遠不止Python原生的幾種數據類型。以下所示爲numpy中支持的數據類型:

數據類型
描述
bool_
布爾(True或False),存儲爲一個字節
int_
默認整數類型(與Clong相同;一般是int64int32
INTC
與Cint(一般爲int32int64)相同
INTP
用於索引的整數(與Cssize_t相同;一般是int32int64
INT8
字節(-128至127)
INT16
整數(-32768至32767)
INT32
整數(-2147483648至2147483647)
Int64的
整數(-9223372036854775808至9223372036854775807)
UINT8
無符號整數(0到255)
UINT16
無符號整數(0到65535)
UINT32
無符號整數(0到4294967295)
UINT64
無符號整數(0到18446744073709551615)
float_
float64的簡寫。
float16
半精度浮點:符號位,5位指數,10位尾數
FLOAT32
單精度浮點數:符號位,8位指數,23位尾數
float64
雙精度浮點:符號位,11位指數,52位尾數
complex_
complex128的簡寫。
complex64
複數,由兩個32位浮點數(實部和虛部)
complex128
複數,由兩個64位浮點數(實部和虛部)

這些數據類型能夠經過如np.bool_、np.float16等形式來調用,上文中提到過,建立數組時能夠指定數據類型:

>>> a = np.array([0, 1, 0, 1], dtype=np.bool_)
>>> a
array([False, True, False, True])

能夠經過numpy數組自帶的dtype屬性來查看數組的數據類型:

>>> a.dtype
dtype('bool')

爲何輸出的類型是bool而不是bool_呢?由於numpy中後綴帶下劃線「_」的數據類型指向的就是Python原生的數據類型,也就是說,np.bool_與Python中的bool數據類型等效,np.float_與Python中的float類型等效。

當一個數組已經被建立,可是想要改變其數據類型,那就能夠經過np.asdtype()方法:

>>> a.astype(np.int)
array([0, 1, 0, 1])
>>> a = np.random.random((2,2))
>>> a
array([[0.02914317, 0.645534 ],
[0.61839509, 0.64155607]])
>>> a.dtype
dtype('float64')
>>> a.astype(np.float16)
array([[0.02914, 0.6455 ],
[0.618 , 0.6416 ]], dtype=float16)
>>> a.dtype
dtype('float64')

4 numpy中數組的形狀

numpy中數組使用與存放多維數據,因此,所謂數組的形狀指的就是數據的維度大小,以及每一維度元素個數。咱們能夠經過數組自帶的shape屬性來查看形狀信息:

>>> a = np.array([[2, 3, 4], [5, 6, 7]])
>>> a
array([[2, 3, 4],
[5, 6, 7]])
>>> a.shape # 查看形狀屬性
(2, 3)

能夠看到,查看形狀屬性時返回的是一個元組,元素的長度表明數組的維度,元組每個屬性表明對應的維度的元素個數,(2,3)就表示第一個維度元素個數是2(兩行),第二個維度長度是3(3列)。

在數組建立以後,數組的形狀也是能夠改變的。改變數組的形狀經過數組的reshape()方法:

>>> a = np.ones((2, 12))
>>> a
array([[1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.]])
>>> a.shape
(2, 12)
>>> b = a.reshape(2, 3, 4)
>>> b
array([[[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]],
 
[[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]]])
>>> b.shape
(2, 3, 4)
>>> b = a.reshape((2,3,4)) # 元組做爲參數
>>> b
array([[[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]],
 
[[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]]])
>>> b.shape
(2, 3, 4)

能夠看到,np.reshape()方法能夠同時傳入多個描述形狀的數字,也能夠傳入一個數組,固然,若是將形狀改變爲一維數組時,必須傳入的是元組。另外須要注意,傳入reshape方法的多個參數的乘積必須與改變前數組總長度相等,不然會報錯。

numpy數組中專門提供了一個方法加你個數組轉換爲覺得數組,那就是flatten()方法,這個方法在執行數組運算是很是有用:

>>> a = np.ones((2, 3))
>>> b = a.flatten()
>>> b
array([1., 1., 1., 1., 1., 1.])
>>> b.shape
(6,)

5 索引與切片

對數據使用時,不可避免要進行索引和切片,numpy在這一方面不可謂不強大。numpy數組中全部的索引都是從0開始的,咱們能夠根據索引來精確取數據。

5.1 按索引取值

下面全部實例都已下方數組a來展開:

>>> a = np.arange(36).reshape((4, 9))
>>> a
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, 24, 25, 26],
[27, 28, 29, 30, 31, 32, 33, 34, 35]])

(1)取一行

>>> a[1] # 取第二行數據
array([ 9, 10, 11, 12, 13, 14, 15, 16, 17])

(2)取連續多行數據

>>> a[:2] # 取前兩行數據
array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8],
[ 9, 10, 11, 12, 13, 14, 15, 16, 17]])

也能夠加上步長:

>>> a[::2] # 每隔一行取一次
array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8],
[18, 19, 20, 21, 22, 23, 24, 25, 26]])
>>> a[1:] # 取第2行後面全部行
array([[ 9, 10, 11, 12, 13, 14, 15, 16, 17],
[18, 19, 20, 21, 22, 23, 24, 25, 26],
[27, 28, 29, 30, 31, 32, 33, 34, 35]])

(3)取不連續多行數據

>>> a[[0,-1]] # 取第一行和最後一行
>>> a[[0,-1]]
array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8],
[27, 28, 29, 30, 31, 32, 33, 34, 35]])

能夠看到,對numpy根據索引進行取值的方法與Python中list索引取值方法相似,都是經過方括號裏面傳入索引取值,當須要對多維進行索引時,每一位數據之間用逗號隔開。

(4)取一列

>>> a[:,1] # 取第2列
array([ 1, 10, 19, 28])

(5)取連續多列

>>> a[:,1:3] # 取第2列到第3列
array([[ 1, 2],
[10, 11],
[19, 20],
[28, 29]])

(6)取不連續多列

>>> a[:,[0,3]] # 取第1列和第4列
array([[ 0, 3],
[ 9, 12],
[18, 21],
[27, 30]]))

(7)取連續多行多列

>>> a[1:3:,1:3] # 取第二、3行中的第二、3列
array([[10, 11],
[19, 20]])

(8)取多個不連續位置數據

看到這裏你應該也明白了取行、取列的規律了,若是取不連續的多行多列呢?例如取第一、3行與第二、4列,你可能認爲是a[[0, 2], [1, 3]],咱們來看看:

>>> a[[0, 2], [1, 3]]
array([ 1, 21])

可見,返回的並非預期的數據,而是第1行第2列、第3行第4列的數據,也就是(0,1)和(2,3)位置的數據。

從而咱們能夠得出結論,若是取第3行中第3列、第5列,第4行中第1列、第7列數據方法以下:

>>> a[[2,2,3,3],[2,4,0,6]] # 第3行中第3列、第5列,第4行中第1列、第7列數據
array([20, 22, 27, 33])

(9)取單個數據

>>> b = a[3,3]
>>> b
30
>>> type(b) # 取單個類型是返回的就是一個確切的numpy類型數值
<class 'numpy.int64'>

5.2 bool索引

(1)bool索引取值

numpy中提供了一些通用函數來實現經過bool條件判斷實現按條件取值,使用這些通用方法,與使用對應的符號時等效的,符號與numpy通用方法對應關係以下:

運算符 對應的通用函數
== np.equal
!= np.not_equal
< np.less
<= np.less_equal
> np.greater
>= np.greater_equal

咱們經過實例感覺一下:

>>> a = np.arange(24).reshape((4,6))
>>> a
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]])
>>> b = a<5 # bool索引選取
>>> b
array([[ True, True, True, True, True, False],
[False, False, False, False, False, False],
[False, False, False, False, False, False],
[False, False, False, False, False, False]])

能夠看到,在元素值小於5的位置上值爲True,不知足條件的爲False。

也可使用通用函數實現:

>>> b = np.less(a,5) # 通用函數選取
>>> b
array([[ True, True, True, True, True, False],
[False, False, False, False, False, False],
[False, False, False, False, False, False],
[False, False, False, False, False, False]])

對bool索引選取出來的結果全是True或者False,可能不是你想要的,能夠進一步使用:

>>> a[b]
array([0, 1, 2, 3, 4])

因此咱們能夠直接刷選值:

>>> a[a<5]
array([0, 1, 2, 3, 4])

(2)三目元算

numpy中提供了一個where()方法來實現三目運算。where()方法接受三個參數,第一個參數是判斷條件,第二個參數時時判斷條件爲真時數組中知足條件的元素將要替換的值,第三個參數是判斷調價爲假時不知足條件元素將要替換的值。

例如,將數組中全部知足元素值小於5的數值替換爲0,不知足的元素值替換爲1:

>>> a = np.arange(24).reshape((4,6))
>>> a
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]])
>>> np.where(a<5, 0, 1) # 三目運算
array([[0, 0, 0, 0, 0, 1],
[1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1]])

6 numpy中賦值、視圖、深複製

(1)賦值

當對numpy數組進行賦值時,只是對同一個對象新建了一個引用,並非創建新的對象,因此賦值先後的變量徹底是同一對象,對其中一個引用修改時,全部引用都會生效:

>>> a = np.arange(12)
>>> b = a # 賦值
>>> a is b
True
>>> b.shape = (3, 4)
>>> b
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
>>> a
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])

(2)視圖(切片、淺複製)

numpy中容許不一樣數組間共享數據,這種機制在numpy中稱爲視圖,對numpy數組的切片和淺複製都是經過視圖實現的。若是數組B是數組A的視圖(view),則稱A爲B的base(除非A也是視圖)。視圖數組中的數據實際上保存在base數組中。

>>> a = np.arange(12)
>>> b = a.view() # 使用視圖
>>> a is b
False
>>> b
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
>>> b.shape = (3, 4) # 改變b的形狀
>>> a
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
>>> b
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
>>> b[0] = 0
>>> a
array([ 0, 0, 0, 0, 4, 5, 6, 7, 8, 9, 10, 11])
>>> b
array([[ 0, 0, 0, 0],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])

從上面代碼中咱們能夠發現,a和b是不一樣的兩個數組,改變b的形狀對a不會有影響,可是改變b的數據以後,a的數據也會發現改變,說明a與b是共享數據的。

 再來探索一些切片:

>>> a = np.arange(12)
>>> b = a[:] # 切片
>>> a is b
False
>>> b.shape = (3, 4)
>>> a
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
>>> b
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
>>> b[0] = 0
>>> a
array([ 0, 0, 0, 0, 4, 5, 6, 7, 8, 9, 10, 11])
>>> b
array([[ 0, 0, 0, 0],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])

果真,切片效果與視圖一致。

(3)深複製

深複製經過數組自帶的copy()方法實現,深複製產生的數組與原數組時徹底不一樣的兩個數組對象,徹底享有獨立的內存空間,全部操做都不會相互影響。

>>> a = np.arange(12)
>>> b = a.copy()
>>> a is b
False
>>> b.shape = (3, 4)
>>> b[0] = 0
>>> a
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
>>> b
array([[ 0, 0, 0, 0],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
相關文章
相關標籤/搜索