python資料分析 -- numpy庫初識
標籤(空格分隔): 王小草機器學習筆記
python的強大之處不但因為簡潔易學高效,還在於她有許多庫,可以方便我們得到想要的計算。比如今天講的numpy庫,為python提供了快速的多維陣列的處理能力。有人數,numpy庫的出現使得python可以像matlab一樣去計算了。(matlab是10年前乃至今日仍然大受青睞的草稿本式的程式語言)。
1. 匯入Numpy庫
要呼叫numpy庫,我們就要匯入這個庫,匯入的語句就一句。
as 後面是重新命名,也可以說是縮寫,在我們的程式中,我們只要寫np,自動就程式碼numpy。這是約定俗稱的一個簡稱,當其他人閱讀你的程式碼的時候,他們也知道np代表的就是Numpy,所以縮寫最好不要自己創新。
import numpy as np
2. 使用Aarry建立陣列
2.1 通過Array傳遞List
標準Python的列表(list)中,元素本質是物件。
如:L = [1, 2, 3],需要3個指標和三個整數物件,對於數值運算比較浪費記憶體和CPU。
因此,Numpy提供了ndarray(N-dimensional array object)物件:儲存單一資料型別的多維陣列。
建立一維陣列:
L = [1, 2, 3, 4, 5, 6]
print L
a = np.array(L)
print a
列印結果:
[1, 2, 3, 4, 5, 6] [1 2 3 4 5 6]
建立多維陣列:
巢狀多個list
b = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
print b
列印結果:
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]
2.2 陣列大小
檢視陣列大小
print a.shape
print b.shape
列印結果:
a是6行1列,b是3行4列
(6L,)
(3L, 4L)
強制修改陣列大小
1.將3*4的陣列改成4*3的陣列
b.shape = 4, 3
print b
列印結果:
從(3,4)改為(4,3)並不是對陣列進行轉置,而只是改變每個軸的大小,陣列元素在記憶體中的位置並沒有改變,還是按照1,2,3,4,5…12這樣的順序來排列的。
[[ 1 2 3]
[ 4 5 6]
[ 7 8 9]
[10 11 12]]
2.當某個軸為-1時,將根據陣列元素的個數自動計算此軸的長度
b.shape = 2, -1
print b
列印結果:
行是2行,列為-1的話就表示根據行來定,所以是6列
[[ 1 2 3 4 5 6]
[ 7 8 9 10 11 12]]
修改陣列大小後成新陣列
使用reshape方法,可以建立改變了尺寸的新陣列,原陣列的shape保持不變
c = b.reshape((4, -1))
print c
建立的新陣列,仍然與老陣列共享記憶體,修改任意一個將影響另外一個。
比如修改b陣列的第1行第2列的元素為20,再來看b和c兩個陣列的變化
2.3 獲取陣列的元素型別
檢視資料型別
print a.dtype
print b.dtype
建立指定元素型別的陣列
可以通過dtype引數在建立時指定元素型別
d = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]], dtype=np.float)
f = np.array([[1+4j, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]], dtype=np.complex)
print d
print f
列印結果:分別是浮點型與複數型
[[ 1. 2. 3. 4.]
[ 5. 6. 7. 8.]
[ 9. 10. 11. 12.]]
[[ 1.+4.j 2.+0.j 3.+0.j 4.+0.j]
[ 5.+0.j 6.+0.j 7.+0.j 8.+0.j]
[ 9.+0.j 10.+0.j 11.+0.j 12.+0.j]]
更改元素型別
如果更改元素型別,可以使用astype安全的轉換
f = d.astype(np.int)
print f
列印結果:
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]
3. 使用函式建立
3.1 arrage
如果生成一定規則的資料,可以使用NumPy提供的專門函式
arange函式類似於python的range函式:指定起始值、終止值和步長來建立陣列
和Python的range類似,arange同樣不包括終值;但arange可以生成浮點型別,而range只能是整數型別
生成1開始,10結束(不包含10),步長為0.5的一個數組
a = np.arange(1, 10, 0.5)
print a
列印結果:
[ 1. 1.5 2. 2.5 3. 3.5 4. 4.5 5. 5.5 6. 6.5 7. 7.5 8.
8.5 9. 9.5]
3.2 linespace
linspace函式通過指定起始值、終止值和元素個數來建立陣列,預設包括終止值
b = np.linspace(1, 10, 10)
print b
列印結果:生成了一個1到10,步長為1的等差數列,並且時前閉後閉的。
[ 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]
可以通過endpoint關鍵字指定是否包括終值 ,預設是包括的。
c = np.linspace(1, 10, 10, endpoint=False)
print c
列印結果:生成了1到9的10個等差數列
[ 1. 1.9 2.8 3.7 4.6 5.5 6.4 7.3 8.2 9.1]
3.3 logspace
和linspace類似,logspace可以建立等比數列
下面函式建立起始值為10^1,終止值為10^2,有20個數的等比數列
d = np.logspace(1, 2, 20, endpoint=False)
print d
列印結果:
[ 10. 11.22018454 12.58925412 14.12537545 15.84893192
17.7827941 19.95262315 22.38721139 25.11886432 28.18382931
31.6227766 35.48133892 39.81071706 44.66835922 50.11872336
56.23413252 63.09573445 70.79457844 79.43282347 89.12509381]
下面建立起始值為2^0,終止值為2^10(不包括),有10個數的等比數列
f = np.logspace(0, 10, 11, endpoint=True, base=2)
print f
列印結果:
[ 1.00000000e+00 2.00000000e+00 4.00000000e+00 8.00000000e+00
1.60000000e+01 3.20000000e+01 6.40000000e+01 1.28000000e+02
2.56000000e+02 5.12000000e+02 1.02400000e+03]
3.4 frombuffer, fromstring, fromfile
使用 frombuffer, fromstring, fromfile等函式可以從位元組序列建立陣列
s = 'ABCDZ'
g = np.fromstring(s, dtype=np.int8)
列印結果:
[65 66 67 68 90]
4. 存取
4.1 常規辦法
陣列元素的存取方法和Python的標準方法相同
首先我們使用arange建立一個數組a
a = np.arange(10)
[0 1 2 3 4 5 6 7 8 9]
獲取某個元素
print a[3]
獲取索引為3的元素
3
獲取一組元素,切片[3,6),左閉右開
print a[3:6]
[3 4 5]
省略開始下標,表示從0開始
print a[:5]
[0 1 2 3 4]
下標為負表示從後向前數
print a[3:]
[3 4 5 6 7 8 9]
取索引[1,8)步長為2
print a[1:8:2]
[1 3 5 7]
步長為-1,即翻轉
print a[::-1]
[9 8 7 6 5 4 3 2 1 0]
切片資料是原陣列的一個檢視,與原陣列共享內容空間,可以直接修改元素
a[1:4] = 10, 20, 30
print a
[ 0 10 20 30 4 5 6 7 8 9]
4.2 整數陣列的存取
根據整數陣列存取:當使用整數序列對陣列元素進行存取時,
將使用整數序列中的每個元素作為下標,整數序列可以是列表(list)或者陣列(ndarray)。
使用整數序列作為下標獲得的陣列不和原始陣列共享資料空間。
//建立兩個陣列
a = np.logspace(0, 9, 10, base=2)
print a
i = np.arange(0, 10, 2)
print i
//利用i取a中的元素
b = a[i]
print b
列印結果
[ 1. 2. 4. 8. 16. 32. 64. 128. 256. 512.]
[0 2 4 6 8]
[ 1. 4. 16. 64. 256.]
//b的元素更改,a中元素不受影響
b[2] = 1.6
print b
print a
列印結果:b變了,a不變
[ 1. 4. 1.6 64. 256. ]
[ 1. 2. 4. 8. 16. 32. 64. 128. 256. 512.]
4.3 布林陣列的存取
使用布林陣列i作為下標存取陣列a中的元素:返回陣列a中所有在陣列b中對應下標為True的元素
首先生成10個滿足[0,1)中均勻分佈的隨機數
a = np.random.rand(10)
print a
[ 0.84334711 0.54587789 0.41350371 0.73992619 0.00475762 0.0972838
0.0522206 0.6696739 0.33550459 0.64959176]
大於0.5的元素索引
print a > 0.5
[ True True False True False False False True False True]
大於0.5的元素,打印出了一組布林型別的值,符合條件的為true
b = a[a > 0.5]
print b
[ 0.84334711 0.54587789 0.73992619 0.6696739 0.64959176]
將原陣列中大於0.5的元素擷取成0.5
a[a > 0.5] = 0.5
print a
//b不受影響
print b
[ 0.5 0.5 0.41350371 0.5 0.00475762 0.0972838
0.0522206 0.5 0.33550459 0.5 ]
[ 0.84334711 0.54587789 0.73992619 0.6696739 0.64959176]
4.4 二維陣列的切片
生成二維陣列
若我們想生成以下這樣一個多維陣列:
[[ 0 1 2 3 4 5]
[10 11 12 13 14 15]
[20 21 22 23 24 25]
[30 31 32 33 34 35]
[40 41 42 43 44 45]
[50 51 52 53 54 55]]
可以經過以下幾步
先生成行向量,0到60,步長為10的陣列。
a = np.arange(0, 60, 10)
[ 0 10 20 30 40 50]
將行向量,轉化成列向量
b = a.reshape(-1, 1)
[[ 0]
[10]
[20]
[30]
[40]
[50]]
生成一個0到5,步長為1的行向量
c = np.arange(6)
[0 1 2 3 4 5]
將列向量b每一列都c行向量
f = b + c
print f
[[ 0 1 2 3 4 5]
[10 11 12 13 14 15]
[20 21 22 23 24 25]
[30 31 32 33 34 35]
[40 41 42 43 44 45]
將上面所有步驟合起來可以用一句程式碼表示:
a = np.arange(0, 60, 10).reshape((-1, 1)) + np.arange(6)
二維陣列的切片
//大括號裡,前面的list表示行的索引,後面的list表示列的索引
//比如第一個數提取的是行索引為0列索引為2
print a[(0,1,2,3), (2,3,4,5)]
//獲取行號從3開始(包括3),列號是0,2,5的元素
print a[3:, [0, 2, 5]]
//建立布林型別的陣列
i = np.array([True, False, True, False, False, True])
//獲取為true的行
print a[i]
//獲取為true的行的列索引為3的元素
print a[i, 3]
列印結果:
[ 2 13 24 35]
[[30 32 35]
[40 42 45]
[50 52 55]]
[[ 0 1 2 3 4 5]
[20 21 22 23 24 25]
[50 51 52 53 54 55]]
[ 3 23 53]
5. 繪圖
5.1 繪製正態分佈概率密度函式
mu = 2 //均值
sigma = 32 //標準差
//建立一個50個元素的陣列,收尾與均值相差三個標準差
x = np.linspace(mu - 3 * sigma, mu + 3 * sigma, 50)
//根據正太分佈的公式寫出y
y = np.exp(-(x - mu) ** 2 / (2 * sigma ** 2)) / (math.sqrt(2 * math.pi) * sigma)
//以x,y為橫縱座標,'r-'表示紅色線,'ro-表示紅色線加原點',linewidth為線的粗細度
#plot.plot(x, y, 'ro-', linewidth=2)
//或者也可以:用'go'表示綠色原點,markersize為原點大小
plot.plot(x, y, 'r-', x, y, 'go', linewidth=2, markersize=8)
//有灰色格子
plot.grid(True)
//畫出來吧,少年!
plot.show()
圖形如下:
接下去,我們再來看幾個好玩的畫圖案例
5.2 損失函式:Logistic損失(-1,1)/SVM Hinge損失/ 0/1損失
x = np.linspace(-3, 3, 1000)
y_logit = np.log(1 + np.exp(-x)) / math.log(2)
y_01 = x < 0
y_hinge = 1 - x
y_hinge[y_hinge < 0] = 0
//label表示標記
plot.plot(x, y_logit, 'r-', label='Logistic Loss', linewidth=2)
plot.plot(x, y_01, 'g-', label='0/1 Loss', linewidth=2)
plot.plot(x, y_hinge, 'b-', label='Hinge Loss', linewidth=2)
plot.grid()
//標記的放的位置,這裡是右上角
plot.legend(loc='upper right')
plot.show()
圖形畫出來如下:
5.3 x^x
x = np.linspace(-1.3, 1.3, 101)
y = f(x)
plot.plot(x, y, 'g-', label='x^x', linewidth=2)
plot.grid()
plot.legend(loc='upper right')
plot.show()
5.4 胸型線
(前方高能。。。)
x = np.arange(1, 0, -0.001)
y = (-3 * x * np.log(x) + np.exp(-(40 * (x - 1 / np.e)) ** 4) / 25) / 2
//設定畫布大小
plot.figure(figsize=(5,7))
plot.plot(y, x, 'r-', linewidth=2)
plot.grid(True)
plot.show()
這個圖太辣眼睛了。。。男生心裡估計已經浮現過ABCDEF了。。
5.5 心形線
t = np.linspace(0, 7, 100)
x = 16 * np.sin(t) ** 3
y = 13 * np.cos(t) - 5 * np.cos(2*t) - 2 * np.cos(3*t) - np.cos(4*t)
plot.plot(x, y, 'r-', linewidth=2)
plot.grid(True)
plot.show()
嗯,這個圖美,願大家有情人終成眷屬
5.6 漸開線
t = np.linspace(0, 50, num=1000)
x = t*np.sin(t) + np.cos(t)
y = np.sin(t) - t*np.cos(t)
plot.plot(x, y, 'r-', linewidth=2)
plot.grid()
plot.show()
關於畫函式圖,總結規律,其實就是,設定一個x的變數,然後根據某種公式用x得到y的分佈,然後把x,y用Plot函式套進去,什麼顏色啊,圓點啊,線條粗細啊之類的都可以套模板寫。棒棒棒!