天天看點

[資料分析基礎] 1. NumPy庫

[資料分析基礎] 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對象的屬性 說明

.ndim

秩,即軸的數量或次元的數量

.shape

ndarray對象的尺度,對于矩陣,n行m列

.size

ndarray對象元素的個數,相當于.shape中的n*m的值

.dtype

ndarray對象的元素類型

.itemsize

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數組
函數 說明

np.arange(n)

類似range()函數,傳回ndarray類型,元素從0到n-1

np.ones(shape)

根據shape生成一個全1數組,shape是元組類型

np.zeros(shape)

根據shape生成一個全0數組,shape是元組類型

np.full(shape,val)

根據shape生成一個數組,每個元素值都是val

np.eye(n)

建立一個正方的n*n機關矩陣,對角線為1,其餘為0

np.ones_like(a)

根據數組a的形狀生成一個全1的數組

np.zeros_like(a)

根據數組a的形狀生成一個全0的數組

np.full_like(a,val)

根據數組a的形狀狀生成一個數組,每個元素值都是val

np.linspace(start,end,num)

根據起止資料及元素個數等間距地填充資料,形成數組

如果将參數endpoint置為False,end将不作為最後一個元素出現

np.concatenate(a)

将兩個或多個數組合并成一個新數組, 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數組的次元變換
方法 說明

.reshape(shape)

不改變數組元素,傳回一個shape形狀的數組,原數組不變

.resize(shape)

與.reshape()功能一緻,但修改原數組

.swapaxes(ax1,ax2)

将數組 n個次元中兩個次元進行調換

.flatten()

對數組進行降維,傳回折疊後的一維數組,原數組不變
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開始的
  1. 一維數組的索引和切片:起始編号: 終止編号(不含) : 步長
    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])
               
  2. 多元數組的索引:每個次元一個索引值,逗号分割
    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
               
  3. 多元數組的切片:沒有選取具體次元,那麼可以用

    :

    表示所有次元。
    # 選取一個次元用
    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的随機數函數
基本随機數函數 說明

rand(d0,d1,..,dn)

根據d0‐dn建立随機數數組,浮點數,[0,1),均勻分布

randn(d0,d1,..,dn)

根據d0‐dn建立随機數數組,标準正态分布

randint(low[,high,shape])

根據shape建立随機整數或整數數組,範圍是[low, high)

seed(s)

随機數種子,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]])
           
進階随機數函數 說明

shuffle(a)

根據數組a的第1軸進行随機排列,改變數組x

permutation(a)

根據數組a的第1軸産生一個新的亂序數組,不改變數組x

choice(a[,size,replace,p])

從一維數組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]])
           
産生分布的函數 說明

uniform(low,high,size)

産生具有均勻分布的數組,low起始值,high結束值,size形狀

normal(loc,scale,size)

産生具有正态分布的數組,loc均值,scale标準差,size形狀

poisson(lam,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 是統計函數的标配參數)

sum(a, axis=None)

根據給定軸axis計算數組a相關元素之和,axis整數或元組

mean(a, axis=None)

根據給定軸axis計算數組a相關元素的期望,axis整數或元組

average(a,axis=None,weights=None)

根據給定軸axis計算數組a相關元素的權重平均值

std(a, axis=None)

根據給定軸axis計算數組a相關元素的标準差

var(a, axis=None)

根據給定軸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 是統計函數的标配參數)

min(a) max(a)

計算數組a中元素的最小值、最大值

argmin(a) argmax(a)

計算數組a中元素最小值、最大值的降一維後下标

unravel_index(index, shape)

根據shape将一維下标index轉換成多元下标

ptp(a)

計算數組a中元素最大值與最小值的差

median(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的梯度函數
函數 說明

np.gradient(f)

計算數組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. 圖像的變換

圖像變換的基本流程:

  1. 首先打開圖像
  2. 對其中RGB對象做一個運算
  3. 運算後的數組再生成一個圖像類型
  4. 儲存為檔案
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. 圖像的手繪效果

手繪效果的幾個特征:

  1. 黑白灰色
  2. 邊界線條較重
  3. 相同或相近色彩趨于白色
  4. 略有光源效果

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 光源效果

根據灰階變化來模拟人類視覺的遠近程度

[資料分析基礎] 1. NumPy庫
  • 設計一個位于圖像斜上方的虛拟光源
  • 光源相對于圖像的俯視角為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')
           

繼續閱讀