1. 程式人生 > >Python numpy 學習筆記

Python numpy 學習筆記

NumPy快速入門手冊》寫得很好,也推薦閱讀


一. numpy

1. 介紹

2. numpy引用

"""numpy的主要物件是一個規範格式的多維陣列"""
import numpy as np

二. 建立numpy陣列

1. 通過list、tuple或其他序列,建立陣列

### 通過list、tuple或其他序列,建立陣列
data = np.array([[1, 2, 3], [4, 5, 6]])     # 生成np的陣列,注意入參不能是多個元素:如np.array(1,2,3,4),否則會報錯
data2 = np.array(
[[1, 3], [5, 7], [9, 11]], dtype=complex) # 可以直接指定資料型別dtype print(data2) ''' 可以看到資料格式轉成了複數 [[ 1.+0.j 3.+0.j] [ 5.+0.j 7.+0.j] [ 9.+0.j 11.+0.j]] '''

2. 建立特定格式和內容的陣列

a. 全一陣列
# 全一陣列
one_np = np.ones([3,2], dtype=int)           # 建立全為1的二維陣列,第一個引數shape決定了陣列的格式
print(one_np)
'''
[[1 1]
 [1 1]
 [1 1]]
'''
b. 全零陣列
# 全零陣列
zero_np = np.zeros([2, 3, 2], dtype=float)    # 建立了一個三維陣列,每個陣列元素都是0
print(zero_np)
'''
[[[ 0.  0.]
  [ 0.  0.]
  [ 0.  0.]]
 [[ 0.  0.]
  [ 0.  0.]
  [ 0.  0.]]]
'''
c. 空隨機陣列
# 空隨機陣列
random_np = np.empty([2, 2])    # 根據系統的狀態隨機生成一些佔位元素,陣列完全是隨機的
print(random_np)
''' 
[[  1.33511562e-306   6.23040373e-307]
 [  1.20161730e-306   1.02360527e-306]]
'''

3. 數字序列陣列

### 數字序列陣列
# arange()      起點start + 終點stop(不包含) + 總共節點數step
data3 = np.arange(1, 9, 2)      # 類似於range()函式, 一維陣列
print(data3)                    # [1 3 5 7]

# linspace()    起點start + 終點stop(包含) + 總共節點數num
data4 = np.linspace(0, 5)       # linspace(start, stop, num=50)生成從起點到終點(包括),均勻間隔的一維陣列。
                                # 其中num預設為50,表示陣列長度(因此元素間隔寬度為(stop - start)/num )
print(data4)
'''
array([ 0.        ,  0.10204082,  0.20408163,  0.30612245,  0.40816327,
        0.51020408,  0.6122449 ,  0.71428571,  0.81632653,  0.91836735,
        1.02040816,  1.12244898,  1.2244898 ,  1.32653061,  1.42857143,
        1.53061224,  1.63265306,  1.73469388,  1.83673469,  1.93877551,
        2.04081633,  2.14285714,  2.24489796,  2.34693878,  2.44897959,
        2.55102041,  2.65306122,  2.75510204,  2.85714286,  2.95918367,
        3.06122449,  3.16326531,  3.26530612,  3.36734694,  3.46938776,
        3.57142857,  3.67346939,  3.7755102 ,  3.87755102,  3.97959184,
        4.08163265,  4.18367347,  4.28571429,  4.3877551 ,  4.48979592,
        4.59183673,  4.69387755,  4.79591837,  4.89795918,  5.        ])
'''

4. 隨機數

