[資料分析基礎] 1. NumPy庫
文章目錄
-
- [資料分析基礎] 1. NumPy庫
-
-
- 一、NumPy的數組對象:ndarray
-
- 1. ndarray對象的屬性
- 2. ndarray數組的元素類型
- 二、ndarray數組的建立和變換
-
- 1. 從清單、元組等類型中建立ndarray數組
- 2. 使用NumPy中函數建立ndarray數組
- 3. ndarray數組的次元變換
- 4. ndarray數組的類型變換
- 三、ndarray數組的操作與運算
-
- 1. 數組的索引和切片
- 2. NumPy一進制函數
- 3. NumPy二進制函數
- 四、Numpy中檔案的存取
-
- 1. 資料的CSV檔案存取
- 2. 多元資料的存取
- 3. NumPy的便捷檔案存取
- 五、NumPy的函數
-
- 1. NumPy的随機數函數
- 2. NumPy的統計函數
- 3. NumPy的梯度函數
- 六、執行個體:圖像的手繪效果
-
- 1. 圖像的數組表示
- 2. 圖像的變換
- 3. 圖像的手繪效果
-
- 3.1 梯度的重構
- 3.2 光源效果
- 3.3 梯度歸一化
- 3.4 圖像生成
- 3.5 全代碼
-
Numpy是一個開源的python科學計算基礎庫,包含
- 一個強大的N維數組對象ndarry
- 廣播功能函數
- 整合C/C++/Fortran代碼的工具
- 線性代數、傅裡葉變換、随機數生成等功能
NumPy是SciPy、Pandas等資料處理或科學計算庫的基礎
一、NumPy的數組對象:ndarray
問題:Python已有清單類型表示數組,為什麼需要一個數組對象(類型)?
計算 A 2 + B 3 A^2+B^3 A2+B3,其中,A和B是一維數組
- 普通方法
def pySum(): a=[0,1,2,3,4] b=[9,8,7,6,5] c=[] for i in range(len(a)): c.append(a[i]**2+b[i]**3) return c print(pySum())
- Numpy科學計算
import numpy as np #引入numpy子產品 def npSum(): a = np.array([0,1,2,3,4]) #生成一個數組 b = np.array([9,8,7,6,5]) c = a**2 + b**3 # '**' 數組中每個元素的次方 return c print(npSum())
- 使用ndarry的原因
- 數組對象可以去掉元素間運算所需的循環,使一維向量更像單個資料。
- 通過設定專門的數組對象,經過優化,可以提升這類應用的運算速度。
- 數組對象采用相同的資料類型,有助于節省運算和存儲空間。
ndarray是一個多元數組對象,由兩部分構成:
- 實際的資料
- 描述這些資料的中繼資料(資料次元、資料類型等)
ndarray數組一般要求所有元素類型相同(同質),數組下标從0開始。
1. ndarray對象的屬性
ndarray的兩個基本概念
- 軸(axis): 儲存資料的次元
- 秩(rank): 軸的數量
ndarray對象的屬性 | 說明 |
---|---|
| 秩,即軸的數量或次元的數量 |
| ndarray對象的尺度,對于矩陣,n行m列 |
| ndarray對象元素的個數,相當于.shape中的n*m的值 |
| ndarray對象的元素類型 |
| ndarray對象中每個元素的大小,以位元組為機關 |
#np.array()生成一個ndarray數組
#ndarray在程式中的别名是:array
>>> a=np.array([[0,1,2,3,4],[9,8,7,6,5]])
>>> a
array([[0, 1, 2, 3, 4],
[9, 8, 7, 6, 5]])
>>> print(a) #列印時元素由空格分割
[[0 1 2 3 4]
[9 8 7 6 5]]
>>> a.ndim
2
>>> a.shape
(2,5)
>>> a.size
10
>>> a.dtype
dtype('int32')
>>> a.itemsize
4
2. ndarray數組的元素類型
資料類型 | 說明 |
---|---|
bool | 布爾類型,True 或False |
intc | 與 C語言中的int類型一緻,一般是int32 或int64 |
intp | 用于索引的整數,與 C語言中ssize_t一緻,int32 或int64 |
int8 | 位元組長度的整數,取值: [ ‐128, 127] |
int16 | 16位長度的整數,取值: [ ‐32768, 32767] |
int32 | 32位長度的整數,取值: [ ‐ 231 , 231 ‐1] |
int64 | 64位長度的整數,取值: [ ‐ 263 , 263 ‐1] |
uint8 | 8位無符号整數,取值:[0, 255] |
uint16 | 16位無符号整數,取值:[0, 65535] |
uint32 | 32位無符号整數,取值:[0, 232 ‐1] |
uint64 | 32位無符号整數,取值:[0, 264 ‐1] |
float16 | 16位半精度浮點數: 1位符号位, 5位指數,10位尾數 |
float32 | 32位半精度浮點數: 1位符号位, 8位指數,23位尾數 |
float64 | 64位半精度浮點數: 1位符号位,11位指數,52位尾數 |
complex64 | 複數類型,實部和虛部都是32位浮點數 實部(.real) + j虛部(.imag) |
complex128 | 複數類型,實部和虛部都是64位浮點數 實部(.real) + j虛部(.imag) |
二、ndarray數組的建立和變換
1. 從清單、元組等類型中建立ndarray數組
① ndarray數組可由清單類型建立;② ndarray數組可由元組類型建立;③ ndarray數組可由清單和元組的混合類型建立(隻要他們元素個數相同)
x = np.array(list/tuple)
、
x = np.array(list/tuple, dtype=np.float32)
當 np.array() 不指定 dtype 時,NumPy 将根據資料情況關聯一個 dtype 類型
>>> x=np.array([0,1,2,3])
>>> print(x)
[0 1 2 3]
>>> x=np.array((4,5,6,7))
>>> print(x)
[4 5 6 7]
>>> x=np.array([[1,2],[9,8],(0.1,0.2)])
>>> print(x)
[[1. 2. ]
[9. 8. ]
[0.1 0.2]]
2. 使用NumPy中函數建立ndarray數組
函數 | 說明 |
---|---|
| 類似range()函數,傳回ndarray類型,元素從0到n-1 |
| 根據shape生成一個全1數組,shape是元組類型 |
| 根據shape生成一個全0數組,shape是元組類型 |
| 根據shape生成一個數組,每個元素值都是val |
| 建立一個正方的n*n機關矩陣,對角線為1,其餘為0 |
| 根據數組a的形狀生成一個全1的數組 |
| 根據數組a的形狀生成一個全0的數組 |
| 根據數組a的形狀狀生成一個數組,每個元素值都是val |
| 根據起止資料及元素個數等間距地填充資料,形成數組 如果将參數endpoint置為False,end将不作為最後一個元素出現 |
| 将兩個或多個數組合并成一個新數組, a為一個元組 |
除了arrange産生的不是浮點類型,其他都産生浮點類型
In [1]: import numpy as np
In [2]: np.arange(10)
Out[2]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [3]: np.ones((3,6))
Out[3]:
array([[1., 1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1., 1.]])
In [4]: np.zeros((3,6),dtype=np.int32)
Out[4]:
array([[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0]])
In [5]: np.eye(5)
Out[5]:
array([[1., 0., 0., 0., 0.],
[0., 1., 0., 0., 0.],
[0., 0., 1., 0., 0.],
[0., 0., 0., 1., 0.],
[0., 0., 0., 0., 1.]])
In [6]: x=np.ones((2,3,4))
In [7]: print(x)
[[[1. 1. 1. 1.]
[1. 1. 1. 1.]
[1. 1. 1. 1.]]
[[1. 1. 1. 1.]
[1. 1. 1. 1.]
[1. 1. 1. 1.]]]
In [8]: x.shape
Out[8]: (2, 3, 4)
In [10]: np.full(10,4)
Out[10]: array([4, 4, 4, 4, 4, 4, 4, 4, 4, 4])
In [12]: np.ones_like(x)
Out[12]:
array([[[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]],
[[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]]])
In [14]: np.zeros_like(x)
Out[14]:
array([[[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]],
[[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]]])
In [15]: np.full_like(x,6)
Out[15]:
array([[[6., 6., 6., 6.],
[6., 6., 6., 6.],
[6., 6., 6., 6.]],
[[6., 6., 6., 6.],
[6., 6., 6., 6.],
[6., 6., 6., 6.]]])
In [16]: a=np.linspace(1,10,4)
In [17]: a
Out[17]: array([ 1., 4., 7., 10.])
In [18]: b=np.linspace(1,10,4,endpoint=False)
In [19]: b
Out[19]: array([1. , 3.25, 5.5 , 7.75])
In [20]: c=np.concatenate((a,b))
In [21]: c
Out[21]: array([ 1. , 4. , 7. , 10. , 1. , 3.25, 5.5 , 7.75])
3. ndarray數組的次元變換
方法 | 說明 |
---|---|
| 不改變數組元素,傳回一個shape形狀的數組,原數組不變 |
| 與.reshape()功能一緻,但修改原數組 |
| 将數組 n個次元中兩個次元進行調換 |
| 對數組進行降維,傳回折疊後的一維數組,原數組不變 |
In [23]: a=np.ones((2,3,4),dtype=np.int32)
In [24]: a
Out[24]:
array([[[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]],
[[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]]])
In [25]: a.reshape((3,8))
Out[25]:
array([[1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1]])
In [26]: a
Out[26]:
array([[[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]],
[[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]]])
In [27]: a.resize((3,8))
In [28]: a
Out[28]:
array([[1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1]])
In [29]: a.flatten()
Out[29]:
array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1])
In [30]: a
Out[30]:
array([[1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1]])
In [31]: b=a.flatten()
In [32]: b
Out[32]:
array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1])
4. ndarray數組的類型變換
new_a = a.astype(new_type)
:
astype()
方法一定會建立新的數組(原始資料的一個拷貝),即使兩個類型一緻
ls = a.tolist()
:将ndarray數組轉換為清單形式
In [33]: a=np.ones((2,3,4),dtype=np.int)
In [34]: a
Out[34]:
array([[[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]],
[[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]]])
In [35]: b=a.astype(np.float)
In [36]: b
Out[36]:
array([[[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]],
[[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]]])
In [37]: a=np.full((2,3,4),25,dtype=np.int32)
In [38]: a
Out[38]:
array([[[25, 25, 25, 25],
[25, 25, 25, 25],
[25, 25, 25, 25]],
[[25, 25, 25, 25],
[25, 25, 25, 25],
[25, 25, 25, 25]]])
In [39]: a.tolist()
Out[39]:
[[[25, 25, 25, 25], [25, 25, 25, 25], [25, 25, 25, 25]],
[[25, 25, 25, 25], [25, 25, 25, 25], [25, 25, 25, 25]]]
三、ndarray數組的操作與運算
1. 數組的索引和切片
注意:索引和切片下标都是從0開始的
- 一維數組的索引和切片:起始編号: 終止編号(不含) : 步長
In [40]: a=np.array([9,8,7,6,5]) In [41]: a[2] Out[41]: 7 In [42]: a[1:4:2] #[1,4) Out[42]: array([8, 6])
- 多元數組的索引:每個次元一個索引值,逗号分割
In [43]: a=np.arange(24).reshape((2,3,4)) In [44]: a Out[44]: array([[[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]], [[12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]]]) In [45]: a[1,2,3] Out[45]: 23 In [46]: a[0,1,2] Out[46]: 6 In [47]: a[-1,-2,-3] Out[47]: 17
- 多元數組的切片:沒有選取具體次元,那麼可以用
表示所有次元。:
# 選取一個次元用 In [48]: a[:,1,-3] #限制行數為1,列數為-3 Out[48]: array([ 5, 17]) #每個次元切片方法與一維數組相同 In [49]: a[:,1:3,:] #限制行數為[1,3) Out[49]: array([[[ 4, 5, 6, 7], [ 8, 9, 10, 11]], [[16, 17, 18, 19], [20, 21, 22, 23]]]) #每個次元可以使用步長跳躍切片 In [50]: a[:,:,::2] #限制列數的步長為2 Out[50]: array([[[ 0, 2], [ 4, 6], [ 8, 10]], [[12, 14], [16, 18], [20, 22]]])
2. NumPy一進制函數
數組與标量之間的運算作用于數組的每一個元素
函數 | 說明 |
---|---|
np.abs(x) np.fabs(x) | 計算數組各元素的絕對值 |
np.sqrt(x) | 計算數組各元素的平方根 |
np.square(x) | 計算數組各元素的平方 |
np.log(x) np.log10(x) np.log2(x) | 計算數組各元素的自然對數、10底對數和 2底對數 |
np.ceil(x) np.floor(x) | 計算數組各元素的ceiling值 或 floor 值 |
np.rint(x) | 計算數組各元素的四舍五入值 |
np.modf(x) | 将數組各元素的小數和整數部分以兩個獨立數組形式傳回 |
np.cos(x) np.cosh(x) np.sin(x) np.sinh(x) np.tan(x) np.tanh(x) | 計算數組各元素的普通型和雙曲型三角函數 |
np.exp(x) | 計算數組各元素的指數值 |
np.sign(x) | 計算數組各元素的符号值,1(+), 0, ‐1( ‐ ) |
注意一進制函數都不會修改原數組,我們需要再次将它賦給原變量,如 a = np.square(a)
In [51]: a=np.arange(24).reshape((2,3,4))
In [52]: a
Out[52]:
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]],
[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]])
In [53]: a.mean()
Out[53]: 11.5
In [54]: a=a/a.mean()
In [55]: a
Out[55]:
array([[[0. , 0.08695652, 0.17391304, 0.26086957],
[0.34782609, 0.43478261, 0.52173913, 0.60869565],
[0.69565217, 0.7826087 , 0.86956522, 0.95652174]],
[[1.04347826, 1.13043478, 1.2173913 , 1.30434783],
[1.39130435, 1.47826087, 1.56521739, 1.65217391],
[1.73913043, 1.82608696, 1.91304348, 2. ]]])
In [56]: a=np.arange(24).reshape((2,3,4))
In [57]: np.square(a)
Out[57]:
array([[[ 0, 1, 4, 9],
[ 16, 25, 36, 49],
[ 64, 81, 100, 121]],
[[144, 169, 196, 225],
[256, 289, 324, 361],
[400, 441, 484, 529]]], dtype=int32)
In [58]: a=np.sqrt(a)
In [59]: a
Out[59]:
array([[[0. , 1. , 1.41421356, 1.73205081],
[2. , 2.23606798, 2.44948974, 2.64575131],
[2.82842712, 3. , 3.16227766, 3.31662479]],
[[3.46410162, 3.60555128, 3.74165739, 3.87298335],
[4. , 4.12310563, 4.24264069, 4.35889894],
[4.47213595, 4.58257569, 4.69041576, 4.79583152]]])
In [60]: np.modf(a)
Out[60]:
(array([[[0. , 0. , 0.41421356, 0.73205081],
[0. , 0.23606798, 0.44948974, 0.64575131],
[0.82842712, 0. , 0.16227766, 0.31662479]],
[[0.46410162, 0.60555128, 0.74165739, 0.87298335],
[0. , 0.12310563, 0.24264069, 0.35889894],
[0.47213595, 0.58257569, 0.69041576, 0.79583152]]]),
array([[[0., 1., 1., 1.],
[2., 2., 2., 2.],
[2., 3., 3., 3.]],
[[3., 3., 3., 3.],
[4., 4., 4., 4.],
[4., 4., 4., 4.]]]))
3. NumPy二進制函數
函數 | 說明 |
---|---|
| 兩個數組各元素進行對應運算 |
np.maximum(x,y) np.fmax() np.minimum(x,y) np.fmin() | 元素級的最大值 /最小值計算 |
np.mod(x,y) | 元素級的模運算 |
np.copysign(x,y) | 将數組 y中各元素值的符号指派給數組 x對應元素 |
| 算術比較,産生布爾型數組 |
In [61]: a=np.arange(24).reshape((2,3,4))
In [62]: b=np.sqrt(a) #a是int,b是float
In [63]: np.maximum(a,b) #max()函數将a轉換為float了
Out[63]:
array([[[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.]],
[[12., 13., 14., 15.],
[16., 17., 18., 19.],
[20., 21., 22., 23.]]])
In [64]: a>b
Out[64]:
array([[[False, False, True, True],
[ True, True, True, True],
[ True, True, True, True]],
[[ True, True, True, True],
[ True, True, True, True],
[ True, True, True, True]]])
四、Numpy中檔案的存取
1. 資料的CSV檔案存取
CSV (Comma‐Separated Value, 逗号分隔值) 是一種常見的檔案格式,用來存儲批量資料。
np.savetxt(frame, array, fmt='%.18e', delimiter=None)
:CSV的儲存
- frame : 檔案、字元串或産生器,可以是.gz或.bz2的壓縮檔案
- array : 存入檔案的數組
- fmt : 寫入檔案的格式,例如:
%d
%.2f
(科學計數法)%.18e
- delimiter : 分割字元串,預設是任何空格
In [2]: import numpy as np
In [3]: a=np.arange(100).reshape(5,20)
In [4]: np.savetxt('a.csv',a,fmt='%d',delimiter=',') #整數形式,資料五行20列
In [6]: a=np.arange(100).reshape(5,20)
In [7]: np.savetxt('a.csv',a,fmt='%.1f',delimiter=',') #浮點數形式,五行二十列
np.loadtxt(frame, dtype=np.float, delimiter=None, unpack=False)
:CSV的讀取
- frame : 檔案、字元串或産生器,可以是.gz或.bz2的壓縮檔案
- dtype : 資料類型,可選
- delimiter : 分割字元串,預設是任何空格
- unpack : 如果True,讀入屬性将分别寫入不同變量
In [8]: b=np.loadtxt('a.csv',delimiter=',') #不指定内容預設為浮點數
In [9]: b
Out[9]:
array([[ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.,
13., 14., 15., 16., 17., 18., 19.],
[20., 21., 22., 23., 24., 25., 26., 27., 28., 29., 30., 31., 32.,
33., 34., 35., 36., 37., 38., 39.],
[40., 41., 42., 43., 44., 45., 46., 47., 48., 49., 50., 51., 52.,
53., 54., 55., 56., 57., 58., 59.],
[60., 61., 62., 63., 64., 65., 66., 67., 68., 69., 70., 71., 72.,
73., 74., 75., 76., 77., 78., 79.],
[80., 81., 82., 83., 84., 85., 86., 87., 88., 89., 90., 91., 92.,
93., 94., 95., 96., 97., 98., 99.]])
In [10]: b=np.loadtxt('a.csv',dtype=np.int,delimiter=',')
In [11]: b
Out[11]:
array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19],
[20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39],
[40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59],
[60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,
76, 77, 78, 79],
[80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
96, 97, 98, 99]])
CSV檔案的局限性:CSV隻能有效存儲一維和二維數組
np.savetxt()
隻能有效存取一維和二維數組
np.loadtxt()
2. 多元資料的存取
a.tofile(frame, sep='', format='%s')
:多元資料的儲存
- frame : 檔案、字元串
- sep : 資料分割字元串,如果是空串,寫入檔案為二進制
- format : 寫入資料的格式
二進制檔案會比文本檔案占用更少空間
In [12]: a=np.arange(100).reshape(5,10,2)
In [13]: a.tofile("b.dat",sep=",",format='%d') #生成由逗号分隔的序列檔案 1,2,3...
#與CSV檔案不同,它沒有包含任何次元資訊,隻是把所有元素列出,然後輸出到檔案。
#會破壞reshape函數設定的格式。
In [14]: a=np.arange(100).reshape(5,10,2)
In [15]: a.tofile("b.dat",format='%d') # 生成二進制檔案
np.fromfile(frame, dtype=float, count=‐1, sep='')
:多元資料的讀取
- dtype : 讀取的資料類型
- count : 讀入元素個數,‐1表示讀入整個檔案
In [19]: c=np.fromfile("b.dat",dtype=np.int,sep=",")
In [20]: c
Out[20]: #輸出是一維數組,與輸入的格式不一樣
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
……
85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99])
#讓c reshape為 a 的格式
In [21]: c=np.fromfile("b.dat",dtype=np.int,sep=",").reshape(5,10,2)
In [22]: c
Out[22]:
array([[[ 0, 1],
[ 2, 3],
[ 4, 5],
[ 6, 7],
[ 8, 9],
……
……
[96, 97],
[98, 99]]])
In [23]: a=np.arange(100).reshape(5,10,2)
In [24]: a.tofile("b.dat",format='%d') #以二進制形式存入檔案
In [25]: c=np.fromfile("b.dat",dtype=np.int).reshape(5,10,2) # 讀取二進制檔案
In [26]: c
Out[26]:
array([[[ 0, 1],
[ 2, 3],
[ 4, 5],
……
[94, 95],
[96, 97],
[98, 99]]])
該方法需要讀取時知道存入檔案時數組的次元和元素類型和
a.tofile()
需要配合使用 可以通過中繼資料檔案來存儲額外資訊
np.fromfile()
3. NumPy的便捷檔案存取
np.save(fname, array)
或
np.savez(fname, array)
存儲檔案,前者非壓縮,後者壓縮
- fname : 檔案名,以.npy為擴充名,壓縮擴充名為.npz
- array : 數組變量
np.load(fname)
讀取檔案
In [27]: a=np.arange(100).reshape(5,10,2)
In [28]: np.save("a.npy",a)
In [29]: b=np.load("a.npy")
In [30]: b
Out[30]:
array([[[ 0, 1],
[ 2, 3],
[ 4, 5]
……
[94, 95],
[96, 97],
[98, 99]]])
五、NumPy的函數
1. NumPy的随機數函數
基本随機數函數 | 說明 |
---|---|
| 根據d0‐dn建立随機數數組,浮點數,[0,1),均勻分布 |
| 根據d0‐dn建立随機數數組,标準正态分布 |
| 根據shape建立随機整數或整數數組,範圍是[low, high) |
| 随機數種子,s是給定的種子值 |
In [31]: a=np.random.rand(3,4,5) #生成3,4,5次元的數組
In [32]: a
Out[32]:
array([[[8.83299431e-03, 8.05387769e-01, 3.86462185e-01, 6.46913067e-02,
9.93829691e-01],
[4.53347896e-01, 4.22900051e-01, 3.92576772e-01, 8.58568265e-01,
1.20287066e-01],
……
[5.00080272e-01, 4.62143545e-01, 4.03942908e-01, 4.26192622e-01,
6.77575819e-01]]])
In [33]: sn=np.random.randn(3,4,5) #資料符合正太分布
In [34]: sn
Out[34]:
array([[[-2.57248464e+00, 1.03484560e+00, 8.59184836e-01,
-4.11266639e-01, 8.70097584e-01],
[-9.22467511e-01, 6.15670993e-01, 1.17973012e-02,
-2.00623178e+00, -7.09408579e-01],
……
[-2.85435832e-01, -6.54918725e-01, 5.90400730e-01,
2.68995787e-01, 4.09511541e-04]]])
In [35]: b=np.random.randint(100,200,(3,4))
In [36]: b # 100-200間元素的抽取式均勻分布的
Out[36]:
array([[126, 199, 127, 175],
[163, 136, 106, 192],
[164, 193, 110, 113]])
In [37]: np.random.seed(10) #使用相同的随機數種子,會得到相同的數組
In [38]: np.random.randint(100,200,(3,4))
Out[38]:
array([[109, 115, 164, 128],
[189, 193, 129, 108],
[173, 100, 140, 136]])
進階随機數函數 | 說明 |
---|---|
| 根據數組a的第1軸進行随機排列,改變數組x |
| 根據數組a的第1軸産生一個新的亂序數組,不改變數組x |
| 從一維數組a中以機率p抽取元素,形成size形狀新數組 replace表示是否可以重用元素,預設為False |
In [39]: b=np.random.randint(100,200,(3,4))
In [40]: b #116,162,149
Out[40]:
array([[116, 111, 154, 188],
[162, 133, 172, 178],
[149, 151, 154, 177]])
In [43]: np.random.shuffle(b)
In [44]: b # 149,116,162
Out[44]:
array([[149, 151, 154, 177],
[116, 111, 154, 188],
[162, 133, 172, 178]])
In [47]: np.random.shuffle(b)
In [48]: b # 149,162,116
Out[48]:
array([[149, 151, 154, 177],
[162, 133, 172, 178],
[116, 111, 154, 188]])
In [50]: b=np.random.randint(100,200,(8,)) #b有八個元素
In [51]: b
Out[51]: array([130, 189, 112, 165, 131, 157, 136, 127])
In [52]: np.random.choice(b,(3,2))
Out[52]:
array([[112, 157],
[157, 136],
[127, 136]])
In [53]:
In [53]: np.random.choice(b,(3,2),replace=False) #設定無重複抽取
Out[53]:
array([[136, 157],
[189, 127],
[112, 131]])
In [54]: np.random.choice(b,(3,2),p=b/np.sum(b)) #設定每個元素的抽取機率
Out[54]:
array([[112, 165],
[130, 136],
[165, 189]])
産生分布的函數 | 說明 |
---|---|
| 産生具有均勻分布的數組,low起始值,high結束值,size形狀 |
| 産生具有正态分布的數組,loc均值,scale标準差,size形狀 |
| 産生具有泊松分布的數組,lam随機事件發生率,size形狀 |
In [55]: u = np.random.uniform(0,10,(3,4))
In [56]: u
Out[56]:
array([[7.31734625, 1.38782465, 7.66880049, 8.31989768],
[3.09778055, 5.9758229 , 8.7239246 , 9.83020867],
[4.67403279, 8.75744495, 2.96068699, 1.31291053]])
In [57]: u=np.random.normal(10,5,(3,4))
In [58]: u
Out[58]:
array([[12.22662292, 14.79969824, 3.2682308 , 20.09449687],
[15.41188173, 1.07141088, 8.63831508, 8.54815806],
[18.28073583, 3.82715648, 4.71157638, 10.69206992]])
2. NumPy的統計函數
函數 | 說明(axis=None 是統計函數的标配參數) |
---|---|
| 根據給定軸axis計算數組a相關元素之和,axis整數或元組 |
| 根據給定軸axis計算數組a相關元素的期望,axis整數或元組 |
| 根據給定軸axis計算數組a相關元素的權重平均值 |
| 根據給定軸axis計算數組a相關元素的标準差 |
| 根據給定軸axis計算數組a相關元素的方差 |
如果給定軸,就是對軸上的元素進行計算。最外層次元為0
In [59]: a=np.arange(15).reshape(3,5)
In [60]: a
Out[60]:
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])
In [61]: np.sum(a)
Out[61]: 105
In [62]: np.mean(a,axis=1) # 将數組中第二次元的數字進行平均數運算
Out[62]: array([ 2., 7., 12.])
In [63]: np.mean(a,axis=0)
Out[63]: array([5., 6., 7., 8., 9.])
In [65]: np.average(a,axis=0,weights=[10,5,1])
Out[65]: array([2.1875, 3.1875, 4.1875, 5.1875, 6.1875])
In [66]: np.std(a)
Out[66]: 4.320493798938574
In [67]: np.var(a)
Out[67]: 18.666666666666668
函數 | 說明(axis=None 是統計函數的标配參數) |
---|---|
| 計算數組a中元素的最小值、最大值 |
| 計算數組a中元素最小值、最大值的降一維後下标 |
| 根據shape将一維下标index轉換成多元下标 |
| 計算數組a中元素最大值與最小值的差 |
| 計算數組a中元素的中位數(中值) |
In [68]: b=np.arange(15,0,-1).reshape(3,5)
In [69]: b
Out[69]:
array([[15, 14, 13, 12, 11],
[10, 9, 8, 7, 6],
[ 5, 4, 3, 2, 1]])
In [70]: np.max(b)
Out[70]: 15
In [71]: np.argmax(b) #得到的是扁平化後的下标
Out[71]: 0
In [72]: np.unravel_index(np.argmax(b),b.shape) #将扁平化下标重塑為多元下标,即實際位置
Out[72]: (0, 0)
In [73]: np.ptp(b)
Out[73]: 14
In [74]: np.median(b)
Out[74]: 8.0
3. NumPy的梯度函數
函數 | 說明 |
---|---|
| 計算數組f中元素的梯度,當 f 為多元時,傳回每個次元梯度 |
梯度:連續值之間的變化率,即斜率。 XY坐标軸連續三個X坐标對應的Y軸值:a, b, c,其中,a的梯度是: (b‐a)/1、b的梯度是: (c‐a)/2、c的梯度是: (c-b)/1
In [75]: a=np.random.randint(0,20,(5))
In [76]: a
Out[76]: array([16, 18, 16, 14, 19])
In [77]: np.gradient(a)
Out[77]: array([ 2. , 0. , -2. , 1.5, 5. ])
In [78]: b=np.random.randint(0,20,(5))
In [79]: b
Out[79]: array([15, 19, 17, 18, 14])
In [80]: np.gradient(b)
Out[80]: array([ 4. , 1. , -0.5, -1.5, -4. ])
In [81]: c=np.random.randint(0,50,(3,5))
In [82]: c
Out[82]:
array([[48, 42, 17, 32, 17],
[41, 16, 41, 26, 12],
[30, 17, 17, 16, 0]])
In [84]: np.gradient(c) # 分别計算每個次元的梯度
Out[84]:
[array([[ -7. , -26. , 24. , -6. , -5. ], # 最外層次元的梯度
[ -9. , -12.5, 0. , -8. , -8.5],
[-11. , 1. , -24. , -10. , -12. ]]),
array([[ -6. , -15.5, -5. , 0. , -15. ], # 第二層次元的梯度
[-25. , 0. , 5. , -14.5, -14. ],
[-13. , -6.5, -0.5, -8.5, -16. ]])]
梯度有助于發現圖像的邊緣
六、執行個體:圖像的手繪效果
1. 圖像的數組表示
圖像一般采用RGB色彩模式,即每個像素點的顔色由紅(R),綠(G),藍(B)組成。RGB三個顔色通道的變化和疊加得到各種顔色,RGB的取值範圍都是0-255 ,RGB形成的顔色包括了人類視力所能感覺的所有顔色。
圖像是一個由像素組成的二維矩陣,每個像素是一個RGB值。
PIL ( Python Image Library ) 是一個具有強大圖像處理能力的第三庫。
from PIL import Image
引入圖像庫
Image是PIL庫中代表一個圖像的類(對象),一個Image對象就代表一個圖像。
2. 圖像的變換
圖像變換的基本流程:
- 首先打開圖像
- 對其中RGB對象做一個運算
- 運算後的數組再生成一個圖像類型
- 儲存為檔案
In [86]: from PIL import Image
In [87]: im=np.array(Image.open("D:/pycodes/beijing.jpg")
#圖像是一個三維數組,次元分别是高度、寬度和像素RGB值
In [88]: print(im.shape,im.dtype)
(333, 500, 3) uint8
In [89]: b=[255,255,255]-im #計算圖像的RGB通道的補值
In [90]: a=Image.fromarray(b.astype('uint8')) #将數組對象重新生成一個圖像對象
In [91]: a.save("D:/pycodes/beijing1.jpg")
## convert('L')将彩色圖檔轉為灰階圖檔,生成的數組im是二維數組,每個元素對應一個灰階值
In [93]: im=np.array(Image.open("D:/pycodes/beijing.jpg").convert('L'))
#區間變換,灰階較輕
In [94]: c=(100/255)*im+150
In [95]: a=Image.fromarray(c.astype('uint8'))
In [97]: a.save("D:/pycodes/beijing2.jpg")
#像素平方,灰階很深
In [108]: d=255*(im/255)**2
In [109]: a=Image.fromarray(d.astype('uint8'))
In [110]: a.save("D:/pycodes/beijing3.jpg")
3. 圖像的手繪效果
手繪效果的幾個特征:
- 黑白灰色
- 邊界線條較重
- 相同或相近色彩趨于白色
- 略有光源效果
3.1 梯度的重構
利用像素之間的梯度值和虛拟深度值對圖像進行重構,根據灰階變化來模拟人類視覺的遠近程度。
使用公式 深度值 * 方向梯度值 來添加深度對于梯度的影響因素,然後除以 100 進行歸一化
depth=10. ##浮點數,預設深度值為10,取值範圍0-100
grad=np.gradient(a) #取圖像灰階的梯度值
grad_x,grad_y=grad #提取x和y方向的梯度值
深度值
grad_x=grad_x*depth/100.#根據深度調整x和y方向的梯度值
grad_y=grad_y*depth/100.
3.2 光源效果
根據灰階變化來模拟人類視覺的遠近程度

- 設計一個位于圖像斜上方的虛拟光源
- 光源相對于圖像的俯視角為Elevation, 方位角為Azimuth
- 建立光源對個點梯度值的影響函數
- 計算出各點的新像素值
np.cos(vec_el)
可以看做機關光線在平面上的投影長度,再将它們分别投影到x, y ,z軸上,那麼 dx, dy, dz 就可以看做光源在坐标軸中具體位置的表示,這裡可以視為光線在 x/y/z 方向上對物體的影響程度
vec_el = np.pi/2.2 #光源的俯視角度,弧度值
vec_az = np.pi/4. #光源的方位角度,弧度值
dx = np.cos(vec_el)*np.cos(vec_az) #光源對x軸的影響
dy = np.cos(vec_el)*np.sin(vec_az) #光源對y軸的影響
dz = np.sin(vec_el) #光源對z軸的影響
3.3 梯度歸一化
A=np.sqrt(grad_x**2 + grad_y**2 +1.) #構造x和y軸梯度的三維歸一化機關坐标系
#uni_x/y/z 表示圖像平面的機關法向量
uni_x = grad_x/A
uni_y = grad_y/A
uni_z = 1./A
#将歸一化後的各方向梯度分别乘上影響因子,再投影到0-255的灰階範圍,完成梯度還原成灰階的步驟
b = 255*(dx*uni_x + dy*uni_y + dz*uni_z) #梯度與光源互相作用,将梯度轉化為灰階
3.4 圖像生成
b = b.clip(0,255) #為避免資料越界,将生成的灰階值裁剪至0-255區間
im = Image.fromarray(b.astype('uint8')) #重構圖像
im.save('./beijingHD.jpg') #生成圖像
3.5 全代碼
from PIL import Image
import numpy as np
a = np.asarray(Image.open('./beijing.jpg').convert('L')).astype('float')
depth = 10.
grad = np.gradient(a)
grad_x, grad_y = grad
grad_x = grad_x*depth/100.
grad_y = grad_y*depth/100.
A = np.sqrt(grad_x**2 + grad_y**2 + 1.)
uni_x = grad_x/A
uni_y = grad_y/A
uni_z = 1./A
vec_el = np.pi/2.2
vec_az = np.pi/4.
dx = np.cos(vec_el)*np.cos(vec_az)
dy = np.cos(vec_el)*np.sin(vec_az)
dz = np.sin(vec_el)
b = 255*(dx*uni_x + dy*uni_y + dz*uni_z)
b = b.clip(0,255)
im = Image.fromarray(b.astype('uint8'))
im.save('./beijingHD.jpg')