Numpy 介紹


In [ ]:
# 起手式
import numpy as np

建立 ndarray


In [ ]:
np.array([1,2,3,4])

In [ ]:
x = _

In [ ]:
y = np.array([[1.,2,3],[4,5,6]])
y

看 ndarray 的第一件事情: shape , dtype


In [ ]:
x.shape

In [ ]:
y.shape

In [ ]:
x.dtype

In [ ]:
y.dtype

有時候,可以看圖


In [ ]:
# import matplotlib
%matplotlib inline
import matplotlib.pyplot as plt
# 畫圖
plt.plot(x, 'x');

有很多其他建立的方式


In [ ]:
# 建立 0 array
np.zeros_like(y)

In [ ]:
np.zeros((10,10))

In [ ]:
# 跟 range 差不多
x = np.arange(0, 10, 0.1)
# 亂數
y = np.random.uniform(-1,1, size=x.shape)
plt.plot(x, y)

這是一堆資料

  • 資料有什麼資訊?
  • 資料有什麼限制?
  • 這些限制有什麼意義?好處?
  • 以前碰過什麼類似的東西?
  • 可以套用在哪些東西上面?
  • 可以怎麼用(運算)?

最簡單的計算是 逐項計算 see also np.vectorize


In [ ]:
x = np.linspace(0, 2* np.pi, 1000)
plt.plot(x, np.sin(x))

Q0:

畫出 $y=x^2+1$ 或其他函數的圖形 用

plt.plot?

看看 plot 還有什麼參數可以玩


In [ ]:
#可以用 %run -i 跑參考範例
%run -i q0.py

In [ ]:
# 或者看看參考範例
#%load q0.py

Q1:

試試看圖片。 使用

from PIL import Image
# 讀入 PIL Image (這張圖是從 openclipart 來的 cc0)
img = Image.open('img/Green-Rolling-Hills-Landscape-800px.png')
# 圖片轉成 ndarray
img_array = np.array(img)
# ndarray 轉成 PIL Image
Image.fromarray(img_array)

看看這個圖片的內容, dtype 和 shape


In [ ]:
# 參考答案
#%load q1.py

Indexing

可以用類似 list 的 indexing


In [ ]:
a = np.arange(30)
a

In [ ]:
a[5]

In [ ]:
a[3:7]

In [ ]:
# 列出所有奇數項
a[1::2]

In [ ]:
# 還可以用來設定值
a[1::2]  = -1
a

In [ ]:
# 或是
a[1::2] = -a[::2]-1
a

Q2

給定

x = np.arange(30)
a = np.arange(30)
a[1::2] = -a[1::2]

畫出下面的圖


In [ ]:
%run -i q2.py
#%load q2.py

ndarray 也可以


In [ ]:
b = np.array([[1,2,3], [4,5,6], [7,8,9]])
b

In [ ]:
b[1][2]

In [ ]:
b[1,2]

In [ ]:
b[1]

Q3

動手試試看各種情況 比方

b = np.random.randint(0,99, size=(10,10))
b[::2, 2]

Fancy indexing


In [ ]:
b = np.random.randint(0,99, size=(5,10))
b

試試看下面的結果

想一下是怎麼一回事(numpy 在想什麼?)


In [ ]:
b[[1,3]]

In [ ]:
b[(1,3)]

In [ ]:
b[[1,2], [3,4]]

In [ ]:
b[[(1,2),(3,4)]]

In [ ]:
b[[True, False, False, True, False]]

Q4

b 中的偶數都變成 -1


In [ ]:
#參考範例
%run -i q4.py

用圖形來練習


In [ ]:
# 還記得剛才的
from PIL import Image
img = Image.open('img/Green-Rolling-Hills-Landscape-800px.png')
img_array = np.array(img)
Image.fromarray(img_array)

In [ ]:
# 用來顯示圖片的函數
from IPython.display import display
def show(img_array):
    display(Image.fromarray(img_array))

Q

  • 將圖片縮小成一半
  • 擷取中間一小塊
  • 圖片上下顛倒
  • 左右鏡射
  • 去掉綠色
  • 將圖片放大兩倍
  • 貼另外一張圖到大圖中
    from urllib.request import urlopen
    url = "https://raw.githubusercontent.com/playcanvas/engine/master/examples/images/animation.png"
    simg = Image.open(urlopen(url))
    
  • 紅綠交換
  • 團片變成黑白 參考 Y=0.299R+0.587G+0.114B
    • 會碰到什麼困難? 要如何解決

In [ ]:
# 將圖片縮小成一半
%run -i q_half.py

In [ ]:
# 將圖片放大
%run -i q_scale2.py

In [ ]:
# 圖片上下顛倒
show(img_array[::-1])

In [ ]:
%run -i q_paste.py

In [ ]:
%run -i q_grayscale.py

Q

  • 挖掉個圓圈? (300,300)中心,半徑 100
  • 旋轉九十度? x,y 互換?

In [ ]:
# 用迴圈畫圓
%run -i q_slow_circle.py

In [ ]:
# 用 fancy index 畫圓
%run -i q_fast_circle.py