a. np.random.rand 生成[0,1)區間內平均分佈的陣列,引數為維度
### 隨機數
# 生成[0,1)區間內平均分佈的陣列,引數為維度
data5 = np.random.rand(2, 3, 5)
print(data5)
'''
[[[ 0.11460522  0.78475528  0.41318688  0.9830661   0.23276821]
  [ 0.31333353  0.99497377  0.31270973  0.55575352  0.30095844]
  [ 0.83803498  0.07725709  0.60617707  0.17494517  0.7324532 ]]
 [[ 0.03576562  0.84033749  0.81820702  0.46633063  0.06972207]
  [ 0.00538072  0.44754953  0.23233634  0.78536293  0.43381988]
  [ 0.85224057  0.40323818  0.07592376  0.23596046  0.49922436]]]
'''
b. np.random.randn 生成標準正態分佈規律的陣列(數出現的概率滿足標準正太分佈),引數為維度
# 生成標準正態分佈規律的陣列(數出現的概率滿足標準正太分佈),引數為維度
data6 = np.random.randn(2, 3, 5)
print(data6)
'''
[[[-0.51493028  1.78516665 -0.38657793  0.70038985 -1.24254944]
  [-0.80613041  0.63745159  0.74201648  0.39451194 -0.94476024]
  [-0.47833675 -0.92092758  1.01658297  0.85712149 -0.21944187]]
 [[ 1.3295873  -0.10871527  0.31088519 -0.60094403  1.80437504]
  [-0.3851662  -0.26422884  1.03784294 -0.44199909  0.83116801]
  [-0.03563173 -0.66946972  0.45256832  0.17121998  0.2120946 ]]]
'''
c. 生成指定範圍的隨機數
# 生成指定範圍的隨機整數
np.random.randint(1, 7, 10)         # 開區間,不可能取7 ,array([5, 3, 6, 1, 6, 1, 6, 5, 4, 3])
np.random.random_integers(1,7,10)   # 閉區間,可以取到7  array([5, 1, 1, 7, 7, 2, 6, 5, 1, 2])
np.random.random()                  # [0,1)內隨機數 本例:0.3825271804785396
d. np.random.choice 隨機選擇
# 隨機選擇
np.random.choice(10,size=2)         # array([7, 4])
np.random.choice(10,size=(3,4))     # 設定shape
'''
array([[4, 9, 5, 7],
       [6, 6, 5, 1],
       [6, 5, 5, 0]])
'''

np.random.choice(['a','b','c'],size=[2,2])      # 從給出的list中隨機選擇生成陣列
'''
array([['c', 'b'],
       ['c', 'b']],
      dtype='<U1')
'''

二. 陣列的屬性

"""陣列的屬性"""
data = np.array([[1, 2, 3], [4, 5, 6]])     
data.ndim       # 陣列的維度 本例:2
data.shape      # 陣列的形狀,返回一個元組,表示各個方向的長度,元組本身的長度等於陣列的維度. 本例:(2, 3)
data.size       # 陣列的大小,等於shape元組內各個元素的乘積, 本例:6
data.dtype      # 陣列內部元素的資料型別, 本例:dtype('int32')
data.itemsize   # 陣列內元素佔計算機記憶體的大小(多少個Byte), 本例:4
data.data       # 陣列在記憶體中的地址,一般很少用,本例:<memory at 0x00000000070AC1F8>

三. 陣列維度及元素型別轉換

1. 重新修改維度(常用)

### 重新修改維度(常用)
data_shaped1 = data.reshape(3,2)
print(data_shaped1)
'''
[[1 2]
 [3 4]
 [5 6]]
'''

# 利用arrange() 和 reshape() 生成多維陣列
data_shaped3 = np.arange(24).reshape(3, -1, 4)   #如果某一個方向設為-1,則會自動計算
print(data_shaped3)
''' 可以看到,第二維度被自動計算為2
[[[ 0  1  2  3]
  [ 4  5  6  7]]
 [[ 8  9 10 11]
  [12 13 14 15]]
 [[16 17 18 19]
  [20 21 22 23]]]
'''

### resize()
# 與 reshape()相似,不過resize()會修改原陣列

2. np陣列轉換為list

### 轉換為list
list_np = one_np.tolist()           # [[1, 1], [1, 1], [1, 1]]

3. np.astype() 轉換元素型別

### 轉換型別 astype() 在轉換中,可能會損失精度
data2_int = data2.astype(int)           # 元素資料型別,從原先的複數complex轉換為int
print(data2_int)
'''
[[ 1  3]
 [ 5  7]
 [ 9 11]]
'''

4. 陣列轉置

### 陣列轉置
np.transpose(data_shaped1)
'''
array([[1, 3, 5],
       [2, 4, 6]])
'''

# 多維陣列轉置
np.transpose(data_shaped3)        # 多維陣列轉置,就是座標的reverse,然後組成新陣列,注意資料交換
'''
array([[[ 0,  8, 16],       d[0,0,0], d[1,0,0], d[2,0,0]
        [ 4, 12, 20]],      d[0,1,0], d[1,1,0], d[2,1,0]
       [[ 1,  9, 17],       d[0,0,1], d[1,0,1], d[2,0,1]
        [ 5, 13, 21]],      d[0,1,1], d[1,1,1], d[2,1,1]
       [[ 2, 10, 18],       d[0,0,2], d[1,0,2], d[2,0,2]
        [ 6, 14, 22]],      d[0,1,2], d[1,1,2], d[2,1,2]
       [[ 3, 11, 19],       d[0,0,3], d[1,0,3], d[2,0,3]
        [ 7, 15, 23]]])     d[0,1,3], d[1,1,3], d[2,1,3]
'''

