上一章:【從 0 到 1 落地】機器學習實操項目目錄:覆蓋入門到進階,大學生就業 / 競賽必備
下一章:
機器學習核心知識點目錄:機器學習核心知識點目錄
機器學習實戰項目:【從 0 到 1 落地】機器學習實操項目目錄:覆蓋入門到進階,大學生就業 / 競賽必備
文章目錄
- 基本概念
- 數組的創建
- 打印數組
- 基本操作
- 廣播函數
- 索引、切片和迭代
- 數組形狀操作
- 更改數組的形狀
- 堆砌不同的數組
- 將一個數組劃分為多個更小的數組
- 復制和視圖
- 不復制
- 視圖和淺復制
- 深復制
- 多種多樣的索引和索引的小技巧
- 用數組訪問數組
- 用布爾數組來訪問數組
- ix_()函數
- 線性代數
- 簡單的數組操作
- 小技巧和小貼士
- 自動更改數組大小
- 直方圖
基本概念
Numpy 的核心是連續的多維數組。
Numpy中的數組叫做np.ndarray
,也可以使用別名np.array
。
但這里的np.array與Python標準庫中的array.array是不同的。
下列是幾個ndarray
中的重要屬性:
ndarray.ndim
數組的維數。
ndarray.shape
數組的形狀。
ndarray.size
數組的元素個數。
ndarray.dtype
數組的元素類型。
代碼:
import numpy as nppreds = np.array([1,1,1])
labels = np.array([1,2,3])(1/3)*np.sum(np.square(preds-labels))
輸出結果:
1.6666666666666665
代碼:
import numpy as np
data=np.arange(15).reshape(3,5)
print(data)
print(data.shape)
print(data.ndim)
print(data.size)
print(data.dtype.name)
輸出結果:
[[ 0 1 2 3 4][ 5 6 7 8 9][10 11 12 13 14]]
(3, 5)
2
15
int32
數組的創建
創建數組有多種方式。你可以使用np.array
直接用Python的元組和列表來創建。
代碼:
import numpy as np
a=np.array([1,2,3])
print(a.dtype)
b=np.array([1.1,2.2,3.3])
print(b.dtype)
c=np.array([(1,2,3),(4.5,5,6)]) #創建二維數組
print(c)
d=np.array([(1,2),(3,4)],dtype=complex) #數組的類型可以在創建時顯式聲明
print(d)
輸出結果:
int32
float64
[[ 1. 2. 3. ][ 4.5 5. 6. ]]
[[ 1.+0.j 2.+0.j][ 3.+0.j 4.+0.j]]
通常,數組的元素的未知的,但是形狀確實已知的。所以NumPy提供了多種創建空數組的方法。
np.zeros
創建全是0的數組。
np.ones
創建全是1的數組。
np.empty
創建初始值是隨機數的數組。
需要注意的是上述方法創建的數組元素的類型是 float64
代碼:
e=np.zeros((3,4))
print(e)
f=np.ones((2,3,4),dtype=np.int16)#可以更改數據類型
print(f)
g=np.empty((2,3))
print(g)
輸出結果:
[[ 0. 0. 0. 0.][ 0. 0. 0. 0.][ 0. 0. 0. 0.]]
[[[1 1 1 1][1 1 1 1][1 1 1 1]][[1 1 1 1][1 1 1 1][1 1 1 1]]]
[[ 1. 2. 3. ][ 4.5 5. 6. ]]
為了創建列表,NumPy提供了和 range
類似的函數。
np.arange(start,end,step)
代碼:
a=np.arange(10,30,5)
print(a)
b=np.arange(0,2,0.3)#同樣可以接收浮點數
print(b)
輸出結果:
[10 15 20 25]
[ 0. 0.3 0.6 0.9 1.2 1.5 1.8]
在生成浮點數列表時,最好不要使用np.arange
,而是使用np.linspace
。
np.linspace(start,stop,num)
代碼:
np.linspace(0,2,9)
輸出結果:
array([ 0. , 0.25, 0.5 , 0.75, 1. , 1.25, 1.5 , 1.75, 2. ])
打印數組
當你打印一個數組時,NumPy顯示數組的方式和嵌套的列表類似,但是會遵循以下布局:
- 最后一維從左到右顯示
- 第二維到最后一維從上到下顯示
- 剩下的同樣從上到下顯示,以空行分隔
一維數組顯示成一行,二維數組顯示成矩陣,三維數組顯示成矩陣的列表。
代碼:
a=np.arange(6)
print(a)
b=np.arange(12).reshape(4,3)
print(b)
c=np.arange(24).reshape(2,3,4)
print(c)
輸出結果:
[0 1 2 3 4 5]
[[ 0 1 2][ 3 4 5][ 6 7 8][ 9 10 11]]
[[[ 0 1 2 3][ 4 5 6 7][ 8 9 10 11]][[12 13 14 15][16 17 18 19][20 21 22 23]]]
當一個數組元素太多,不方便顯示時,NumPy會自動數組的中間部分,只顯示邊角的數據。
代碼:
print(np.arange(10000))
輸出結果:
[ 0 1 2 ..., 9997 9998 9999]
基本操作
數組的算數計算是在元素層級運算的。計算結果會存在一個新創建的數組中。
代碼:
import numpy as np
a=np.array([20,30,40,50])
b=np.arange(4)
print(b)
c=a-b
print(c)
print(b**2)
print(10*np.sin(a))
print(a<35)
輸出結果:
[0 1 2 3]
[20 29 38 47]
[0 1 4 9]
[ 9.12945251 -9.88031624 7.4511316 -2.62374854]
[ True True False False]
在NumPy中*
號仍然表示乘法,矩陣乘積用np.dot
來計算。
代碼:
A=np.array([(1,1),(0,1)])
B=np.array([(2,0),(3,4)])
print(A*B)
print(A.dot(B))
print(np.dot(A,B))
輸出結果:
[[2 0][0 4]]
[[5 4][3 4]]
[[5 4][3 4]]
類似于+=
和*=
的運算是直接在現有數組上計算的,沒有創建新的數組。Numpy中的計算同樣也是向上轉型的,可以簡單理解成浮點數和整數運算的結果是浮點數。
代碼:
a = np.ones((2,3), dtype=int)
b = np.random.random((2,3))
a*=3
print(a)
b += a
print(b)
# a += b # 浮點數不會自動轉換成整數
輸出結果:
[[3 3 3][3 3 3]]
[[ 3.36167598 3.63342297 3.22543331][ 3.17992397 3.01462584 3.87847828]]
np.ndarray
提供了許多一元操作。比如數組求和、求最大最小值等。
代碼:
a=np.random.random((2,3))
print(a)
print(a.sum())
print(a.mean())
print(a.max())
print(a.min())
輸出結果:
[[ 0.06108727 0.21625055 0.066292 ][ 0.20271722 0.93946432 0.37747181]]
1.86328317161
0.310547195269
0.939464322779
0.0610872663968
默認的,這些一元操作是對整個數組進行計算,沒有考慮到數組的形狀。你可以設置axis
參數來指定運算方向。axis
表示第n維(從0開始)。
代碼:
b=np.arange(12).reshape(3,4)
print(b)
print(b.sum(axis=0)) #對第0維的元素求和
print(b.sum(axis=1)) #對第1維的元素求和
print(b.min(axis=1))
print(b.cumsum(axis=1)) #對第1維的元素累加求和
輸出結果:
[[ 0 1 2 3][ 4 5 6 7][ 8 9 10 11]]
[12 15 18 21]
[ 6 22 38]
[0 4 8]
[[ 0 1 3 6][ 4 9 15 22][ 8 17 27 38]]
廣播函數
NumPy提供了熟知的數學方法,如:sin、cos、exp等。在NumPy中,這些方法被稱作廣播函數。這些函數會對數組中的每個元素進行計算,返回計算后的數組。
代碼:
B=np.arange(3)
print(B)
print(np.exp(B))
print(np.sqrt(B))
C=np.array([2,-1,4])
print(np.add(B,C))
print(B+C)
輸出結果:
[0 1 2]
[ 1. 2.71828183 7.3890561 ]
[ 0. 1. 1.41421356]
[2 0 6]
[2 0 6]
索引、切片和迭代
一維數組可以被索引、切片和迭代,就和Python中的列表一樣。
代碼:
a=np.arange(10)**3
print(a)
print(a[2])
print(a[2:5])
a[:6:2]=-1000
print(a)
print(a[::-1])
for i in a:print(i)
輸出結果:
[ 0 1 8 27 64 125 216 343 512 729]
8
[ 8 27 64]
[-1000 1 -1000 27 -1000 125 216 343 512 729]
[ 729 512 343 216 125 -1000 27 -1000 1 -1000]
-1000
1
-1000
27
-1000
125
216
343
512
729
多維數組可以在每一個維度有一個索引,這些索引構成元組來進行訪問。
代碼:
def f(x,y):return 10*x+y
b=np.fromfunction(f,(5,4),dtype=int)
print(b)
print(b[2,3])
print(b[0:5,1])
print(b[:,1])
print(b[1:3,:])
輸出結果:
[[ 0 1 2 3][10 11 12 13][20 21 22 23][30 31 32 33][40 41 42 43]]
23
[ 1 11 21 31 41]
[ 1 11 21 31 41]
[[10 11 12 13][20 21 22 23]]
...
表示對索引的省略。如下所示:
代碼:
c = np.array( [[[ 0, 1, 2], # 三維數組[ 10, 12, 13]],[[100,101,102],[110,112,113]]])
print(c.shape)
print(c[1,...]) # 和 c[1,:,:] 、 c[1]效果相同
print(c[...,2]) # 和c[:,:,2]效果相同
輸出結果:
(2, 2, 3)
[[100 101 102][110 112 113]]
[[ 2 13][102 113]]
對多維數組的迭代是在第一維進行迭代的。
代碼:
for row in b:print(row)
輸出結果:
[0 1 2 3]
[10 11 12 13]
[20 21 22 23]
[30 31 32 33]
[40 41 42 43]
如果需要遍歷多維數組的所有元素,可以使用flat
這個屬性。
代碼:
for element in b.flat:print(element)
輸出結果:
0
1
2
3
10
11
12
13
20
21
22
23
30
31
32
33
40
41
42
43
數組形狀操作
更改數組的形狀
有很多種方式可以更改數組的形狀。下列的函數都沒有對原數組進行更改,而是返回了一個更改后的新數組。
代碼:
a = np.floor(10*np.random.random((3,4)))
print(a.ravel()) #返回鋪平后的數組
print(a.reshape(6,2)) #按照指定的形狀更改
print(a.T)#返回轉置矩陣
輸出結果:
[ 5. 0. 9. 5. 5. 4. 2. 2. 3. 2. 0. 7.]
[[ 5. 0.][ 9. 5.][ 5. 4.][ 2. 2.][ 3. 2.][ 0. 7.]]
[[ 5. 5. 3.][ 0. 4. 2.][ 9. 2. 0.][ 5. 2. 7.]]
如果一個維度填的是-1,則該維度的形狀會自動進行計算
代碼:
print(a.reshape(3,-1))
輸出結果:
[[ 5. 0. 9. 5.][ 5. 4. 2. 2.][ 3. 2. 0. 7.]]
堆砌不同的數組
多個數組可以按照不同的軸合在一起
代碼:
a=np.floor(10*np.random.random((2,2)))
print(a)
b=np.floor(10*np.random.random((2,2)))
print(b)
print(np.vstack((a,b)))#垂直方向堆砌
print(np.hstack((a,b)))#水平方向堆砌
from numpy import newaxis
print(a[:,newaxis])
輸出結果:
[[ 5. 1.][ 4. 2.]]
[[ 8. 1.][ 7. 8.]]
[[ 5. 1.][ 4. 2.][ 8. 1.][ 7. 8.]]
[[ 5. 1. 8. 1.][ 4. 2. 7. 8.]]
[[[ 5. 1.]][[ 4. 2.]]]
將一個數組劃分為多個更小的數組
使用hsplit
,vsplit
可以對數組按照水平方向和垂直方向進行劃分。
代碼:
a=np.floor(10*np.random.random((2,12)))
print(a)
print(np.hsplit(a,3))
print(np.hsplit(a,(1,2,3)))#在第一列,第二列,第三列進行劃分
輸出結果:
[[ 7. 4. 0. 7. 5. 6. 4. 4. 4. 7. 7. 0.][ 0. 1. 7. 7. 4. 9. 7. 0. 0. 2. 7. 5.]]
[array([[ 7., 4., 0., 7.],[ 0., 1., 7., 7.]]), array([[ 5., 6., 4., 4.],[ 4., 9., 7., 0.]]), array([[ 4., 7., 7., 0.],[ 0., 2., 7., 5.]])]
[array([[ 7.],[ 0.]]), array([[ 4.],[ 1.]]), array([[ 0.],[ 7.]]), array([[ 7., 5., 6., 4., 4., 4., 7., 7., 0.],[ 7., 4., 9., 7., 0., 0., 2., 7., 5.]])]
復制和視圖
當操作數組時,數組的數據有時會復制到新數組中,有時又不會。這通常令初學者感到困難。總的來說有下面三種情況:
不復制
簡單的賦值不會復制數組的數據。
代碼:
a=np.arange(12)
b=a
print(b is a)
b.shape=3,4
print(a.shape)
輸出結果:
True
(3, 4)
視圖和淺復制
不同的數組可以使用同一份數據,view
函數在同一份數據上創建了新的數組對象。
代碼:
c=a.view()
print(c is a)
print(c.base is a) #c是a的數據的視圖
print(c.flags.owndata)
c.shape=6,2
print(a.shape) #a的形狀沒有改變
c[4,1]=1234 #a的數據改變了
print(a)
輸出結果:
False
True
False
(3, 4)
[[ 0 1 2 3][ 4 5 6 7][ 8 1234 10 11]]
對數組切片會返回數組的視圖
代碼:
s=a[:,1:3]
s[:]=10
print(a)
輸出結果:
[[ 0 10 10 3][ 4 10 10 7][ 8 10 10 11]]
深復制
copy
函數實現了對數據和數組的完全復制。
代碼:
d=a.copy()
print(d is a)
print(d.base is a)
d[0,0]=9999
print(a)
輸出結果:
False
False
[[ 0 10 10 3][ 4 10 10 7][ 8 10 10 11]]
多種多樣的索引和索引的小技巧
相比Python的列表,NumPy提供了更多的索引功能。除了可以用整數和列表來訪問數組之外,數組還可以被整型數組和布爾數組訪問。
用數組訪問數組
代碼:
a=np.arange(12)**2
i=np.array([1,1,3,8,5])
print(a[i])
j=np.array([[3,4],[8,5]]) #用二維數組來訪問數組
print(a[j]) #產生和訪問的數組相同形狀的結果
輸出結果:
[ 1 1 9 64 25]
[[ 9 16][64 25]]
在時間序列的數據上尋找最大值通常會用到數組索引
代碼:
time=np.linspace(20,145,5)
data=np.sin(np.arange(20)).reshape(5,4)
print(time)
print(data)
ind=data.argmax(axis=0)#返回按照指定軸的方向的最大值的索引
time_max=time[ind]
print(time_max)
data_max=data[ind,range(data.shape[1])]
print(data_max)
輸出結果:
[ 20. 51.25 82.5 113.75 145. ]
[[ 0. 0.84147098 0.90929743 0.14112001][-0.7568025 -0.95892427 -0.2794155 0.6569866 ][ 0.98935825 0.41211849 -0.54402111 -0.99999021][-0.53657292 0.42016704 0.99060736 0.65028784][-0.28790332 -0.96139749 -0.75098725 0.14987721]]
[ 82.5 20. 113.75 51.25]
[ 0.98935825 0.84147098 0.99060736 0.6569866 ]
你也可以使用數組索引來賦值
代碼:
a=np.arange(5)
a[[1,3,4]]=0
print(a)
輸出結果:
[0 0 2 0 0]
如果賦值時有重復的索引,則賦值會執行多次,留下最后一次執行的結果
代碼:
a=np.arange(5)
a[[0,0,0]]=[1,2,3]
print(a)
輸出結果:
[3 1 2 3 4]
但是賦值時使用+=
時,并不會重復計算
代碼:
a=np.arange(5)
a[[0,0,0]]+=1
print(a)
輸出結果:
[1 1 2 3 4]
這是因為"a+=1"最終是解釋成了"a=a+1"
用布爾數組來訪問數組
通過使用布爾數組索引,我們可以選擇哪些數據是需要的,哪些是不需要的。
在賦值中也非常有用。
代碼:
a = np.arange(12).reshape(3,4)
b = a > 4
print(b)
print(a[b])
a[b]=10
print(a)
輸出結果:
[[False False False False][False True True True][ True True True True]]
[ 5 6 7 8 9 10 11]
[[ 0 1 2 3][ 4 10 10 10][10 10 10 10]]
下面的代碼用布爾數組索引產生了曼德布洛特集合的圖像。
代碼:
import numpy as np
import matplotlib.pyplot as plt
def mandelbrot( h,w, maxit=20 ):"""Returns an image of the Mandelbrot fractal of size (h,w)."""y,x = np.ogrid[ -1.4:1.4:h*1j, -2:0.8:w*1j ]c = x+y*1jz = cdivtime = maxit + np.zeros(z.shape, dtype=int)for i in range(maxit):z = z**2 + cdiverge = z*np.conj(z) > 2**2 # who is divergingdiv_now = diverge & (divtime==maxit) # who is diverging nowdivtime[div_now] = i # note whenz[diverge] = 2 # avoid diverging too muchreturn divtime
plt.imshow(mandelbrot(400,400))
plt.show()
輸出結果:
ix_()函數
ix_函數被用來計算不同的向量的乘積。
代碼:
a = np.array([2,3,4,5])
b = np.array([8,5,4])
c = np.array([5,4,6,8,3])
ax,bx,cx = np.ix_(a,b,c)
print(ax)
print(bx)
print(cx)
print(ax.shape, bx.shape, cx.shape)
result = ax*bx*cx + ax
print(result)
print(result[3,2,4])
print(a[3]*b[2]*c[4]+a[3])#計算的結果是相同的
輸出結果:
[[[2]][[3]][[4]][[5]]]
[[[8][5][4]]]
[[[5 4 6 8 3]]]
(4, 1, 1) (1, 3, 1) (1, 1, 5)
[[[ 82 66 98 130 50][ 52 42 62 82 32][ 42 34 50 66 26]][[123 99 147 195 75][ 78 63 93 123 48][ 63 51 75 99 39]][[164 132 196 260 100][104 84 124 164 64][ 84 68 100 132 52]][[205 165 245 325 125][130 105 155 205 80][105 85 125 165 65]]]
65
65
線性代數
提供基本的線性代數操作
簡單的數組操作
代碼:
import numpy as np
a = np.array([[1.0, 2.0], [3.0, 4.0]])
print(a)
a.transpose()
np.linalg.inv(a)
u = np.eye(2) # unit 2x2 matrix; "eye" represents "I"
j = np.array([[0.0, -1.0], [1.0, 0.0]])
np.dot (j, j) # 點積
np.trace(u) # 矩陣的跡
y = np.array([[5.], [7.]])
print(np.linalg.solve(a, y))#解線性方程組
print(np.linalg.eig(j))#計算特征值
輸出結果:
[[ 1. 2.][ 3. 4.]]
[[-3.][ 4.]]
(array([ 0.+1.j, 0.-1.j]), array([[ 0.70710678+0.j , 0.70710678-0.j ],[ 0.00000000-0.70710678j, 0.00000000+0.70710678j]]))
小技巧和小貼士
自動更改數組大小
在更改數組大小時,你可以省略一個維度的大小,這個維度的大小會自動計算出來
代碼:
a = np.arange(30)
a.shape = 2,-1,3 # -1 表示自動計算大小
print(a.shape)
輸出結果:
(2, 5, 3)
直方圖
代碼:
import numpy as np
import matplotlib.pyplot as plt
mu,sigma=2,0.5
v=np.random.normal(mu,sigma,10000)
#matplotlib版本
plt.hist(v,bins=100,normed=1)
plt.show()
#NumPy版本
(n, bins) = np.histogram(v, bins=50, normed=True) # NumPy version (no plot)
plt.plot(.5*(bins[1:]+bins[:-1]), n)
plt.show()
輸出結果:
上一章:【從 0 到 1 落地】機器學習實操項目目錄:覆蓋入門到進階,大學生就業 / 競賽必備
下一章:
機器學習核心知識點目錄:機器學習核心知識點目錄
機器學習實戰項目:【從 0 到 1 落地】機器學習實操項目目錄:覆蓋入門到進階,大學生就業 / 競賽必備