indexing 的其他用法


In [ ]:
# 還可以做模糊化
a = img_array.astype(float)
for i in range(10):
    a[1:,1:] = (a[1:,1:]+a[:-1,1:]+a[1:,:-1]+a[:-1,:-1])/4
show(a.astype('uint8'))

In [ ]:
# 求邊界
a = img_array.astype(float)
a = a @ [0.299, 0.587, 0.114, 0]
a = np.abs((a[1:]-a[:-1]))*2
show(a.astype('uint8'))

Reshaping

.flatten 拉平看看資料在電腦中如何儲存?

查看 .reshape, .T, np.rot00, .swapaxes .rollaxis 然後再做一下上面的事情


In [ ]:
# reshaping 的應用
R,G,B,A = img_array.reshape(-1,4).T
plt.hist((R,G,B,A), color="rgby");

堆疊在一起

查看 np.vstack np.hstack np.concatenate 然後試試看


In [ ]:
# 例子
show(np.hstack([img_array, img_array2]))

In [ ]:
# 例子
np.concatenate([img_array, img_array2], axis=2).shape

作用在整個 array/axis 的函數


In [ ]:
np.max([1,2,3,4])

In [ ]:
np.sum([1,2,3,4])

In [ ]:
np.mean([1,2,3,4])

In [ ]:
np.min([1,2,3,4])

多重意義的運用, 水平平均,整合垂直平均


In [ ]:
x_mean = img_array.astype(float).min(axis=0, keepdims=True)
print(x_mean.dtype, x_mean.shape)
y_mean = img_array.astype(float).min(axis=1, keepdims=True)
print(y_mean.dtype, y_mean.shape)
# 自動 broadcast 
xy_combined = ((x_mean+y_mean)/2).astype('uint8')
show(xy_combined)

Tensor 乘法

先從點積開始


In [ ]:
# = 1*4 + 2*5 + 4*6
np.dot([1,2,3], [4,5,6])

In [ ]:
u=np.array([1,2,3])
v=np.array([4,5,6])
print( u@v )
print( (u*v).sum() )

矩陣乘法

如果忘記矩陣乘法是什麼了, 參考這裡 http://matrixmultiplication.xyz/ 或者 http://eli.thegreenplace.net/2015/visualizing-matrix-multiplication-as-a-linear-combination/

矩陣乘法可以看成是:

  • 所有組合(其他軸)的內積(共有軸)
  • 多個行向量線性組合
  • 代入線性方程式 A1-矩陣與基本列運算.ipynb
  • 用 numpy 來理解
    np.sum(a[:,:, np.newaxis] * b[np.newaxis, : , :], axis=1)
    dot(a, b)[i,k] = sum(a[i,:] * b[:, k])
    

高維度

要如何推廣?

  • tensordot, tensor contraction, a.shape=(3,4,5), b.shape=(4,5,6), axis = 2 時等價於

    np.sum(a[..., np.newaxis] * b[np.newaxis, ...], axis=(1, 2))
    tensordot(a,b)[i,k]=sum(a[i, ...]* b[..., k])
    

    https://en.wikipedia.org/wiki/Tensor_contraction

  • dot

    dot(a, b)[i,j,k,m] = sum(a[i,j,:] * b[k,:,m])
    np.tensordot(a,b, axes=(-1,-2))
    
  • matmul 最後兩個 index 當成 matrix
    a=np.random.random(size=(3,4,5))
    b=np.random.random(size=(3,5,7))
    (a @ b).shape
    np.sum(a[..., np.newaxis] * np.moveaxis(b[..., np.newaxis], -1,-3), axis=-2)
    
  • einsum https://en.wikipedia.org/wiki/Einstein_notation
    np.einsum('ii', a) # trace(a)
    np.einsum('ii->i', a) #diag(a)
    np.einsum('ijk,jkl', a, b) # tensordot(a,b)
    np.einsum('ijk,ikl->ijl', a,b ) # matmul(a,b)
    

In [28]:
A=np.random.randint(0,10, size=(5,3))
A


Out[28]:
array([[9, 6, 4],
       [4, 6, 7],
       [5, 4, 6],
       [8, 3, 1],
       [7, 6, 1]])

In [29]:
B=np.random.randint(0,10, size=(3,7))
B


Out[29]:
array([[7, 0, 8, 9, 9, 3, 3],
       [5, 9, 0, 0, 7, 8, 8],
       [1, 0, 9, 2, 6, 1, 8]])

In [94]:
A.dot(B)


Out[94]:
array([[ 97,  54, 108,  89, 147,  79, 107],
       [ 65,  54,  95,  50, 120,  67, 116],
       [ 61,  36,  94,  57, 109,  53,  95],
       [ 72,  27,  73,  74,  99,  49,  56],
       [ 80,  54,  65,  65, 111,  70,  77]])

Q

  • 手動算算看 A,B 的 dot
  • 試試看其他的乘法

小結

numpy 以 ndarray 為中心

  • 最基本的運算是逐項運算(用 np.vectorize把一般的函數變成逐項運算 )
  • indexing 很好用
  • reshaping
  • 整合的操作與計算