1. 程式人生 > >cs231n---Python Numpy教程(第二彈)

cs231n---Python Numpy教程(第二彈)

Numpy庫:它提供了高效能的多維陣列物件,以及相關工具。

陣列array

一個numpy陣列是一個由不同數值組成的網格。網格中的資料都是同一種資料型別,可以通過非負整型數的元組來訪問。

維度的數量成為陣列的。陣列大小是一個由整型數構成的元組,可以描述陣列不同維度上的大小。

從列表建立陣列,利用方括號[]訪問其中元素:

# 陣列array
import numpy as np

a = np.array([1, 2, 3])# creat a rank 1 array  1階陣列
print(a) # [1 2 3]
print(type(a)) # <class 'numpy.ndarray'>
print(a.shape) # (3,)
print(a[0], a[1], a[2])  # 1 2 3
a[0] = 5
print(a)  # [5 2 3]

b = np.array([[1,2,3],[4,5,6]])# creat a rank 2 array  2階陣列
print(b)
# [[1 2 3]
#  [4 5 6]]
print(b.shape)  # (2, 3)
print(b[0,0], b[0,1], b[1,0])  # 1 2 4

Numpy還提供了其他建立陣列的方法:

import numpy as np

a = np.zeros((2,2))  # 生成全為0的陣列array
print(a)
# [[ 0.  0.]
#  [ 0.  0.]]

b = np.ones((1,2))  # 生成全為1的陣列array
print(b)
# [[ 1.  1.]]

c = np.full((2,2), 8) # 常數均為8的2x2陣列
print(c)
# [[8 8]
#  [8 8]]

d = np.eye(2)  # 單位矩陣identity matrix
print(d)
# [[ 1.  0.]
#  [ 0.  1.]]

e = np.random.random((2,2))
print(e)
# [[ 0.46699318  0.2937788 ]
#  [ 0.35273887  0.30353399]]

訪問陣列

切片:與python列表類似,numpy陣列可以使用切片語法。而陣列是多維的,所以必須為每個維度指定好切片。

# 建立一個2維3x4的陣列 create the following rank 2 array with shape (3, 4)
# [[ 1  2  3  4]
#  [ 5  6  7  8]
#  [ 9 10 11 12]]
a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])

# 使用切片選出行索引2前(不包含2)即index=0,1,第一行第二行
# 選擇出索引1,2(不包含3)即第二,三列
# [[2 3]
#  [6 7]]
b = a[:2, 1:3]

print(a[0,1])  # 2

b[0,0] = 88  # b[0,0]等價於a[0,1]:b[0,0] is the same piece of data as a[0,1]
print(a)
# [[ 1 88  3  4]
#  [ 5  6  7  8]
#  [ 9 10 11 12]]
print(a[0,1])  # 88

可以同時使用整型和切片語法來訪問陣列,但,這樣會產生一個比原陣列低階的新陣列。

a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])

row_r1 = a[1, :]
row_r2 = a[1:2, :]
print(row_r1, row_r1.shape) # [5 6 7 8] (4,)
print(row_r2, row_r2.shape) # [[5 6 7 8]] (1, 4)

col_r1 = a[:, 1]
col_r2 = a[:, 1:2]
print(col_r1, col_r1.shape) # [ 2  6 10] (3,)
print(col_r2, col_r2.shape) 
# [[ 2]
#  [ 6]
#  [10]] (3, 1)
整型陣列訪問:使用切片語法訪問陣列時,得到的總是原陣列的一個子集。整型陣列訪問我們利用其它陣列的資料構建一個新的陣列:
import numpy as np
a = np.array([[1,2], [3,4], [5,6]])
# [[1 2]
#  [3 4]
#  [5 6]]

# 整型陣列訪問
print(a[[0,1,2], [0,1,0]])  # [1 4 5]
#等價於
print(np.array([a[0,0], a[1,1], a[2,0]]))

print(a[[0,0], [1,1]]) # [2 2]
# 等價於
print(np.array([a[0,1], a[0,1]]))

整型陣列還可以選擇或更改矩陣中每行的一個元素:

import numpy as np