5. 轉換一維陣列

### ravel() 逐行取元素並返回一個一維陣列
print(np.ravel(data_shaped3))       # [ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23]

四. 陣列的完全不復制(全部引用)、指代(區域性引用)、深度複製

1. 完全不復制

### 1. 完全不復制
a = np.arange(4)
b = np.arange(4)
b is a                  # b和a現在還不是同一引用,為False
b = a
b is a                  # b和a是同一引用,為True
a.shape                 # 此時是(4,)
b.shape = (2,2)         # 因為是同一引用,所以也會修改a的形狀
a.shape                 # 變為(2, 2)

2. 指代 (切片也是如此)

### 2. 指代 (切片也是如此)
a = np.arange(12,24).reshape(3,4)
b = a.view()            # 返回一個指代,但還是引用了同一陣列
b is a                  # False

b[1,2] = 678
print(a)
''' 可以看到a[1,2]也變成了678
[[ 12  13  14  15]
 [ 16  17 678  19]
 [ 20  21  22  23]]
'''

3. 深度複製

### 3. 深度複製
a = np.arange(12,24).reshape(3,4)
b = a.copy()

b is a                  # False
b[1,1] = 111
print(b)
'''
[[ 12  13  14  15]
 [ 16 111  18  19]
 [ 20  21  22  23]]
'''
print(a)
''' a 沒變
[[12 13 14 15]
 [16 17 18 19]
 [20 21 22 23]]
'''

五. 陣列取值及分片

1. 多維陣列通過索引取某一元素

### 多維陣列通過索引取某一元素
c = np.arange(12).reshape(3, 4)     # 建立一個3*4的二維陣列
print(c)
'''
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
'''
c[1,3]                  # 取第二行第四列的元素,本例:7
c[1][3]                 # 取第二行第四列的元素,本例:7

2. 一維陣列分片 arr[i:j:k]

i決定起始,j決定結束,k決定步進,都可以為負數,其中k為負則倒序取值

### 一維陣列分片  arr[i:j:k]  i決定起始,j決定結束,k決定步進,都可以為負數,其中k為負則倒序取值
b = np.arange(1,20,2)
b                       # array([ 1,  3,  5,  7,  9, 11, 13, 15, 17, 19])
b[2]                    # 取第三項的元素, 本例:5
b[2:4]                  # 取第三、四項的子分片,本例:array([5, 7])
b[:5:2]                 # 在原陣列前五項中,步進為2的取陣列成新陣列,本例:array([1, 5, 9])
b[-3:1:-2]              # 從倒數第三項('15')開始,從後向前步進2格取值,直到第二項('3',不包含此項) 本例:array([15, 11,  7])


## 注意:雖然語法相似,但不同於list的分片(建立副本),np的分片是不建立副本的,修改分片中的元素,會影響到原陣列的元素
sub_b = b[2:7:3]        # sub_b = array([ 5, 11])
sub_b[1] = 1            # 此時sub_b變為了array([5, 1])
b                       # 同時原陣列也發生了變化:array([ 1,  3,  5,  7,  9,  1, 13, 15, 17, 19])

### 如果想建立絕對的副本,則要用copy()
b = np.arange(1,20,2)
duplicate_b = b[2:7:3].copy()           # duplicate_b = array([ 5, 11]), 使用copy建立副本
duplicate_b[1] = 1                      # 此時duplicate_b變為了array([5, 1])
b                       # 原陣列沒有變:array([ 1,  3,  5,  7,  9, 11, 13, 15, 17, 19])

4. 多維陣列分片

### 多維陣列分片
c = np.arange(12).reshape(3, 4)     # 建立一個3*4的二維陣列
print(c)
'''
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
'''
sub_c = c[1:3,1:3]      # 取2、3行和2、3列的子陣列
print(sub_c)
'''
[[ 5  6]
 [ 9 10]]
'''

## 多維陣列倒序分片
sub_c = c[::-2,1:3]      # 取所有行步進為-2(從後向前)和2、3列組成的子陣列
print(sub_c)
'''
[[ 9 10]            # 先取的第三行的9,10
 [ 1  2]]           # 再取的第一行的1,2 
'''

使用分片,批量修改元素及順序

