第4章 numpy基礎:數組和矢量計算
使用numpy計算比純python計算快10到100倍(甚至更快),并且使用內存更少。
NumPy的ndarray:一種多維數組對象
numpy的N維數組對象(ndarray),該對象是一個快速而靈活的大數據集容器。
import numpy as np
data=np.random.randn(2,3)
data
array([[ 0.00668162, 0.45723418, 0.0438548 ],
[-2.23335801, -0.39107094, -0.25007822]])
data*10
array([[ 0.06681624, 4.57234183, 0.43854801],
[-22.33358006, -3.91070938, -2.5007822 ]])
data+data
array([[ 0.01336325, 0.91446837, 0.0877096 ],
[-4.46671601, -0.78214188, -0.50015644]])
每個ndarray都有一個shape(一個表示各維度大小的元組)和一個dtype(一個用于說明數組數據類型的對象)
data.shape
(2, 3)
data.dtype
dtype('float64')
創建ndarray
使用array函數,接受將一切序列型的對象(包括其他數組),然后產生一個新的含有傳入數據的numpy數組。同時可以把嵌套序列轉為一個多維數組。
data1=[1,2,3,4,9.4]
arr1=np.array(data1)
arr1
array([1. , 2. , 3. , 4. , 9.4])
data2=[[1,2,3],[4.5,4,5]]
arr2=np.array(data2)
arr2
array([[1. , 2. , 3. ],
[4.5, 4. , 5. ]])
除非特別說明,np.array會嘗試為新建的這個數組推斷出一個較為合適的數據類型。數據類型保存在一個特殊的dtype對象中。
numpy還可以建立一些特殊數組,例如:ones(全1)、zeros(全0)。empty可以創建一個沒有具體值的數組。
np.zeros(10)
array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
np.ones((2,3))
array([[1., 1., 1.],
[1., 1., 1.]])
np.empty((2,3,4))
array([[[2.05833592e-312, 2.05833592e-312, 1.29441743e-312,
1.03977794e-312],
[1.06099790e-312, 1.08221785e-312, 1.10343781e-312,
1.20953760e-312],
[1.10343781e-312, 2.12199580e-313, 2.41907520e-312,
1.03977794e-312]],
[[2.33419537e-312, 9.76118064e-313, 2.41907520e-312,
2.05833592e-312],
[8.48798317e-313, 2.05833592e-312, 2.05833592e-312,
8.70018275e-313],
[2.05833592e-312, 2.41907520e-312, 9.80058112e+252,
1.23971686e+224]]])
np.arange(15)
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
一些常見的數組創建函數如下表。一般數據類型在沒有特別說明的情況下,都是float64(浮點數)。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-VfeYa2QQ-1579187132805)(attachment:16.png)]
ndarray的數據類型
dtype含有ndarray將一塊內存解釋為特定數據類型所需的信息。常見的NumPy數據類型有:
可以通過astype方法明確地把一個數組從一個dtype轉到另一個dtype。
arr1=np.array([1,2,3],dtype=np.float64)
arr2=np.array([1,2,3],dtype=np.int32)
arr1.dtype
dtype('float64')
arr2.dtype
dtype('int32')
arr3=arr1.astype(np.int32)
arr3.dtype
dtype('int32')
numpy數組的運算
大小相等(shape相同)的數組之間的任何算術運算都會將運算應用到元素級。
會降到對應元素之間的算術運算。
對于標量(非數組,單獨數字)與數組的算術運算將標量傳播到各個元素。
對于shape相同的數組之間的比較,會產出布爾數組。
arr=np.array([[1.,2.,3.],[4.,5.,6.]])
arr*arr
array([[ 1., 4., 9.],
[16., 25., 36.]])
arr-arr
array([[0., 0., 0.],
[0., 0., 0.]])
arr**2
array([[ 1., 4., 9.],
[16., 25., 36.]])
1/arr
array([[1. , 0.5 , 0.33333333],
[0.25 , 0.2 , 0.16666667]])
arr2=np.array([[2.,3.,4.],[1.,2.,10.]])
arr2>arr1
array([[ True, True, True],
[False, False, True]])
基本的索引和切片
對于一維數組的切片和python列表的功能差不多。
需要注意的是,對于數組的切片的修改,也會直接反應到原數組中,源數組的數據類型也會發生變化。
arr=np.arange(10)
arr
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
arr[1:3]
array([1, 2])
arr[4:6]=13
arr
array([ 0, 1, 2, 3, 13, 13, 6, 7, 8, 9])
arr_sl=arr[3:6]
arr_sl[2]=999
arr
array([ 0, 1, 2, 3, 13, 999, 6, 7, 8, 9])
對于多維數組,進行元素選擇的時候,只需要逐層向下傳遞就行。
在二維數組中,軸0作為行,軸1作為列。(axis=0即為行,axis=1即為列)。
數組或標量值都是可以被賦值為數組中的某部分。
arr3d = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])
arr3d[0]
array([[1, 2, 3],
[4, 5, 6]])
old_values = arr3d[0].copy()
arr3d[0] = 42
arr3d
array([[[42, 42, 42],
[42, 42, 42]],
[[ 7, 8, 9],
[10, 11, 12]]])
arr3d[0] = old_values
arr3d
array([[[ 1, 2, 3],
[ 4, 5, 6]],
[[ 7, 8, 9],
[10, 11, 12]]])
就切片而言,一維數組切片和python語法差別不大。二維數組的切片,其是按著某個軸方向進行切片的。
切片中的多軸取值如下例:
arr2d=np.array([[1,2,3],[4,5,6],[7,8,9]])
arr2d[:2]
#沿著第一個軸(第0軸)進行切片。
#注意,“只有冒號”表示選取整個軸,因此你可以像下面這樣只對高維軸進行切片。
array([[1, 2, 3],
[4, 5, 6]])
布爾型索引
利用true或者false進行選擇數據。布爾型數組的長度必須跟被索引的軸長度一致。要選擇除"Bob"以外的其他值,既可以使用不等于符號(!=),也可以通過~對條件進行否定。選取這三個名字中的兩個需要組合應用多個布爾條件,使用&(和)、|(或)之類的布爾算術運算符。
names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'])
data = np.random.randn(7, 4)
names == 'Bob'
array([ True, False, False, True, False, False, False])
data
array([[ 1.88604910e+00, -1.09239246e+00, 7.36955312e-01,
6.21962781e-01],
[-8.94589801e-01, -7.04479134e-01, 6.15735344e-01,
4.17365984e-01],
[-1.88309621e+00, 1.48204259e+00, -1.05637845e-01,
-1.47304673e+00],
[-3.27432236e-01, 2.47418588e-03, 6.11339801e-01,
-9.02064313e-01],
[-2.30341292e+00, 3.13932432e-01, 1.25433341e+00,
-7.04365322e-02],
[ 1.10938161e+00, 6.42370960e-01, 1.09503863e+00,
-2.70052944e-01],
[ 1.14600475e+00, 1.34853669e+00, 1.38460778e-01,
-2.01624321e-03]])
data[names == 'Bob']
array([[ 1.8860491 , -1.09239246, 0.73695531, 0.62196278],
[-0.32743224, 0.00247419, 0.6113398 , -0.90206431]])
data[names == 'Bob', 2:]
array([[ 0.73695531, 0.62196278],
[ 0.6113398 , -0.90206431]])
names != 'Bob'
array([False, True, True, False, True, True, True])
data[~(names == 'Bob')]
array([[-8.94589801e-01, -7.04479134e-01, 6.15735344e-01,
4.17365984e-01],
[-1.88309621e+00, 1.48204259e+00, -1.05637845e-01,
-1.47304673e+00],
[-2.30341292e+00, 3.13932432e-01, 1.25433341e+00,
-7.04365322e-02],
[ 1.10938161e+00, 6.42370960e-01, 1.09503863e+00,
-2.70052944e-01],
[ 1.14600475e+00, 1.34853669e+00, 1.38460778e-01,
-2.01624321e-03]])
con=names=='Bob'
data[~con]
array([[-8.94589801e-01, -7.04479134e-01, 6.15735344e-01,
4.17365984e-01],
[-1.88309621e+00, 1.48204259e+00, -1.05637845e-01,
-1.47304673e+00],
[-2.30341292e+00, 3.13932432e-01, 1.25433341e+00,
-7.04365322e-02],
[ 1.10938161e+00, 6.42370960e-01, 1.09503863e+00,
-2.70052944e-01],
[ 1.14600475e+00, 1.34853669e+00, 1.38460778e-01,
-2.01624321e-03]])
mask = (names == 'Bob') | (names == 'Will')
mask
array([ True, False, True, True, True, False, False])
data[mask]
array([[ 1.8860491 , -1.09239246, 0.73695531, 0.62196278],
[-1.88309621, 1.48204259, -0.10563785, -1.47304673],
[-0.32743224, 0.00247419, 0.6113398 , -0.90206431],
[-2.30341292, 0.31393243, 1.25433341, -0.07043653]])
data[data < 0] = 0
data
array([[1.8860491 , 0. , 0.73695531, 0.62196278],
[0. , 0. , 0.61573534, 0.41736598],
[0. , 1.48204259, 0. , 0. ],
[0. , 0.00247419, 0.6113398 , 0. ],
[0. , 0.31393243, 1.25433341, 0. ],
[1.10938161, 0.64237096, 1.09503863, 0. ],
[1.14600475, 1.34853669, 0.13846078, 0. ]])
data[names != 'Joe'] = 7
data
array([[7. , 7. , 7. , 7. ],
[0. , 0. , 0.61573534, 0.41736598],
[7. , 7. , 7. , 7. ],
[7. , 7. , 7. , 7. ],
[7. , 7. , 7. , 7. ],
[1.10938161, 0.64237096, 1.09503863, 0. ],
[1.14600475, 1.34853669, 0.13846078, 0. ]])
數組轉置和軸對換
數組轉置有transpose方法,也有一個特殊T屬性.
arr=np.arange(15).reshape((3,5))
arr
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])
arr.T
array([[ 0, 5, 10],
[ 1, 6, 11],
[ 2, 7, 12],
[ 3, 8, 13],
[ 4, 9, 14]])
np.dot(arr.T,arr)
array([[125, 140, 155, 170, 185],
[140, 158, 176, 194, 212],
[155, 176, 197, 218, 239],
[170, 194, 218, 242, 266],
[185, 212, 239, 266, 293]])
對于高維數組,transpose需要得到一個由軸編號組成的元組才能對這些軸進行轉置。
arr.transpose((1,0,2)) 表示第一軸被換成原數組的第二個維度,第二個軸被換成原數組的第一個維度數組,最后一個軸不變。
arr=np.arange(12).reshape((2,2,3))
arr
array([[[ 0, 1, 2],
[ 3, 4, 5]],
[[ 6, 7, 8],
[ 9, 10, 11]]])
arr.transpose((1,0,2))
array([[[ 0, 1, 2],
[ 6, 7, 8]],
[[ 3, 4, 5],
[ 9, 10, 11]]])
通用函數:快速的元素級數組函數
可以同時對數組的整體數據進行函數變換。例如sqrt(平方)和exp(e的指數值);add(求多個數組的和)或maximum(多個數組中元素級別最大的元素)。modf函數,可以分離浮點數數組的小數和整數部分。
還有一些函數如下:
arr = np.random.randn(7) * 5
remainder, whole_part = np.modf(arr)
remainder
array([-0.17048277, -0.85976085, 0.54241456, -0.10808041, 0.4622122 ,
0.89957455, 0.38456908])
whole_part
array([-10., -3., 8., -0., 4., 1., 5.])
利用數組進行數據處理
numpy矢量化數組運算速度要比等價的純Python方式快上一兩個數量級。
p=np.arange(-5,5,0.01)
x,y=np.meshgrid(p,p)#np.meshgrid函數接受兩個1維數組,并產生兩個二維矩陣(對應于兩個數組中所有的(x,y)對)
y
array([[-5. , -5. , -5. , ..., -5. , -5. , -5. ],
[-4.99, -4.99, -4.99, ..., -4.99, -4.99, -4.99],
[-4.98, -4.98, -4.98, ..., -4.98, -4.98, -4.98],
...,
[ 4.97, 4.97, 4.97, ..., 4.97, 4.97, 4.97],
[ 4.98, 4.98, 4.98, ..., 4.98, 4.98, 4.98],
[ 4.99, 4.99, 4.99, ..., 4.99, 4.99, 4.99]])
z=np.sqrt(x**2+y**2)
import matplotlib.pyplot as plt
plt.imshow(z, cmap=plt.cm.gray); plt.colorbar()
plt.title("Image plot of $\sqrt{x^2 + y^2}$ for a grid of values")
Text(0.5,1,'Image plot of $\\sqrt{x^2 + y^2}$ for a grid of values')
plt.imshow(z, cmap=plt.cm.gray); plt.colorbar()
<matplotlib.colorbar.Colorbar at 0x12cf75f8>
將條件邏輯表述為數組運算
np.where函數是三元表達是 x if condition else y的矢量化版本。np.where的第2個和第三個參數不必是數組,它們都可以是標量值。在數據分析工作中,where通常用于根據另一個數組而產生一個新的數組。
xarr = np.array([1.1, 1.2, 1.3, 1.4, 1.5])
yarr = np.array([2.1, 2.2, 2.3, 2.4, 2.5])
cond = np.array([True, False, True, True, False])
result = [(x if c else y)
for x, y, c in zip(xarr, yarr, cond)]
result
[1.1, 2.2, 1.3, 1.4, 2.5]
result = np.where(cond, xarr, yarr)
result
array([1.1, 2.2, 1.3, 1.4, 2.5])
數學和統計方法
sum、mean以及標準差std等聚合計算。對于一維數組而言,arr.mean(1)是“計算行的平均值”,arr.sum(0)是“計算每列的和”。arr.cumsum()為arr數組的累加數組。
使用布爾數組進行數據選擇。
True表示1,0為False.
排序
和python中的sort方法一樣。np.sort返回的是數組是已排序副本。
唯一化以及其它的集合邏輯
通過np.unique方法可以找出數組中的唯一值并返回已排序的結果。
用于數組的文件輸入輸出
numpy保存的文件是npy文件。np.save(保存數據文件)和np.load(讀取數據文件)是讀寫磁盤數組數據的兩個主要函數。
線性代數
x = np.array([[1., 2., 3.], [4., 5., 6.]])
y = np.array([[6., 23.], [-1, 7], [8, 9]])
#x.dot(y)等價于np.dot(x, y)
x.dot(y)
array([[ 28., 64.],
[ 67., 181.]])
np.ones(3)
array([1., 1., 1.])
np.dot(x, np.ones(3))
array([ 6., 15.])
numpy.linalg中有1組標準的矩陣分解運算以及諸如求逆和行列式之類的函數。
偽隨機數生成
隨機數的生成和隨機種子相關,
#隨機漫步的計算。