a = np.array([[1,2,3], [4,5,6], [7,8,9], [10,11,12]])
print(a)
# [[ 1  2  3]
#  [ 4  5  6]
#  [ 7  8  9]
#  [10 11 12]]
b = np.array([0,2,0,1]) # 建立一個數組索引

# 選取每行對應b中索引的元素
print(np.arange(4)) # [0 1 2 3]
print(a[np.arange(4), b]) # [ 1  6  7 11]

a[np.arange(4), b] += 10
print(a)
# [[11  2  3]
#  [ 4  5 16]
#  [17  8  9]
#  [10 21 12]]
布林型陣列訪問:布林型陣列訪問可以選擇陣列中任意元素。通常,這種訪問方式用於選取陣列中滿足某些條件的元素:
# 布林型陣列訪問
import numpy as np


a = np.array([[1, 2], [3, 4], [5, 6]])


bool_idx = (a > 2) # 找到陣列a中比2大的元素
print(bool_idx)
# [[False False]
#  [ True  True]
#  [ True  True]]


print(a[bool_idx])
# [3 4 5 6]


print(a[a > 2])  # [3 4 5 6]

資料型別

每個numpy陣列都是資料型別相同的元素組成的網格。當建立陣列時,numpy會猜測陣列的資料型別,我們可以通過引數直接指定資料:

# 資料型別
import numpy as np

x = np.array([1, 2])
print(x.dtype)

x = np.array([1.0, 2.0])
print(x.dtype)

# x = np.array([1, 2], dtype=np.int64)
# print(x.dtype) # for python2 is ok,but python3 is false

陣列計算

基本數學計算函式會對陣列中的元素逐個進行計算,既可以利用操作符過載,也可以使用函式方式:

# 陣列計算
import numpy as np

x = np.array([[1,2], [3,4]])
y = np.array([[5,6], [7,8]])

print(x + y)
print(np.add(x, y))
# [[ 6  8]
#  [10 12]]

print(x - y)
print(np.subtract(x, y))
# [[-4 -4]
#  [-4 -4]]

print(x * y)
print(np.multiply(x, y))
# [[ 5 12]
#  [21 32]]

print(x / y)
print(np.divide(x, y))
# [[ 0.2         0.33333333]
#  [ 0.42857143  0.5       ]]

print(np.sqrt(x))
# [[ 1.          1.41421356]
#  [ 1.73205081  2.        ]]
和matlab不同, * 是元素逐個相乘,不是矩陣乘法。numpy中使用dot來進行矩陣乘法
# 陣列的元素逐個相乘以及矩陣乘法
import numpy as np

x = np.array([[1,2], [3,4]])
y = np.array([[5,6], [7,8]])

v = np.array([9, 10])
w = np.array([11,12])

print(v.dot(w))
print(np.dot(v, w))
# 219

print(x.dot(v))
print(np.dot(x, v))
# [29 67]

print(x.dot(y))
print(np.dot(x, y))
# [[19 22]
#  [43 50]]

numpy提供了很多計算陣列的函式,其中最常用的一個是sum:

# sum函式
import numpy as np

x = np.array([[1,2], [3,4]])
# [[1 2]
#  [3 4]]

print(np.sum(x)) # 10 即陣列中所有元素之和
print(np.sum(x, axis=0)) # [4 6] 陣列中每列(axis=0)元素相加
print(np.sum(x, axis=1)) # [3 7] 陣列中每行(axis=1)元素相加
除了計算,還需改變陣列或者操作其中的元素。其中numpy中用 T 將矩陣轉置
# 轉置T
import numpy as np

x = np.array([[1,2], 
              [3,4]])
print(x)
# [[1 2]
#  [3 4]]
print(x.T)
# [[1 3]
#  [2 4]]

v = np.array([1,2,3]) # 對一維陣列不起作用
print(v) # [1 2 3]
print(v.T) # [1 2 3]

廣播broadcasting

廣播是一種強有力的機制,它使Numpy可以讓不同大小的矩陣在一起進行數學計算。我們常會有一個小的矩陣和一個大的矩陣,然後需要用小的矩陣對大的矩陣做一些計算。

