Numpy是一個(gè)開(kāi)源的Python科學(xué)計(jì)算庫(kù),它是python科學(xué)計(jì)算庫(kù)的基礎(chǔ)庫(kù),許多其他著名的科學(xué)計(jì)算庫(kù)如Pandas,Scikit-learn等都要用到Numpy庫(kù)的一些功能。
本文主要內(nèi)容如下:
Numpy數(shù)組對(duì)象
創(chuàng)建ndarray數(shù)組
Numpy的數(shù)值類(lèi)型
ndarray數(shù)組的屬性
ndarray數(shù)組的切片和索引
處理數(shù)組形狀
數(shù)組的類(lèi)型轉(zhuǎn)換
numpy常用統(tǒng)計(jì)函數(shù)
數(shù)組的廣播
1 Numpy數(shù)組對(duì)象
Numpy中的多維數(shù)組稱(chēng)為ndarray,這是Numpy中最常見(jiàn)的數(shù)組對(duì)象。ndarray對(duì)象通常包含兩個(gè)部分:
ndarray數(shù)據(jù)本身
描述數(shù)據(jù)的元數(shù)據(jù)
Numpy數(shù)組的優(yōu)勢(shì)
Numpy數(shù)組通常是由相同種類(lèi)的元素組成的,即數(shù)組中的數(shù)據(jù)項(xiàng)的類(lèi)型一致。這樣有一個(gè)好處,由于知道數(shù)組元素的類(lèi)型相同,所以能快速確定存儲(chǔ)數(shù)據(jù)所需空間的大小。
Numpy數(shù)組能夠運(yùn)用向量化運(yùn)算來(lái)處理整個(gè)數(shù)組,速度較快;而Python的列表則通常需要借助循環(huán)語(yǔ)句遍歷列表,運(yùn)行效率相對(duì)來(lái)說(shuō)要差。
Numpy使用了優(yōu)化過(guò)的C API,運(yùn)算速度較快
關(guān)于向量化和標(biāo)量化運(yùn)算,對(duì)比下面的參考例子就可以看出差異
使用python的list進(jìn)行循環(huán)遍歷運(yùn)算
def pySum(): a = list(range(10000)) b = list(range(10000)) c = [] for i in range(len(a)): c.append(a[i]**2 + b[i]**2) return c
%timeit pySum()
10 loops, best of 3: 49.4 ms per loop
使用numpy進(jìn)行向量化運(yùn)算
import numpy as npdef npSum(): a = np.arange(10000) b = np.arange(10000) c = a**2 + b**2 return c
%timeit npSum()
The slowest run took 262.56 times longer than the fastest. This could mean that an intermediate result is being cached. 1000 loops, best of 3: 128 μs per loop
從上面的運(yùn)行結(jié)果可以看出,numpy的向量化運(yùn)算的效率要遠(yuǎn)遠(yuǎn)高于python的循環(huán)遍歷運(yùn)算(效率相差好幾百倍)。
(1ms=1000μs)
2 創(chuàng)建ndarray數(shù)組
首先需要導(dǎo)入numpy庫(kù),在導(dǎo)入numpy庫(kù)時(shí)通常使用“np”作為簡(jiǎn)寫(xiě),這也是Numpy官方倡導(dǎo)的寫(xiě)法。
當(dāng)然,你也可以選擇其他簡(jiǎn)寫(xiě)的方式或者直接寫(xiě)numpy,但還是建議用“np”,這樣你的程序能和大都數(shù)人的程序保持一致。
import numpy as np
創(chuàng)建ndarray數(shù)組的方式有很多種,這里介紹我使用的較多的幾種:
Method 1: 基于list或tuple
# 一維數(shù)組# 基于listarr1 = np.array([1,2,3,4]) print(arr1)# 基于tuplearr_tuple = np.array((1,2,3,4)) print(arr_tuple)# 二維數(shù)組 (2*3)arr2 = np.array([[1,2,4], [3,4,5]]) arr2
[1 2 3 4] [1 2 3 4] array([[1, 2, 4], [3, 4, 5]])
請(qǐng)注意:
一維數(shù)組用print輸出的時(shí)候?yàn)?[1 2 3 4],跟python的列表是有些差異的,沒(méi)有“,”
在創(chuàng)建二維數(shù)組時(shí),在每個(gè)子list外面還有一個(gè)”[]”,形式為“[[list1], [list2]]”
Method 2: 基于np.arange
# 一維數(shù)組arr1 = np.arange(5) print(arr1)# 二維數(shù)組arr2 = np.array([np.arange(3), np.arange(3)]) arr2
[0 1 2 3 4] array([[0, 1, 2], [0, 1, 2]])
Method 3: 基于arange以及reshape創(chuàng)建多維數(shù)組
# 創(chuàng)建三維數(shù)組arr = np.arange(24).reshape(2,3,4) arr
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]]])
請(qǐng)注意:arange的長(zhǎng)度與ndarray的維度的乘積要相等,即 24 = 2X3X4
用numpy.random創(chuàng)建數(shù)組的方法,可以參考下面的文章
其他創(chuàng)建ndarray的方法,各位小伙伴們自己可以研究下。
3 Numpy的數(shù)值類(lèi)型
Numpy的數(shù)值類(lèi)型如下:
每一種數(shù)據(jù)類(lèi)型都有相應(yīng)的數(shù)據(jù)轉(zhuǎn)換函數(shù),參考示例如下:
np.int8(12.334)
12
np.float64(12)
12.0
np.float(True)
1.0
bool(1)
True
在創(chuàng)建ndarray數(shù)組時(shí),可以指定數(shù)值類(lèi)型:
a = np.arange(5, dtype=float) a
array([ 0., 1., 2., 3., 4.])
請(qǐng)注意,復(fù)數(shù)不能轉(zhuǎn)換成為整數(shù)類(lèi)型或者浮點(diǎn)數(shù),比如下面的代碼會(huì)運(yùn)行出錯(cuò)
# float(42 + 1j)
4 ndarray數(shù)組的屬性
dtype屬性,ndarray數(shù)組的數(shù)據(jù)類(lèi)型,數(shù)據(jù)類(lèi)型的種類(lèi),前面已描述。
np.arange(4, dtype=float)
array([ 0., 1., 2., 3.])
# 'D'表示復(fù)數(shù)類(lèi)型np.arange(4, dtype='D')
array([ 0.+0.j, 1.+0.j, 2.+0.j, 3.+0.j])
np.array([1.22,3.45,6.779], dtype='int8')
array([1, 3, 6], dtype=int8)
ndim屬性,數(shù)組維度的數(shù)量
a = np.array([[1,2,3], [7,8,9]]) a.ndim
2
shape屬性,數(shù)組對(duì)象的尺度,對(duì)于矩陣,即n行m列,shape是一個(gè)元組(tuple)
a.shape
(2, 3)
size屬性用來(lái)保存元素的數(shù)量,相當(dāng)于shape中nXm的值
a.size
6
itemsize屬性返回?cái)?shù)組中各個(gè)元素所占用的字節(jié)數(shù)大小。
a.itemsize
4
nbytes屬性,如果想知道整個(gè)數(shù)組所需的字節(jié)數(shù)量,可以使用nbytes屬性。其值等于數(shù)組的size屬性值乘以itemsize屬性值。
a.nbytes
24
a.size*a.itemsize
24
T屬性,數(shù)組轉(zhuǎn)置
b = np.arange(24).reshape(4,6) b
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.T
array([[ 0, 6, 12, 18], [ 1, 7, 13, 19], [ 2, 8, 14, 20], [ 3, 9, 15, 21], [ 4, 10, 16, 22], [ 5, 11, 17, 23]])
復(fù)數(shù)的實(shí)部和虛部屬性,real和imag屬性
d = np.array([1.2+2j, 2+3j]) d
array([ 1.2+2.j, 2.0+3.j])
real屬性返回?cái)?shù)組的實(shí)部
d.real
array([ 1.2, 2. ])
imag屬性返回?cái)?shù)組的虛部
d.imag
array([ 2., 3.])
flat屬性,返回一個(gè)numpy.flatiter對(duì)象,即可迭代的對(duì)象。
e = np.arange(6).reshape(2,3) e
array([[0, 1, 2], [3, 4, 5]])
f = e.flat f
<numpy.flatiter at 0x65eaca0>
for item in f: print(item)
0 1 2 3 4 5
可通過(guò)位置進(jìn)行索引,如下:
f[2]
2
f[[1,4]]
array([1, 4])
也可以進(jìn)行賦值
e.flat=7e
array([[7, 7, 7], [7, 7, 7]])
e.flat[[1,4]]=1e
array([[7, 1, 7], [7, 1, 7]])
下圖是對(duì)ndarray各種屬性的一個(gè)小結(jié)
5 ndarray數(shù)組的切片和索引
一維數(shù)組
一維數(shù)組的切片和索引與python的list索引類(lèi)似。
a = np.arange(7) a
array([0, 1, 2, 3, 4, 5, 6])
a[1:4]
array([1, 2, 3])
# 每間隔2個(gè)取一個(gè)數(shù)a[ : 6: 2]
array([0, 2, 4])
二維數(shù)組的切片和索引,如下所示:
插播一條硬廣:技術(shù)文章轉(zhuǎn)發(fā)太多。本文涉及的代碼量比較多,如需要查看源代碼,請(qǐng)?jiān)谖⑿殴娞?hào)“Python數(shù)據(jù)之道”(ID:PyDataRoad)后臺(tái)回復(fù)關(guān)鍵字“2017026”。
6 處理數(shù)組形狀
6.1 形狀轉(zhuǎn)換
reshape()和resize()
b.reshape(4,3)
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.resize(4,3) b
array([[ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8], [ 9, 10, 11]])
函數(shù)resize()的作用跟reshape()類(lèi)似,但是會(huì)改變所作用的數(shù)組,相當(dāng)于有inplace=True的效果
ravel()和flatten(),將多維數(shù)組轉(zhuǎn)換成一維數(shù)組,如下:
b.ravel()
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
b.flatten()
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]])
兩者的區(qū)別在于返回拷貝(copy)還是返回視圖(view),flatten()返回一份拷貝,需要分配新的內(nèi)存空間,對(duì)拷貝所做的修改不會(huì)影響原始矩陣,而ravel()返回的是視圖(view),會(huì)影響原始矩陣。
參考如下代碼:
用tuple指定數(shù)組的形狀,如下:
b.shape=(2,6) b
array([[ 0, 1, 20, 3, 4, 5], [ 6, 7, 8, 9, 10, 11]])
轉(zhuǎn)置
前面描述了數(shù)組轉(zhuǎn)置的屬性(T),也可以通過(guò)transpose()函數(shù)來(lái)實(shí)現(xiàn)
b.transpose()
array([[ 0, 6], [ 1, 7], [20, 8], [ 3, 9], [ 4, 10], [ 5, 11]])
6.2 堆疊數(shù)組
b
array([[ 0, 1, 20, 3, 4, 5], [ 6, 7, 8, 9, 10, 11]])
c = b*2c
array([[ 0, 2, 40, 6, 8, 10], [12, 14, 16, 18, 20, 22]])
水平疊加
hstack()
np.hstack((b,c))
array([[ 0, 1, 20, 3, 4, 5, 0, 2, 40, 6, 8, 10], [ 6, 7, 8, 9, 10, 11, 12, 14, 16, 18, 20, 22]])
column_stack()函數(shù)以列方式對(duì)數(shù)組進(jìn)行疊加,功能類(lèi)似hstack()
np.column_stack((b,c))
array([[ 0, 1, 20, 3, 4, 5, 0, 2, 40, 6, 8, 10], [ 6, 7, 8, 9, 10, 11, 12, 14, 16, 18, 20, 22]])
垂直疊加
vstack()
np.vstack((b,c))
array([[ 0, 1, 20, 3, 4, 5], [ 6, 7, 8, 9, 10, 11], [ 0, 2, 40, 6, 8, 10], [12, 14, 16, 18, 20, 22]])
row_stack()函數(shù)以行方式對(duì)數(shù)組進(jìn)行疊加,功能類(lèi)似vstack()
np.row_stack((b,c))
array([[ 0, 1, 20, 3, 4, 5], [ 6, 7, 8, 9, 10, 11], [ 0, 2, 40, 6, 8, 10], [12, 14, 16, 18, 20, 22]])
concatenate()方法,通過(guò)設(shè)置axis的值來(lái)設(shè)置疊加方向
axis=1時(shí),沿水平方向疊加
axis=0時(shí),沿垂直方向疊加
np.concatenate((b,c),axis=1)
array([[ 0, 1, 20, 3, 4, 5, 0, 2, 40, 6, 8, 10], [ 6, 7, 8, 9, 10, 11, 12, 14, 16, 18, 20, 22]])
np.concatenate((b,c),axis=0)
array([[ 0, 1, 20, 3, 4, 5], [ 6, 7, 8, 9, 10, 11], [ 0, 2, 40, 6, 8, 10], [12, 14, 16, 18, 20, 22]])
由于針對(duì)數(shù)組的軸為0或1的方向經(jīng)常會(huì)混淆,通過(guò)示意圖,或許可以更好的理解。
關(guān)于數(shù)組的軸方向示意圖,以及疊加的示意圖,如下:
深度疊加
這個(gè)有點(diǎn)燒腦,舉個(gè)例子如下,自己可以體會(huì)下:
arr_dstack = np.dstack((b,c)) print(arr_dstack.shape) arr_dstack
(2, 6, 2) array([[[ 0, 0], [ 1, 2], [20, 40], [ 3, 6], [ 4, 8], [ 5, 10]], [[ 6, 12], [ 7, 14], [ 8, 16], [ 9, 18], [10, 20], [11, 22]]])
疊加前,b和c均是shape為(2,6)的二維數(shù)組,疊加后,arr_dstack是shape為(2,6,2)的三維數(shù)組。
深度疊加的示意圖如下:
6.3 數(shù)組的拆分
跟數(shù)組的疊加類(lèi)似,數(shù)組的拆分可以分為橫向拆分、縱向拆分以及深度拆分。
涉及的函數(shù)為 hsplit()、vsplit()、dsplit() 以及split()
b
array([[ 0, 1, 20, 3, 4, 5], [ 6, 7, 8, 9, 10, 11]])
沿橫向軸拆分(axis=1)
np.hsplit(b, 2)
[array([[ 0, 1, 20], [ 6, 7, 8]]), array([[ 3, 4, 5], [ 9, 10, 11]])]
np.split(b,2, axis=1)
[array([[ 0, 1, 20], [ 6, 7, 8]]), array([[ 3, 4, 5], [ 9, 10, 11]])]
沿縱向軸拆分(axis=0)
np.vsplit(b, 2)
[array([[ 0, 1, 20, 3, 4, 5]]), array([[ 6, 7, 8, 9, 10, 11]])]
np.split(b,2,axis=0)
[array([[ 0, 1, 20, 3, 4, 5]]), array([[ 6, 7, 8, 9, 10, 11]])]
深度拆分
arr_dstack
array([[[ 0, 0], [ 1, 2], [20, 40], [ 3, 6], [ 4, 8], [ 5, 10]], [[ 6, 12], [ 7, 14], [ 8, 16], [ 9, 18], [10, 20], [11, 22]]])
np.dsplit(arr_dstack,2)
[array([[[ 0], [ 1], [20], [ 3], [ 4], [ 5]], [[ 6], [ 7], [ 8], [ 9], [10], [11]]]), array([[[ 0], [ 2], [40], [ 6], [ 8], [10]], [[12], [14], [16], [18], [20], [22]]])]
拆分的結(jié)果是原來(lái)的三維數(shù)組拆分成為兩個(gè)二維數(shù)組。
這個(gè)燒腦的拆分過(guò)程可以自行分析下~~
7 數(shù)組的類(lèi)型轉(zhuǎn)換
數(shù)組轉(zhuǎn)換成list,使用tolist()
b
array([[ 0, 1, 20, 3, 4, 5], [ 6, 7, 8, 9, 10, 11]])
b.tolist()
[[0, 1, 20, 3, 4, 5], [6, 7, 8, 9, 10, 11]]
轉(zhuǎn)換成指定類(lèi)型,astype()函數(shù)
b.astype(float)
array([[ 0., 1., 20., 3., 4., 5.], [ 6., 7., 8., 9., 10., 11.]])
8 numpy常用統(tǒng)計(jì)函數(shù)
常用的函數(shù)如下:
請(qǐng)注意函數(shù)在使用時(shí)需要指定axis軸的方向,若不指定,默認(rèn)統(tǒng)計(jì)整個(gè)數(shù)組。
np.sum(),返回求和
np.mean(),返回均值
np.max(),返回最大值
np.min(),返回最小值
np.ptp(),數(shù)組沿指定軸返回最大值減去最小值,即(max-min)
np.std(),返回標(biāo)準(zhǔn)偏差(standard deviation)
np.var(),返回方差(variance)
np.cumsum(),返回累加值
np.cumprod(),返回累乘積值
b
array([[ 0, 1, 20, 3, 4, 5], [ 6, 7, 8, 9, 10, 11]])
np.max(b)
20
# 沿axis=1軸方向統(tǒng)計(jì)np.max(b,axis=1)
array([20, 11])
# 沿axis=0軸方向統(tǒng)計(jì)np.max(b,axis=0)
array([ 6, 7, 20, 9, 10, 11])
np.min(b)
0
np.ptp(),返回整個(gè)數(shù)組的最大值減去最小值,如下:
np.ptp(b)
20
# 沿axis=0軸方向np.ptp(b, axis=0)
array([ 6, 6, 12, 6, 6, 6])
# 沿axis=1軸方向np.ptp(b, axis=1)
array([20, 5])
np.cumsum(),沿指定軸方向進(jìn)行累加
b.resize(4,3) b
array([[ 0, 1, 20], [ 3, 4, 5], [ 6, 7, 8], [ 9, 10, 11]])
np.cumsum(b, axis=1)
array([[ 0, 1, 21], [ 3, 7, 12], [ 6, 13, 21], [ 9, 19, 30]], dtype=int32)
np.cumsum(b, axis=0)
array([[ 0, 1, 20], [ 3, 5, 25], [ 9, 12, 33], [18, 22, 44]], dtype=int32)
np.cumprod(),沿指定軸方向進(jìn)行累乘積 (Return the cumulative product of the elements along the given axis)
np.cumprod(b,axis=1)
array([[ 0, 0, 0], [ 3, 12, 60], [ 6, 42, 336], [ 9, 90, 990]], dtype=int32)
np.cumprod(b,axis=0)
array([[ 0, 1, 20], [ 0, 4, 100], [ 0, 28, 800], [ 0, 280, 8800]], dtype=int32)
9 數(shù)組的廣播
當(dāng)數(shù)組跟一個(gè)標(biāo)量進(jìn)行數(shù)學(xué)運(yùn)算時(shí),標(biāo)量需要根據(jù)數(shù)組的形狀進(jìn)行擴(kuò)展,然后執(zhí)行運(yùn)算。
這個(gè)擴(kuò)展的過(guò)程稱(chēng)為“廣播(broadcasting)”
b
array([[ 0, 1, 20], [ 3, 4, 5], [ 6, 7, 8], [ 9, 10, 11]])
d = b + 2d
array([[ 2, 3, 22], [ 5, 6, 7], [ 8, 9, 10], [11, 12, 13]])
寫(xiě)在最后
numpy涵蓋的內(nèi)容其實(shí)是非常豐富的,本文僅僅介紹了numpy一些常用的基本功能,算是對(duì)numpy的一個(gè)入門(mén)級(jí)的簡(jiǎn)單的較為全面的描述。
numpy官方的《Numpy Reference》文檔,光頁(yè)面數(shù)量就有1500+頁(yè),如想要系統(tǒng)的學(xué)習(xí)numpy,建議仔細(xì)閱讀官方的參考文檔,可在其官方網(wǎng)站進(jìn)行查閱。當(dāng)然,資料都是英文版的,可能看起來(lái)難度稍微大點(diǎn),看習(xí)慣了就好。
本文涉及的代碼量比較多,如需要查看源代碼,請(qǐng)?jiān)谖⑿殴娞?hào)“Python數(shù)據(jù)之道”(ID:PyDataRoad)后臺(tái)回復(fù)關(guān)鍵字“2017026”。
作者:Lemon
出處:個(gè)人微信公眾號(hào):“Python數(shù)據(jù)之道”(ID:PyDataRoad)和博客園:http://www.cnblogs.com/lemonbit/
本文版權(quán)歸作者所有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁(yè)面明顯位置給出原文出處,否則保留追究法律責(zé)任的權(quán)利。
http://www.cnblogs.com/lemonbit/p/7043879.html