### 使用分片,批量修改元素(因為只是引用)
b = np.arange(1,20,2)   # array([ 1,  3,  5,  7,  9, 11, 13, 15, 17, 19])
b[1:9:2] += 1           # 從第2項到第9項,步進為2的數都自增1
b                       # array([ 1,  4,  5,  8,  9, 12, 13, 16, 17, 19])
### 拓展:重新排序
c = b[[0,2,1]]
print(c)
'''
[[10 11 12 13]
 [18 19 20 21]          第二行和第三行交換了順序
 [14 15 16 17]]
'''

d = b[:,[3,0,-2,1]]
print(d)
''' 列上交換了順序
[[13 10 12 11]
 [17 14 16 15]
 [21 18 20 19]]
'''

六. 高階索引

1. 整數索引

a. 陣列arr_index為索引,從一維陣列array中篩選出新的陣列
## 陣列arr_index為索引,從一維陣列array中篩選出新的陣列
a = np.arange(10,20)            # a: array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
arr_index = np.array(([3,4,5],[1,2,3]))
a_new = a[arr_index]
print(a_new)
''' 可以看到取的陣列的格式跟arr_index一致,每個元素為原陣列在索引arr_index[i]處的值
[[13 14 15]         a[3]=13, a[4]=14, a[5]=15
 [11 12 13]]        a[1]=11, a[2]=12, a[3]=13
'''
b. 陣列arr_index為索引,從多維陣列array中篩選出新的陣列
## 陣列arr_index為索引,從多維陣列array中篩選出新的陣列
b = np.arange(10,22).reshape(3,4)
print(b)
"""
[[10 11 12 13]
 [14 15 16 17]
 [18 19 20 21]]
"""
arr_index = np.array([[0,2,1],[1,2,0]])
e = b[arr_index]
print(e)
''' 本質上與一維陣列和多維索引的結果類似,整體陣列的形狀還是按照索引arr_index的形狀,
只是這裡的索引搜出來的元素不是簡單資料,而是一維陣列,所以整個結果陣列擴充為了三維陣列
[[[10 11 12 13]         b[0]=[10 11 12 13]
  [18 19 20 21]         b[2]=[18 19 20 21]  
  [14 15 16 17]]        b[1]
 [[14 15 16 17]         b[1]
  [18 19 20 21]         b[2]
  [10 11 12 13]]]       b[0]
'''
c. 列表、元組list_index為索引,從多維陣列array中篩選出新的陣列
## 列表、元組list_index為索引,從多維陣列array中篩選出新的陣列
b = np.arange(10,22).reshape(3,4)
print(b)
'''
[[10 11 12 13]
 [14 15 16 17]
 [18 19 20 21]]
'''
list_index = ([0,2,1],[1,2,0])       # 注意這裡是list、tuple或者其他簡單序列,不是np.array
b_new = b[list_index]
print(b_new)
''' 通過索引來取元素組成新的結果
[11 20 14]          a[0,1]=11, a[2,2]=20, a[1,0]=14

2. 布林索引

a. 布林索引的意義
###  布林索引  通過True/False的陣列,來索引陣列
m = np.random.rand(30).reshape(10, 3)       # 建立一個10 * 3 的二維陣列
print(m)
'''
[[ 0.64877021  0.72179137  0.56534942]
 [ 0.66861906  0.99436     0.09971997]
 [ 0.71550022  0.39179217  0.69544798]
 [ 0.76190541  0.71990526  0.5056289 ]
 [ 0.09218896  0.20907768  0.53118   ]
 [ 0.04977315  0.79410303  0.86770033]
 [ 0.39507158  0.42490585  0.48495278]
 [ 0.18026899  0.47850156  0.13560222]
 [ 0.11837795  0.67394728  0.7619298 ]
 [ 0.23708205  0.93920253  0.79138269]]
'''

m_select = m[[True,False,False,False,True,True,False,False,False,False]]        # 總共10個Boolean值,對應m的10行
print(m_select)
''' 通過True值,篩選出第一行、第五、六行的資料組成子陣列
[[ 0.64877021  0.72179137  0.56534942]
 [ 0.09218896  0.20907768  0.53118   ]
 [ 0.04977315  0.79410303  0.86770033]]
'''

# 這樣乍一看覺得用布林值多此一舉,用數篩選更方便,但如果有兩個陣列,之間存在對應關係,布林值搜尋就十分方便
n = np.array(['小明','小紅','李白','小明','小明','李白','小紅','張偉','李白','張偉'])    # n中有10個人,對應m的十行資料

# 現在我們要篩選出屬於'小紅'的資料
m_select2 = m[n=='小紅']
print(m_select2)
''' 篩選出屬於小紅的第二行、第七行資料
[[ 0.66861906  0.99436     0.09971997]
 [ 0.39507158  0.42490585  0.48495278]]