# baseline for迴圈
import numpy as np

# We will add the vector v to each row of the matrix x, 
# storing the result in the matrix y
x = np.array([[1,2,3], [4,5,6], [7,8,9], [10,11,12]])
v = np.array([1, 0, 1])
y = np.empty_like(x) # 建立一個空矩陣大小和x一樣 create an empty matrix with the same shape as x
print(y)
# [[0 0 0]
#  [0 0 0]
#  [0 0 0]
#  [0 0 0]]

# Add the vector v to each row of the matrix x with an explicit  
for i in range(4):
    y[i, :] = x[i, :] + v

print(y)
# [[ 2  2  4]
#  [ 5  5  7]
#  [ 8  8 10]
#  [11 11 13]]

以上是baseline,但是當x矩陣非常大的時候,迴圈的計算就會很慢,我們換成矩陣的思路:

# 矩陣思路
import numpy as np
x = np.array([[1,2,3], [4,5,6], [7,8,9], [10,11,12]])
v = np.array([1, 0, 1])
vv = np.tile(v, (4, 1))  # Stack 4 copies of v on top of each other 拓展
print(vv)
# [[1 0 1]
#  [1 0 1]
#  [1 0 1]
#  [1 0 1]]

y = x + vv
print(y)
# [[ 2  2  4]
#  [ 5  5  7]
#  [ 8  8 10]
#  [11 11 13]]

numpy廣播機制可以讓我們不用建立vv,直接運算:

# 廣播機制
import numpy as np

x = np.array([[1,2,3], [4,5,6], [7,8,9], [10,11,12]])
v = np.array([1, 0, 1])
y = x + v
print(y)
# [[ 2  2  4]
#  [ 5  5  7]
#  [ 8  8 10]
#  [11 11 13]]

對兩個陣列使用廣播機制要遵守下列規則:

  1. 如果陣列的秩不同,使用1來將秩較小的陣列進行擴充套件,直到兩個陣列的尺寸的長度都一樣。
  2. 如果兩個陣列在某個維度上的長度是一樣的,或者其中一個數組在該維度上長度為1,那麼我們就說這兩個陣列在該維度上是相容的。
  3. 如果兩個陣列在所有維度上都是相容的,他們就能使用廣播。
  4. 如果兩個輸入陣列的尺寸不同,那麼注意其中較大的那個尺寸。因為廣播之後,兩個陣列的尺寸將和那個較大的尺寸一樣。
  5. 在任何一個維度上,如果一個數組的長度為1,另一個數組長度大於1,那麼在該維度上,就好像是對第一個陣列進行了複製。

如果上述解釋看不明白,可以讀一讀文件和這個解釋譯者注:強烈推薦閱讀文件中的例子。

下面是一些廣播機制的使用:

# examples
import numpy as np

v = np.array([1,2,3]) # v has shape (3,)

w = np.array([4,5]) # w has shape (2,)
# To compute an outer product, we first reshape v to be a column
# vector of shape (3, 1); we can then broadcast it against w to yield

print(np.reshape(v, (3, 1))) # 變成3行一列
# [[1]
#  [2]
#  [3]]

# an output of shape (3, 2), which is the outer product of v and w:
print(np.reshape(v, (3, 1)) * w)
# [[ 4  5]
#  [ 8 10]
#  [12 15]]

x = np.array([[1,2,3], 
              [4,5,6]])

print(x * 2)
# [[ 2  4  6]
#  [ 8 10 12]]

print(x + v)
# [[2 4 6]
#  [5 7 9]]

print(x.T)
# [[1 4]
#  [2 5]
#  [3 6]]

print((x.T + w).T)
# [[ 5  6  7]
#  [ 9 10 11]]

print(np.reshape(w, (2,1))) 
# [[4]
#  [5]]

print(x + np.reshape(w, (2,1)))
# [[ 5  6  7]
#  [ 9 10 11]]

Numpy文件

這篇教程涉及了你需要了解的numpy中的一些重要內容,但是numpy遠不止如此。可以查閱numpy文獻來學習更多。

以上內容轉載整理來自知乎專欄點選開啟連結,侵刪侵刪。