1. 程式人生 > >python資料分析 -- numpy庫初識

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()

圖形如下:
QQ截圖20160905162243.png-25.9kB

接下去,我們再來看幾個好玩的畫圖案例

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()

圖形畫出來如下:
QQ截圖20160905162424.png-29.9kB

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()

QQ截圖20160905162629.png-26.1kB

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了。。
QQ截圖20160905162940.png-19.3kB

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()

嗯,這個圖美,願大家有情人終成眷屬
QQ截圖20160905163213.png-23.7kB

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()

QQ截圖20160905163233.png-49.4kB

關於畫函式圖,總結規律,其實就是,設定一個x的變數,然後根據某種公式用x得到y的分佈,然後把x,y用Plot函式套進去,什麼顏色啊,圓點啊,線條粗細啊之類的都可以套模板寫。棒棒棒!