'''
b. 布林索引判斷的拓展
## 還可以再用切片或者篩選
m_select3 = m[n=='小紅',1]            # 篩選出第二列的資料
print(m_select3)                    # [ 0.99436     0.42490585]

## 與或非運算
m_select4 = m[n!='小紅',:2]        # 篩選出不是小紅的前兩列資料
print(m_select4)
'''
[[ 0.64877021  0.72179137]
 [ 0.71550022  0.39179217]
 [ 0.76190541  0.71990526]
 [ 0.09218896  0.20907768]
 [ 0.04977315  0.79410303]
 [ 0.18026899  0.47850156]
 [ 0.11837795  0.67394728]
 [ 0.23708205  0.93920253]]
'''

m_select5 = m[(n=='小紅')|(n=='李白')]        # 篩選出小紅或者李白的資料
print(m_select5)
'''
[[ 0.66861906  0.99436     0.09971997]
 [ 0.71550022  0.39179217  0.69544798]
 [ 0.04977315  0.79410303  0.86770033]
 [ 0.39507158  0.42490585  0.48495278]
 [ 0.11837795  0.67394728  0.7619298 ]]
'''

七. 陣列元素替換和填充

1. 布林索引

"""陣列元素替換和填充   布林索引 + np.where() """
### 通過布林索引,實現元素替換與填充
x = np.array([[1,2],[np.nan, 3],[np.nan, np.nan]])
print(x)
'''
[[  1.   2.]
 [ nan   3.]
 [ nan  nan]]
'''

np.isnan(x)
'''
array([[False, False],
       [ True, False],
       [ True,  True]], dtype=bool)
'''
x[np.isnan(x)]              # 篩選出是nan元素組成新一維陣列, array([ nan,  nan,  nan])
x[np.isnan(x)] = 0          # 將x中是nan的元素,都替換為0,通過布林索引實現替換元素的功能
print(x)
'''
[[ 1.  2.]
 [ 0.  3.]
 [ 0.  0.]]
'''
x[~np.isnan(x)]             # 篩選出是nan元素組成新一維陣列, array([ 1.,  2.,  3.])

2. 篩選函式where(condition, a, b)

condition元素為布林值,能起到和布林索引同樣的功能

### 篩選函式where(condition, a, b)  condition元素為布林值,能起到和布林索引同樣的功能
a = np.arange(1,10,2)           # array([1, 3, 5, 7, 9])
b = np.arange(2,11,2)           # array([ 2,  4,  6,  8, 10])
f = np.array([True,True,False,True,False])
r = np.where(f, a, b)       # 如果f某位置的值為True則取對應位置的a的值,否則取b的值
'''
array([ 1,  3,  6,  7, 10])
'''

# a/b可以不為陣列,用法如下
a = np.random.rand(12).reshape(3,4)
'''
array([[ 0.21251241,  0.28023144,  0.01282137,  0.24889945],
       [ 0.55515714,  0.95901587,  0.34933226,  0.80928682],
       [ 0.69281057,  0.63581292,  0.960359  ,  0.7399842 ]])
'''
r = np.where(a>0.5, 1, 0)
'''
array([[0, 0, 0, 0],
       [1, 1, 0, 1],
       [1, 1, 1, 1]])
'''
r2 = np.where(a>0.5, a, 0)
'''
array([[ 0.        ,  0.        ,  0.        ,  0.        ],
       [ 0.55515714,  0.95901587,  0.        ,  0.80928682],
       [ 0.69281057,  0.63581292,  0.960359  ,  0.7399842 ]])
'''

## 與r2相同結果的方法實現
a[a<=0.5] = 0           # 將a中所有小於等於0.5的都設為0
print(a)
'''
[[ 0.          0.          0.          0.        ]
 [ 0.55515714  0.95901587  0.          0.80928682]
 [ 0.69281057  0.63581292  0.960359    0.7399842 ]]
'''

八. 陣列的組裝拼接和分割

1. 拼接陣列

a = np.array([[1,2],[3,4]])
b = np.array([['A','B'],['C','D']])

### 豎直拼接
v = np.vstack((a,b))
print(v)
''' 有意思的是,數字也被轉換string格式了
[['1' '2']
 ['3' '4']
 ['A' 'B']
 ['C' 'D']]
'''

### 水平拼接
h = np.hstack((a,b))
print(h)
'''
[['1' '2' 'A' 'B']
 ['3' '4' 'C' 'D']]
'''

2. 分割陣列

### 分割陣列
d = np.arange(32).reshape(4,8)
prin