numpy 系統性總結

numpy總結

最常用的python庫,卻經常混淆,故對網頁上的內容和書籍上內容彙總總結下,未完待續。。。

1 數組基礎

1.1數組創建

創建數組有5種常規機制:

  1. 從其他Python結構(例如,列表,元組)轉換
  2. numpy原生數組的創建(例如,arange、ones、zeros等)
  3. 從磁盤讀取數組,無論是標準格式還是自定義格式
  4. 通過使用字符串或緩衝區從原始字節創建數組
  5. 使用特殊庫函數(例如,random)

1.1.1將Python array_like對象轉換爲Numpy數組

常規是從Python列表或元組中創建數組

例如,你可以使用array函數從常規Python列表或元組中創建數組。得到的數組的類型是從Python列表中元素的類型推導出來的。

>>> import numpy as np
>>> a = np.array([2,3,4])
>>> a
array([2, 3, 4])
>>> a.dtype
dtype('int64')
>>> b = np.array([1.2, 3.5, 5.1])
>>> b.dtype
dtype('float64')

一個常見的錯誤,就是調用array的時候傳入多個數字參數,而不是提供單個數字的列表類型作爲參數。

>>> a = np.array(1,2,3,4)    # WRONG
>>> a = np.array([1,2,3,4])  # RIGHT

array 還可以將序列的序列轉換成二維數組,將序列的序列的序列轉換成三維數組,等等。

>>> b = np.array([(1.5,2,3), (4,5,6)])
>>> b
array([[ 1.5,  2. ,  3. ],
       [ 4. ,  5. ,  6. ]])

也可以在創建時顯式指定數組的類型:

>>> c = np.array( [ [1,2], [3,4] ], dtype=complex )
>>> c
array([[ 1.+0.j,  2.+0.j],
       [ 3.+0.j,  4.+0.j]])

1.1.2numpy原生數組的創建

用 NumPy 內置的方法從頭創建數組

通常,數組的元素最初是未知的,但它的大小是已知的。因此,NumPy提供了幾個函數來創建具有初始佔位符內容的數組。這就減少了數組增長的必要,因爲數組增長的操作花費很大。

函數zeros創建一個由0組成的數組,函數 ones創建一個完整的數組,函數empty 創建一個數組,其初始內容是隨機的,取決於內存的狀態。默認情況下,創建的數組的dtype是 float64 類型的。

>>> np.zeros( (3,4) )
array([[ 0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.]])
>>> np.ones( (2,3,4), dtype=np.int16 )                # dtype can also be specified
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]]], dtype=int16)
>>> np.empty( (2,3) )                                 # uninitialized, output may vary
array([[  3.73603959e-262,   6.02658058e-154,   6.55490914e-260],
       [  5.30498948e-313,   3.14673309e-307,   1.00000000e+000]])

爲了創建數字組成的數組,NumPy提供了一個類似於range的函數,該函數返回數組而不是列表。

>>> np.arange( 10, 30, 5 )
array([10, 15, 20, 25])
>>> np.arange( 0, 2, 0.3 )                 # it accepts float arguments
array([ 0. ,  0.3,  0.6,  0.9,  1.2,  1.5,  1.8])

arange與浮點參數一起使用時,由於有限的浮點精度,通常不可能預測所獲得的元素的數量。出於這個原因,通常最好使用linspace函數來接收我們想要的元素數量的函數,而不是步長(step):

>>> from numpy import pi
>>> np.linspace( 0, 2, 9 )                 # 9 numbers from 0 to 2
array([ 0.  ,  0.25,  0.5 ,  0.75,  1.  ,  1.25,  1.5 ,  1.75,  2.  ])
>>> x = np.linspace( 0, 2*pi, 100 )        # useful to evaluate function at lots of points
>>> f = np.sin(x)

另見這些API

arrayzeroszeros_likeonesones_likeemptyempty_likearangelinspacenumpy.random.mtrand.RandomState.randnumpy.random.mtrand.RandomState.randnfromfunctionfromfile

1.1.3 從磁盤讀取數組

這大概是大數組創建的最常見情況。當然,細節很大程度上取決於磁盤上的數據格式,所以本節只能給出如何處理各種格式的一般指示。

標準二進制格式 #

各種字段都有數組數據的標準格式。下面列出了那些已知的Python庫來讀取它們並返回numpy數組(可能有其他可能讀取並轉換爲numpy數組的其他數據,因此請檢查最後一節)

HDF5: h5py
FITS: Astropy

無法直接讀取但不易轉換的格式示例是像PIL這樣的庫支持的格式(能夠讀取和寫入許多圖像格式,如jpg,png等)。

常見ASCII格式 #

逗號分隔值文件(CSV)被廣泛使用(以及Excel等程序的導出和導入選項)。有很多方法可以在Python中閱讀這些文件。python中有CSV函數和pylab函數(matplotlib的一部分)。

更多通用的ascii文件可以在scipy中使用io軟件包讀取。

自定義二進制格式 #

有各種各樣的方法可以使用。如果文件具有相對簡單的格式,那麼可以編寫一個簡單的 I/O 庫,並使用 numpy fromfile() 函數和 .tofile() 方法直接讀取和寫入numpy數組(儘管介意你的字節序)!如果存在一個讀取數據的良好 C 或 C++ 庫,可以使用各種技術來封裝該庫,但這肯定要做得更多,並且需要更多的高級知識才能與C或C++ 接口。

1.1.4 使用特殊庫 #

有些庫可用於生成特殊用途的數組,且無法列出所有的這些庫。最常見的用途是隨機使用許多數組生成函數,這些函數可以生成隨機值數組,以及一些實用函數來生成特殊矩陣(例如對角線)。

1.2 數據類型

NumPy支持比Python更多種類的數字類型。本節顯示了哪些可用,以及如何修改數組的數據類型。

支持的原始類型與 C 中的原始類型緊密相關:

Numpy 的類型 C 的類型 描述
np.bool bool 存儲爲字節的布爾值(True或False)
np.byte signed char 平臺定義
np.ubyte unsigned char 平臺定義
np.short short 平臺定義
np.ushort unsigned short 平臺定義
np.intc int 平臺定義
np.uintc unsigned int 平臺定義
np.int_ long 平臺定義
np.uint unsigned long 平臺定義
np.longlong long long 平臺定義
np.ulonglong unsigned long long 平臺定義
np.half / np.float16 半精度浮點數:符號位,5位指數,10位尾數
np.single float 平臺定義的單精度浮點數:通常爲符號位,8位指數,23位尾數
np.double double 平臺定義的雙精度浮點數:通常爲符號位,11位指數,52位尾數。
np.longdouble long double 平臺定義的擴展精度浮點數
np.csingle float complex 複數,由兩個單精度浮點數(實部和虛部)表示
np.cdouble double complex 複數,由兩個雙精度浮點數(實部和虛部)表示。
np.clongdouble long double complex 複數,由兩個擴展精度浮點數(實部和虛部)表示。

由於其中許多都具有依賴於平臺的定義,因此提供了一組固定大小的別名:

Numpy 的類型 C 的類型 描述
np.int8 int8_t 字節(-128到127)
np.int16 int16_t 整數(-32768至32767)
np.int32 int32_t 整數(-2147483648至2147483647)
np.int64 int64_t 整數(-9223372036854775808至9223372036854775807)
np.uint8 uint8_t 無符號整數(0到255)
np.uint16 uint16_t 無符號整數(0到65535)
np.uint32 uint32_t 無符號整數(0到4294967295)
np.uint64 uint64_t 無符號整數(0到18446744073709551615)
np.intp intptr_t 用於索引的整數,通常與索引相同 ssize_t
np.uintp uintptr_t 整數大到足以容納指針
np.float32 float
np.float64 / np.float_ double 請注意,這與內置python float的精度相匹配。
np.complex64 float complex 複數,由兩個32位浮點數(實數和虛數組件)表示
np.complex128 / np.complex_ double complex 請注意,這與內置python 複合體的精度相匹配。

NumPy數值類型是dtype(數據類型)對象的實例,每個對象都具有獨特的特徵。使用後導入NumPy

1.3 數組屬性

NumPy的數組類被調用ndarray。它也被別名所知 array。請注意,numpy.array這與標準Python庫類不同array.array,後者只處理一維數組並提供較少的功能。ndarray對象更重要的屬性是:

  • ndarray.ndim - 數組的軸(維度)的個數。在Python世界中,維度的數量被稱爲rank。
  • ndarray.shape - 數組的維度。這是一個整數的元組,表示每個維度中數組的大小。對於有 n 行和 m 列的矩陣,shape 將是 (n,m)。因此,shape 元組的長度就是rank或維度的個數 ndim
  • ndarray.size - 數組元素的總數。這等於 shape 的元素的乘積。
  • ndarray.dtype - 一個描述數組中元素類型的對象。可以使用標準的Python類型創建或指定dtype。另外NumPy提供它自己的類型。例如numpy.int32、numpy.int16和numpy.float64。
  • ndarray.itemsize - 數組中每個元素的字節大小。例如,元素爲 float64 類型的數組的 itemsize 爲8(=64/8),而 complex32 類型的數組的 itemsize 爲4(=32/8)。它等於 ndarray.dtype.itemsize
  • ndarray.data - 該緩衝區包含數組的實際元素。通常,我們不需要使用此屬性,因爲我們將使用索引訪問數組中的元素。

1.4 數組打印

當您打印數組時,NumPy以與嵌套列表類似的方式顯示它,但具有以下佈局:

  • 最後一個軸從左到右打印,
  • 倒數第二個從上到下打印,
  • 其餘部分也從上到下打印,每個切片用空行分隔。

然後將一維數組打印爲行,將二維數據打印爲矩陣,將三維數據打印爲矩數組表。

>>> a = np.arange(6)                         # 1d array
>>> print(a)
[0 1 2 3 4 5]
>>>
>>> b = np.arange(12).reshape(4,3)           # 2d array
>>> print(b)
[[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]]
>>>
>>> c = np.arange(24).reshape(2,3,4)         # 3d array
>>> print(c)
[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]
 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]

有關 reshape 的詳情,請參閱下文。

如果數組太大而無法打印,NumPy會自動跳過數組的中心部分並僅打印角點:

>>> print(np.arange(10000))
[   0    1    2 ..., 9997 9998 9999]
>>>
>>> print(np.arange(10000).reshape(100,100))
[[   0    1    2 ...,   97   98   99]
 [ 100  101  102 ...,  197  198  199]
 [ 200  201  202 ...,  297  298  299]
 ...,
 [9700 9701 9702 ..., 9797 9798 9799]
 [9800 9801 9802 ..., 9897 9898 9899]
 [9900 9901 9902 ..., 9997 9998 9999]]

要禁用此行爲並強制NumPy打印整個數組,可以使用更改打印選項set_printoptions

>>> np.set_printoptions(threshold=sys.maxsize)       # sys module should be imported

2 索引

索引得到的是副本,而不是另一個視圖。

2.1單個元素索引

和 Python 列表一樣,在一維數組中,你也可以通過中括號指定 索引獲取第 i 個值(從 0 開始計數):

請注意,和 Python 列表不同,NumPy 數組是固定類型的。這意味着當你試圖將一個浮點值插入一個整型數組時,浮點值會被截短成整型。並 且這種截短是自動完成的,不會給你提示或警告,所以需要特別注意這一點!

In[5]: x1
Out[5]: array([5, 0, 3, 3, 7, 9])
In[6]: x1[0] Out[6]: 5 In[7]: x1[4] Out[7]: 7

爲了獲取數組的末尾索引,可以用負值索引:

In[8]: x1[-1] Out[8]: 9 In[9]: x1[-2] 
Out[9]: 7

在多維數組中,可以用逗號分隔的索引元組獲取元素:

In[10]: x2 
Out[10]: array([[3, 5, 2, 4], [7, 6, 8, 8], [1, 6, 7, 7]]) 
In[11]: x2[0, 0] 
Out[11]: 3
In[12]: x2[2, 0]
Out[12]: 1 
In[13]: x2[2, -1] 
Out[13]: 7

也可以用以上索引方式修改元素值:

In[14]: x2[0, 0] = 12 x2 
Out[14]: array([[12, [ 7, [ 1,
5, 6, 6,
2, 8, 7,
4], 8], 7]])

請注意,和 Python 列表不同,NumPy 數組是固定類型的。這意味着當你試圖將一個浮點值插入一個整型數組時,浮點值會被截短成整型。並 且這種截短是自動完成的,不會給你提示或警告,所以需要特別注意這一點!

In[15]: x1[0] = 3.14159  #這將被截短
x1  
Out[15]: array([3, 0, 3, 3, 7, 9])

2.2 索引數組

索引數組返回的是原始數據的副本,而不是切片獲取的視圖。

索引數組必須是整數類型。數組中的每個值指示要使用的數組中的哪個值代替索引。爲了顯示:

>>> x = np.arange(10,1,-1)
>>> x
array([10,  9,  8,  7,  6,  5,  4,  3,  2])
>>> x[np.array([3, 3, 1, 8])]
array([7, 7, 9, 2])

由值3,3,1和8組成的索引數組相應地創建一個長度爲4的數組(與索引數組相同),其中每個索引由索引數組在被索引的數組中具有的值替換。

允許使用負值,並且與單個索引或切片一樣工作:

>>> x[np.array([3,3,-3,8])]
array([7, 7, 4, 2])

索引值超出範圍是錯誤的:

>>> x[np.array([3, 3, 20, 8])]
<type 'exceptions.IndexError'>: index 20 out of bounds 0<=index<9

一般來說,使用索引數組時返回的是與索引數組具有相同形狀的數組,但索引的數組的類型和值。作爲示例,我們可以使用多維索引數組:

>>> x[np.array([[1,1],[2,3]])]
array([[9, 9],
       [8, 7]])

3 切片

正如此前用中括號獲取單個數組元素,我們也可以用切片(slice)符號獲取子數組,切片符號用冒號(:)表示。NumPy 切片語法和 Python 列 表的標準切片語法相同。爲了獲取數組 x 的一個切片,可以用以下方式:

x[start:stop:step]

如果以上 3 個參數都未指定,那麼它們會被分別設置默認值 start=0、stop= 維度的大小(size of dimension)和 step=1。我們將詳細介 紹如何在一維和多維數組中獲取子數組。

  1. 一維子數組
In[16]: x = np.arange(10) 
x 
Out[16]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) 
In[17]: x[:5] # 前五個元素 Out[17]: array([0, 1, 2, 3, 4]) 
In[18]: x[5:] # 索引五之後的元素 Out[18]: array([5, 6, 7, 8, 9]) 
In[19]: x[4:7] # 中間的子數組 Out[19]: array([4, 5, 6]) 
In[20]: x[::2] # 每隔一個元素 
Out[20]: array([0, 2, 4, 6, 8]) 
In[21]: x[1::2] # 每隔一個元素,從索引1開始 Out[21]: array([1, 3, 5, 7, 9])

你可能會在步長值爲負時感到困惑。在這個例子中,start 參數和 stop 參數默認是被交換的。 因此這是一種非常方便的逆序數組的方式:

In[22]: x[::-1] # 所有元素,逆序的 
Out[22]: array([9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) 
In[23]: x[5::-2] # 從索引5開始每隔一個元素逆序 
Out[23]: array([5, 3, 1])
  1. 多維子數組

多維切片也採用同樣的方式處理,用冒號分隔。例如:

In[24]: x2 
Out[24]: array([[12, 5, 2, 4],
								[7, 6, 8, 8],
								[1 ,6, 7, 7]])
In[25]: x2[:2, :3] # 兩行,三列
Out[25]: array([[12, 5, 2],
								[ 7, 6, 8]]) 
In[26]: x2[:3, ::2] # 所有行,每隔一列
Out[26]: array([[12,2],
								[ 7,8],
								[ 1,7]])

最後,子數組維度也可以同時被逆序:

In[27]: x2[::-1, ::-1] 
Out[27]: array([[ 7, 7, 6, 1],
								[8, 8 ,6, 7],
								[4, 2, 5, 12]])
  1. 獲取數組的行和列

一種常見的需求是獲取數組的單行和單列。你可以將索引與切片組合起來實現這個功能,用一個冒號(:)表示空切片:

In[28]: print(x2[:, 0])  # x2的第一列
[12 7 1]  
In[29]: print(x2[0, :]) # x2的第一行
[12 5 2 4]

在獲取行時,出於語法的簡介考慮,可以省略空的切片:

In[30]: print(x2[0]) #等於x2[0, :]
[12 5 2 4]

需要注意的是,二位數組切片獲取某一列,得到是數組,而不是二維單列,只有一個緯度。
04. 非副本視圖的子數組

關於數組切片有一點很重要也非常有用,那就是數組切片返回的是數組數據的視圖,而不是數值數據的副本。這一點也是 NumPy 數組切 片和 Python 列表切片的不同之處:在 Python 列表中,切片是值的副本。

例如此前示例中的那個二維數組:

In[31]: print(x2) 
[[12 5 2 4]
 [ 7 6 8 8]
 [ 1 6 7 7]]

從中抽取一個 2×2 的子數組:

In[32]: x2_sub = x2[:2, :2] 
print(x2_sub)
[[12 5] 
 [ 7 6]]

現在如果修改這個子數組,將會看到原始數組也被修改了!結果如下所示:

In[33]: x2_sub[0, 0] = 99 
print(x2_sub)

[[99 5] 
 [ 7 6]]

In[34]: print(x2)

[[99 5 2 4]
 [ 7 6 8 8]
 [1 6 7 7]]

這種默認的處理方式實際上非常有用:它意味着在處理非常大的數據集時,可以獲取或處理這些數據集的片段,而不用複製底層的數據緩 存。

  1. 創建數組的副本

儘管數組視圖有一些非常好的特性,但是在有些時候明確地複製數組裏的數據或子數組也是非常有用的。可以很簡單地通過 copy() 方法 實現:

In[35]: x2_sub_copy = x2[:2, :2].copy() 
print(x2_sub_copy)

[[99 5]
 [ 7 6]]

如果修改這個子數組,原始的數組不會被改變:

In[36]: x2_sub_copy[0, 0] = 42 
print(x2_sub_copy)

[[42 5] 
 [ 7 6]]

In[37]: print(x2)

[[99 5 2 4]
 [ 7 6 8 8]
 [1 6 7 7]]

4 數組變形和拼接、分裂

4.1數組變形

可以使用各種命令更改數組的形狀。請注意,以下三個命令都返回一個修改後的數組,但不會更改原始數組:

ravel
reshape
nT
>>> a.ravel()  # returns the array, flattened
array([ 2.,  8.,  0.,  6.,  4.,  5.,  1.,  1.,  8.,  9.,  3.,  6.])
>>> a.reshape(6,2)  # returns the array with a modified shape
array([[ 2.,  8.],
       [ 0.,  6.],
       [ 4.,  5.],
       [ 1.,  1.],
       [ 8.,  9.],
       [ 3.,  6.]])
>>> a.T  # returns the array, transposed
array([[ 2.,  4.,  8.],
       [ 8.,  5.,  9.],
       [ 0.,  1.,  3.],
       [ 6.,  1.,  6.]])
>>> a.T.shape
(4, 3)
>>> a.shape
(3, 4)

ndarray.resize方法會修改數組本身:

>>> a
array([[ 2.,  8.,  0.,  6.],
       [ 4.,  5.,  1.,  1.],
       [ 8.,  9.,  3.,  6.]])
>>> a.resize((2,6))
>>> a
array([[ 2.,  8.,  0.,  6.,  4.,  5.],
       [ 1.,  1.,  8.,  9.,  3.,  6.]])

4.2 數組拼接

拼接或連接 NumPy 中的兩個數組主要由 np.concatenate、np.vstack 和 np.hstack 例程實現。np.concatenate 將數組元組或數組列 表作爲第一個參數,如下所示:

In[43]: x = np.array([1, 2, 3]) 
				y = np.array([3, 2, 1]) 
				np.concatenate([x, y])
Out[43]: array([1, 2, 3, 3, 2, 1])

你也可以一次性拼接兩個以上數組:

In[44]: z = [99, 99, 99]
print(np.concatenate([x, y, z]))

[ 1  2   3  3  2  1 99 99 99]

np.concatenate 也可以用於二維數組的拼接:

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

In[46]: # 沿着第一個軸拼接 np.concatenate([grid, grid])

Out[46]: array([[1, 2, 3],
								[4, 5, 6],
                [1, 2, 3], 
                [4, 5, 6]])

In[47]: # 沿着第二個軸拼接(從0開始索引) np.concatenate([grid, grid], axis=1)

Out[47]: array([[1, 2, 3, 1, 2, 3], 
								[4, 5, 6, 4, 5, 6]])

沿着固定維度處理數組時,使用 np.vstack(垂直棧)和 np.hstack(水平棧)函數會更簡潔:

In[48]: x = np.array([1, 2, 3])

grid = np.array([[9, 8, 7],
                 [6, 5, 4]])

垂直棧數組 np.vstack([x, grid])

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

In[49]: # 水平棧數組

y = np.array([[99], [99]]) 
np.hstack([grid, y])

Out[49]: array([[ 9, 8, 7, 99],
[ 6, 5, 4, 99]])

與之類似,np.dstack 將沿着第三個維度拼接數組。

4.3 數組分裂

與拼接相反的過程是分裂。分裂可以通過 np.split、np.hsplit 和 np.vsplit 函數來實現。可以向以上函數傳遞一個索引列表作爲參 數,索引列表記錄的是分裂點位置:

In[50]: x = [1, 2, 3, 99, 99, 3, 2, 1] 

x1, x2, x3 = np.split(x, [3, 5]) 
print(x1, x2, x3)

[1 2 3] [99 99] [3 2 1]

值得注意的是,N 分裂點會得到 N + 1 個子數組。相關的 np.hsplit 和 np.vsplit 的用法也類似:

In[51]: grid = np.arange(16).reshape((4, 4)) grid

Out[51]: array([[ 0, 1, 2, 3],
								[ 4, 5, 6, 7], 
								[ 8, 9, 10, 11], 
								[12, 13, 14, 15]])

In[52]: upper, lower = np.vsplit(grid, [2])
				print(upper) 
				print(lower)

[[0 1 2 3] 
[4 5 6 7]]
[[ 8 9 10 11]
[12 13 14 15]]

In[53]: left, right = np.hsplit(grid, [2]) 
				print(left)
        print(right)

[[ 0 1]
[ 4 5] 
[ 8 9] 
[12 13]]

[[ 2 3] 
[ 6 7]
[10 11] 
[14 15]]

同樣,np.dsplit 將數組沿着第三個維度分裂。

5 通用函數

5.1 數組的運算

NumPy 通用函數的使用方式非常自然,因爲它用到了 Python 原生的算術運算符,標準的加、減、乘、除都可以使用:

In[7]: x = np.arange(4)

print("x =", x) 
print("x + 5 =", x + 5) 
print("x - 5 =", x - 5) 
print("x * 2 =", x * 2) 
print("x / 2 =", x / 2)
print("x // 2 =", x // 2) #地板除法運算

x = [0 1 2 3]
x + 5 = [5 6 7 8] 
x - 5 = [-5 -4 -3 -2] 
x * 2 = [0 2 4 6] 
x / 2 = [ 0. 0.5 1. 1.5]
x // 2 = [0 0 1 1]

還有邏輯非、** 表示的指數運算符和 % 表示的模運算符的一元通用函數:

In[8]: print("-x = ", -x)
			print("x ** 2 = ", x ** 2) 
			print("x % 2 = ", x % 2)

-x = [ 0 -1 -2 -3] 
x ** 2 = [0 1 4 9]
x % 2 = [0 1 0 1] 

你可以任意將這些算術運算符組合使用。當然,你得考慮這些運算符的優先級:

In[9]: -(0.5*x + 1) ** 2

Out[9]: array([-1. , -2.25, -4. , -6.25])

所有這些算術運算符都是 NumPy 內置函數的簡單封裝器,例如 + 運算符就是一個 add 函數的封裝器:

In[10]: np.add(x, 2)

Out[10]: array([2, 3, 4, 5])

表 2-2 列出了所有 NumPy 實現的算術運算符。 表2-2:NumPy實現的算術運算符

運算符 對應的通用函數 描述
+ np.add 加法運算(即 1 + 1 = 2)
- np.subtract 減法運算(即 3 - 2 = 1)
- np.negative 負數運算( 即 -2)
* np.multiply 乘法運算(即 2 * 3 = 6)
/ np.divide 除法運算(即 3 / 2 = 1.5)
// np.floor_divide 地板除法運算(floor division,即 3 // 2 = 1)
** np.power 指數運算(即 2 ** 3 = 8)
% np.mod 模 / 餘數( 即 9 % 4 = 1)

另外,NumPy 中還有布爾 / 位運算符.

需要注意的是與許多矩陣語言不同,乘積運算符*在NumPy數組中按元素進行運算。矩陣乘積可以使用@運算符(在python> = 3.5中)或dot(不推薦)函數或方法執行.
@也能表示兩個數組的點積。

>>> A = np.array( [[1,1],
...             [0,1]] )
>>> B = np.array( [[2,0],
...             [3,4]] )
>>> A * B                       # elementwise product
array([[2, 0],
       [0, 4]])
>>> A @ B                       # matrix product
array([[5, 4],
       [3, 4]])
>>> A.dot(B)                    # another matrix product
array([[5, 4],
       [3, 4]])

5.2 其他數學函數

5.2.1 絕對值

正如 NumPy 能理解 Python 內置的運算操作,NumPy 也可以理解 Python 內置的絕對值函數:

In[11]: x = np.array([-2, -1, 0, 1, 2]) 
				abs(x)

Out[11]: array([2, 1, 0, 1, 2])

對應的 NumPy 通用函數是 np.absolute,該函數也可以用別名 np.abs 來訪問:

In[12]: np.absolute(x)

Out[12]: array([2, 1, 0, 1, 2])

In[13]: np.abs(x)

Out[13]: array([2, 1, 0, 1, 2])

這個通用函數也可以處理複數。當處理複數時,絕對值返回的是該複數的幅度:

In[14]: x = np.array([3 - 4j, 4 - 3j, 2 + 0j, 0 + 1j]) 
				np.abs(x)

Out[14]: array([ 5., 5., 2., 1.])

5.2.2 三角函數

NumPy 提供了大量好用的通用函數,其中對於數據科學家最有用的就是三角函數。首先定義一個角度數組:

In[15]: theta = np.linspace(0, np.pi, 3)

現在可以對這些值進行一些三角函數計算:

In[16]: print("theta = ", theta)
				print("sin(theta) = ", np.sin(theta)) 
				print("cos(theta) = ", np.cos(theta)) 
				print("tan(theta) = ", np.tan(theta))

theta = [ 0. 1.57079633 3.14159265] 
sin(theta) = [ 0.00000000e+00 1.00000000e+00 1.22464680e-16] 
cos(theta) = [ 1.00000000e+00 6.12323400e-17 -1.00000000e+00]
tan(theta) = [ 0.00000000e+00 1.63312394e+16 -1.22464680e-16]

這些值是在機器精度內計算的,所以有些應該是 0 的值並沒有精確到 0 。逆三角函數同樣可以使用:

In[17]: x = [-1, 0, 1]
				print("x = ", x) 
				print("arcsin(x) = ", np.arcsin(x))
        print("arccos(x) = ", np.arccos(x))
        print("arctan(x) = ", np.arctan(x))

x = [-1, 0, 1]
arcsin(x) =  [-1.57079633 0. 1.57079633]
arccos(x) = [3.14159265 1.57079633 0. ]
arctan(x) = [-0.78539816 0. 0.78539816]

5.2.3 指數和對數

NumPy 中另一個常用的運算通用函數是指數運算:

In[18]: x = [1, 2, 3] 
print("x=", x)
print("e^x =", np.exp(x))
print("2^x  =", np.exp2(x)) 
print("3^x=", np.power(3, x))
x = [1, 2, 3]
e^x = [ 2.71828183   7.3890561  20.08553692]
2^x  = [ 2. 4. 8.]
3^x = [ 3 9 27]

指數運算的逆運算,即對數運算也是可用的。最基本的 np.log 給出的是以自然數爲底數的對數。如果你希望計算以 2 爲底數或者以 10 爲 底數的對數,可以按照如下示例處理:

In[19]: x = [1, 2, 4, 10]

print("x =", x) 
print("ln(x) =", np.log(x)) 
print("log2(x) =", np.log2(x)) 
print("log10(x) =", np.log10(x))

x = [1, 2, 4, 10] 
ln(x) = [ 0.     0.69314718    1.38629436  2.30258509]

log2(x) = [ 0.   1.   2.   3.32192809]

log10(x) = [ 0.    0.30103    0.60205999   1. ] 

還有一些特殊的版本,對於非常小的輸入值可以保持較好的精度:

In[20]: x = [0, 0.001, 0.01, 0.1]

print("exp(x) - 1 =", np.expm1(x)) 
print("log(1 + x) =", np.log1p(x))

exp(x) - 1 = [ 0.   0.0010005 	0.01005017	0.10517092]
log(1 + x) = [ 0. 	0.0009995 	0.00995033	0.09531018]

當 x 的值很小時,以上函數給出的值比 np.log 和 np.exp 的計算更精確。

5.2.4 舍入函數

numpy.around()

around()函數返回四捨五入到指定精度的值。

numpy.around(num, decimals)  

複製

參數:

  • num 輸入數值。
  • decimals 四捨五入的精度。默認值爲0,如果是負數,對小數點之前進行四捨五入。

示例

import numpy as np 
a = np.array([1.0,5.55, 123, 0.567, 25.532]) 

print ('數組原始值:') 
print (a) 
print ('\n')  

print ('四捨五入後:') 
print (np.around(a)) 
print (np.around(a, decimals = 1)) 
print (np.around(a, decimals = -1)) 

複製

輸出

數組原始值:                                                               
[   1.       5.55   123.       0.567   25.532] 

四捨五入後:                                                               
[   1.    6.   123.    1.   26. ]                                               
[   1.    5.6  123.    0.6  25.5]                                          
[   0.    10.  120.    0.   30. ]

numpy.floor()

floor()函數用於對數值往小取整。

示例

import numpy as np 
a = np.array([-1.7, 1.5, -0.2, 0.6, 10]) 

print ('數組原始值:') 
print (a) 
print ('\n')  

print ('修改後:') 
print (np.floor(a))

複製

輸出

數組原始值:                                                              
[-1.7  1.5 -0.2  0.6 10. ]


修改後:                                                           
[-2.  1. -1.  0. 10.]

複製

numpy.ceil()

ceil()函數用於對數值往大取整。

示例

import numpy as np 
a = np.array([-1.7, 1.5, -0.2, 0.6, 10]) 

print ('數組原始值:') 
print (a) 
print ('\n')  

print ('修改後:') 
print (np.ceil(a))

複製

輸出

數組原始值:                                                              
[-1.7  1.5 -0.2  0.6 10. ]

修改後:                                                           
[-1.  2. -0.  1. 10.]

5.3 統計函數

5.3.1 Order statistics

method description
amin(a[, axis, out, keepdims, initial, where]) Return the minimum of an array or minimum along an axis.
amax(a[, axis, out, keepdims, initial, where]) Return the maximum of an array or maximum along an axis.
nanmin(a[, axis, out, keepdims]) Return minimum of an array or minimum along an axis, ignoring any NaNs.
nanmax(a[, axis, out, keepdims]) Return the maximum of an array or maximum along an axis, ignoring any NaNs.
ptp(a[, axis, out, keepdims]) Range of values (maximum - minimum) along an axis.
percentile(a, q[, axis, out, …]) Compute the q-th percentile of the data along the specified axis.
nanpercentile(a, q[, axis, out, …]) Compute the qth percentile of the data along the specified axis, while ignoring nan values.
quantile(a, q[, axis, out, overwrite_input, …]) Compute the q-th quantile of the data along the specified axis.
nanquantile(a, q[, axis, out, …]) Compute the qth quantile of the data along the specified axis, while ignoring nan values.

5.3.2#Averages and variances

method description
median(a[, axis, out, overwrite_input, keepdims]) Compute the median along the specified axis.
average(a[, axis, weights, returned]) Compute the weighted average along the specified axis.
mean(a[, axis, dtype, out, keepdims]) Compute the arithmetic mean along the specified axis.
std(a[, axis, dtype, out, ddof, keepdims]) Compute the standard deviation along the specified axis.
var(a[, axis, dtype, out, ddof, keepdims]) Compute the variance along the specified axis.
nanmedian(a[, axis, out, overwrite_input, …]) Compute the median along the specified axis, while ignoring NaNs.
nanmean(a[, axis, dtype, out, keepdims]) Compute the arithmetic mean along the specified axis, ignoring NaNs.
nanstd(a[, axis, dtype, out, ddof, keepdims]) Compute the standard deviation along the specified axis, while ignoring NaNs.
nanvar(a[, axis, dtype, out, ddof, keepdims]) Compute the variance along the specified axis, while ignoring NaNs.

5.3.3 #Correlating

method description
corrcoef(x[, y, rowvar, bias, ddof]) Return Pearson product-moment correlation coefficients.
correlate(a, v[, mode]) Cross-correlation of two 1-dimensional sequences.
cov(m[, y, rowvar, bias, ddof, fweights, …]) Estimate a covariance matrix, given data and weights.

5.3.4#Histograms

method description
histogram(a[, bins, range, normed, weights, …]) Compute the histogram of a set of data.
histogram2d(x, y[, bins, range, normed, …]) Compute the bi-dimensional histogram of two data samples.
histogramdd(sample[, bins, range, normed, …]) Compute the multidimensional histogram of some data.
bincount(x[, weights, minlength]) Count number of occurrences of each value in array of non-negative ints.
histogram_bin_edges(a[, bins, range, weights]) Function to calculate only the edges of the bins used by the histogram function.
digitize(x, bins[, right]) Return the indices of the bins to which each value in input array belongs.

5.4 排序、查找和計數

Sorting, searching, and counting

#Sorting

method description
sort(a[, axis, kind, order]) Return a sorted copy of an array.
lexsort(keys[, axis]) Perform an indirect stable sort using a sequence of keys.
argsort(a[, axis, kind, order]) Returns the indices that would sort an array.
ndarray.sort([axis, kind, order]) Sort an array in-place.
msort(a) Return a copy of an array sorted along the first axis.
sort_complex(a) Sort a complex array using the real part first, then the imaginary part.
partition(a, kth[, axis, kind, order]) Return a partitioned copy of an array.
argpartition(a, kth[, axis, kind, order]) Perform an indirect partition along the given axis using the algorithm specified by the kind keyword.

#Searching

method description
argmax(a[, axis, out]) Returns the indices of the maximum values along an axis.
nanargmax(a[, axis]) Return the indices of the maximum values in the specified axis ignoring NaNs.
argmin(a[, axis, out]) Returns the indices of the minimum values along an axis.
nanargmin(a[, axis]) Return the indices of the minimum values in the specified axis ignoring NaNs.
argwhere(a) Find the indices of array elements that are non-zero, grouped by element.
nonzero(a) Return the indices of the elements that are non-zero.
flatnonzero(a) Return indices that are non-zero in the flattened version of a.
where(condition, [x, y]) Return elements chosen from x or y depending on condition.
searchsorted(a, v[, side, sorter]) Find indices where elements should be inserted to maintain order.
extract(condition, arr) Return the elements of an array that satisfy some condition.

#Counting

method description
count_nonzero(a[, axis]) Counts the number of non-zero values in the array a.

5.5 專用的通用函數

sqrt(x, /[, out, where, cast, order, …]) 以元素方式返回數組的非負平方根。
square(x, /[, out, where, cast, order, …]) 返回輸入的元素方塊。
cbrt(x, /[, out, where, cast, order, …]) 以元素方式返回數組的立方根。
reciprocal(x, /[, out, where, cast, …]) 以元素方式返回參數的倒數。

6 聚合

當你面對大量的數據時,第一個步驟通常都是計算相關數據的概括統計值。最常用的概括統計值可能是均值和標準差,這兩個值能讓你分別概 括出數據集中的“經典”值,但是其他一些形式的聚合也是非常有用的(如求和、乘積、中位數、最小值和最大值、分位數,等等)。

NumPy 有非常快速的內置聚合函數可用於數組,我們將介紹其中的一些。

### 6.1 數組值求和

先來看一個小例子,設想計算一個數組中所有元素的和。Python 本身可用內置的 sum 函數來實現:

In[1]: import numpy as np

In[2]: L = np.random.random(100) sum(L)

Out[2]: 55.61209116604941

它的語法和 NumPy 的 sum 函數非常相似,並且在這個簡單的例子中的結果也是一樣的:

In[3]: np.sum(L)

Out[3]: 55.612091166049424

但是,因爲 NumPy 的 sum 函數在編譯碼中執行操作,所以 NumPy 的操作計算得更快一些:

In[4]: big_array = np.random.rand(1000000) 
				%timeit sum(big_array) 
				%timeit np.sum(big_array)

10 loops, best of 3: 104 ms per loop 
1000 loops, best of 3: 442 μs per loop

但是需要注意,sum 函數和 np.sum 函數並不等同,這有時會導致混淆。尤其是它們各自的可選參數都有不同的含義,np.sum 函數是知道數組 的維度的,這一點將在接下來的部分講解。

6.2 最小值和最大值

同樣,Python 也有內置的 min 函數和 max 函數,分別被用於獲取給定數組的最小值和最大值:``

In[5]: min(big_array), max(big_array)

Out[5]: (1.1717128136634614e-06, 0.9999976784968716)

NumPy 對應的函數也有類似的語法,並且也執行得更快:

In[6]: np.min(big_array), np.max(big_array)

Out[6]: (1.1717128136634614e-06, 0.9999976784968716)

In[7]: %timeit min(big_array) 
				%timeit np.min(big_array)

10 loops, best of 3: 82.3 ms per loop 
1000 loops, best of 3: 497 μs per loop

對於 min、max、sum 和其他 NumPy 聚合,一種更簡潔的語法形式是數組對象直接調用這些方法:

In[8]: print(big_array.min(), big_array.max(), big_array.sum())

1.17171281366e-06 0.999997678497 499911.628197

當你操作 NumPy 數組時,確保你執行的是 NumPy 版本的聚合。

6.3 多維度聚合

一種常用的聚合操作是沿着一行或一列聚合。例如,假設你有一些數據存儲在二維數組中:

In[9]: M = np.random.random((3, 4)) print(M)

[[ 0.8967576	0.03783739 0.75952519	0.06682827]

[ 0.8354065	0.99196818 0.19544769	0.43447084]

 [ 0.66859307	0.15038721 0.37911423	0.6687194]]

默認情況下,每一個 NumPy 聚合函數將會返回對整個數組的聚合結果:

In[10]: M.sum()

Out[10]: 6.0850555667307118

聚合函數還有一個參數,用於指定沿着哪個軸的方向進行聚合。例如,可以通過指定 axis=0 找到每一列的最小值:

In[11]: M.min(axis=0)

Out[11]: array([ 0.66859307, 0.03783739, 0.19544769, 0.06682827])

這個函數返回四個值,對應四列數字的計算值。同樣,也可以找到每一行的最大值:

In[12]: M.max(axis=1)

Out[12]: array([ 0.8967576 , 0.99196818, 0.6687194])

其他語言的用戶會對軸的指定方式比較困惑。axis 關鍵字指定的是數組將會被摺疊的維度,而不是將要返回的維度。因此指定 axis=0 意味着第一個軸將要被摺疊——對於二維數組,這意味着每一列的值都將被聚合。

6.4 其他聚合函數

NumPy 提供了很多其他聚合函數,但是這裏不會詳細地介紹它們。另外,大多數的聚合都有對 NaN 值的安全處理策略(NaN-safe),即計 算時忽略所有的缺失值,這些缺失值即特殊的 IEEE 浮點型 NaN 值(關於缺失值更全面的介紹請參見 3.5 節)。有些 NaN-safe 的函數直到 NumPy 1.8 版本才加進去,所以更早版本的 NumPy 並不支持此功能。 表 2-3 提供了一個 NumPy 中可用的聚合函數的清單。 表2-3:NumPy中可用的聚合函數

函數名稱 NaN安全版本 描述
np.sum np.nansum 計算元素的和
np.prod np.nanprod 計算元素的積
np.mean np.nanmean 計算元素的平均值
np.std np.nanstd 計算元素的標準差
np.var np.nanvar 計算元素的方差
np.min np.nanmin 找出最小值
np.max np.nanmax 找出最大值
np.argmin np.nanargmin 找出最小值的索引
np.argmax np.nanargmax 找出最大值的索引
np.median np.nanmedian 計算元素的中位數
np.percentile np.nanpercentile 計算基於元素排序的統計值
np.any N/A 驗證任何一個元素是否爲真
np.all N/A 驗證所有元素是否爲真

7 廣播

廣播可以簡單理解爲用於不同大小數組的二進制通用函數(加、減、乘等)的一組規則。
2.5.1 廣播的介紹

前面曾提到,對於同樣大小的數組,二進制操作是對相應元素逐個計算:

In[1]: import numpy as np

In[2]: a = np.array([0, 1, 2]) 
			 b = np.array([5, 5, 5])
       a + b
Out[2]: array([5, 6, 7])

廣播允許這些二進制操作可以用於不同大小的數組。例如,可以簡單地將一個標量(可以認爲是一個零維的數組)和一個數組相加:

In[3]: a + 5

Out[3]: array([5, 6, 7])

我們可以認爲這個操作是將數值 5 擴展或重複至數組 [5, 5, 5],然後執行加法。NumPy 廣播功能的好處是,這種對值的重複實際上並沒有 發生,但是這是一種很好用的理解廣播的模型。 我們同樣也可以將這個原理擴展到更高維度的數組。觀察以下將一個一維數組和一個二維數組相加的結果:

In[4]: M = np.ones((3, 3))
M

Out[4]: array([[ 1., [ 1., [ 1.,

In[5]: M + a

Out[5]: array([[ 1., [ 1., [ 1.,

1., 1.],

1., 1.],

1., 1.]])

2., 3.],

2., 3.],

2., 3.]])

這裏這個一維數組就被擴展或者廣播了。它沿着第二個維度擴展,擴展到匹配 M 數組的形狀。 以上的這些例子理解起來都相對容易,更復雜的情況會涉及對兩個數組的同時廣播,例如以下示例:

In[6]: a = np.arange(3) b = np.arange(3)[:, np.newaxis]

print(a) print(b)

[0 1 2] [[0]

[1]

[2]]

In[7]: a + b

Out[7]: array([[0, 1, 2],

[1, 2, 3], [2, 3, 4]])

正如此前將一個值擴展或廣播以匹配另外一個數組的形狀,這裏將 a 和 b 都進行了擴展來匹配一個公共的形狀,最終的結果是一個二維數組。 以上這些例子的幾何可視化如圖 所示。

在這裏插入圖片描述
圖 2-4:NumPy 廣播的可視化 淺色的盒子表示廣播的值。同樣需要注意的是,這個額外的內存並沒有在實際操作中進行分配,但是這樣的想象方式更方便我們從概念上理 解。

廣播的規則

NumPy 的廣播遵循一組嚴格的規則,設定這組規則是爲了決定兩個數組間的操作。

規則 1:如果兩個數組的維度數不相同,那麼小維度數組的形狀將會在最左邊補 1。

規則 2:如果兩個數組的形狀在任何一個維度上都不匹配,那麼數組的形狀會沿着維度爲 1 的維度擴展以匹配另外一個數組的形狀。

規則 3:如果兩個數組的形狀在任何一個維度上都不匹配並且沒有任何一個維度等於 1,那麼會引發異常。 爲了更清楚地理解這些規則,來看幾個具體示例。

  1. 廣播示例1 將一個二維數組與一個一維數組相加:
In[8]: M = np.ones((2, 3)) 
a = np.arange(3)

來看這兩個數組的加法操作。兩個數組的形狀如下:

M.shape = (2, 3)
a.shape = (3,)

可以看到,根據規則 1,數組 a 的維度數更小,所以在其左邊補 1:

M.shape -> (2, 3) 
a.shape -> (1, 3)

根據規則 2,第一個維度不匹配,因此擴展這個維度以匹配數組:

M.shape -> (2, 3)
a.shape -> (2, 3)

現在兩個數組的形狀匹配了,可以看到它們的最終形狀都爲 (2, 3):

In[9]: M + a

Out[9]: array([[ 1.,2., 3.],
							[ 1.,,2., 3.]])
  1. 廣播示例2

來看兩個數組均需要廣播的示例:

In[10]: a = np.arange(3).reshape((3, 1))
b = np.arange(3)

同樣,首先寫出兩個數組的形狀:

a.shape = (3, 1) 
b.shape = (3,)

規則 1 告訴我們,需要用 1 將 b 的形狀補全:

a.shape -> (3, 1) 
b.shape -> (1, 3)

規則 2 告訴我們,需要更新這兩個數組的維度來相互匹配:

a.shape -> (3, 3) b.shape -> (3, 3)

因爲結果匹配,所以這兩個形狀是兼容的,可以看到以下結果:

In[11]: a + b

Out[11]: array([[0, 1, 2],
								[1, 2, 3], 
								[2, 3, 4]])
  1. 廣播示例3

現在來看一個兩個數組不兼容的示例:

In[12]: M = np.ones((3, 2))
a = np.arange(3)

和第一個示例相比,這裏有個微小的不同之處:矩陣 M 是轉置的。那麼這將如何影響計算呢?兩個數組的形狀如下:

M.shape = (3, 2) 
a.shape = (3,)

同樣,規則 1 告訴我們,a 數組的形狀必須用 1 進行補全:

M.shape -> (3, 2) 
a.shape -> (1, 3)

根據規則 2,a 數組的第一個維度進行擴展以匹配 M 的維度:

M.shape -> (3, 2) a.shape -> (3, 3)

現在需要用到規則 3——最終的形狀還是不匹配,因此這兩個數組是不兼容的。當我們執行運算時會看到以下結果:

In[13]: M + a  

--------------------------------------------------------------------------  ValueError Traceback (most recent call last)   <ipython-input-13-9e16e9f98da6> in <module>()

----> 1 M + a     ValueError: operands could not be broadcast together with shapes (3,2) (3,)

請注意,這裏可能發生的混淆在於:你可能想通過在 a 數組的右邊補 1,而不是左邊補 1,讓 a 和 M 的維度變得兼容。但是這不被廣播的 規則所允許。這種靈活性在有些情景中可能會有用,但是它可能會導致結果模糊。如果你希望實現右邊補全,可以通過變形數組來實現 (將會用到 np.newaxis 關鍵字,詳情請參見 2.2 節):

In[14]: a[:, np.newaxis].shape

Out[14]: (3, 1)

In[15]: M + a[:, np.newaxis]

Out[15]: array([[ 1.,1.],
								[ 2.,2.],
								[ 3.,3.]])

另外也需要注意,這裏僅用到了 + 運算符,而這些廣播規則對於任意二進制通用函數都是適用的。例如這裏的 logaddexp(a, b) 函數, 比起簡單的方法,該函數計算 log(exp(a) + exp(b)) 更準確:

In[16]: np.logaddexp(M, a[:, np.newaxis])

Out[16]: array([[ 1.31326169, 1.31326169],
								[ 1.69314718, 1.69314718], 
								[ 2.31326169,2.31326169]])

8 比較、掩碼和布爾邏輯

9 花哨的索引

10 數組的排序

儘管 Python 有內置的 sort 和 sorted 函數可以對列表進行排序,但是這裏不會介紹這兩個函數,因爲 NumPy 的 np.sort 函數實際上效率更 高。默認情況下,np.sort 的排序算法是 快速排序,其算法複雜度爲 [N log N],另外也可以選擇歸併排序和堆排序。對於大多數應用場景, 默認的快速排序已經足夠高效了。

如果想在不修改原始輸入數組的基礎上返回一個排好序的數組,可以使用 np.sort:

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

Out[5]: array([1, 2, 3, 4, 5])

如果希望用排好序的數組替代原始數組,可以使用數組的 sort 方法:

In[6]: x.sort() 
				print(x)

[1 2 3 4 5]

另外一個相關的函數是 argsort,該函數返回的是原始數組排好序的索引值:

In[7]: x = np.array([2, 1, 4, 3, 5]) 
				i = np.argsort(x) 
				print(i)

[1 0 3 2 4]

以上結果的第一個元素是數組中最小元素的索引值,第二個值給出的是次小元素的索引值,以此類推。這些索引值可以被用於(通過花哨的索 引)創建有序的數組:

In[8]: x[i] 
Out[8]: array([1, 2, 3, 4, 5])

沿着行或列排序 NumPy 排序算法的一個有用的功能是通過 axis 參數,沿着多維數組的行或列進行排序,例如:

In[9]: rand = np.random.RandomState(42)
X = rand.randint(0, 10, (4, 6))
print(X)

[[6 3 7 4 6 9]
	[2 6 7 4 3 7] 
	[7 2 5 4 1 7]
	[5 1 4 0 9 5]]

In[10]: # 對X的每一列排序
np.sort(X, axis=0)

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

In[11]: # 對X每一行排序 np.sort(X, axis=1)

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

需要記住的是,這種處理方式是將行或列當作獨立的數組,任何行或列的值之間的關係將會丟失!

11 結構化數據

12 副本和視圖

數組副本是內容與原數組相同,存儲在另一個內存位置的數組。

數組視圖是由原數組生成的另一個數組,但是與原數組共享數組元素內存,是對同一個內存位置所存儲數組元素的不同呈現。

數組引用是原數組的別名,與原數組是同一個數組。

數組賦值

NumPy中,把一個數組賦值給另一個數組,不會拷貝數組,賦值只是對原始數組的引用。對被賦值數組做的更改也會反映在原始數組中。

id()函數返回數組的通用標識符,類似於C語言中的指針。

示例

import numpy as np  

a = np.array([[1,2,3,4],[9,0,2,3],[1,2,3,19]])  

print("原始數組:")
print(a)
print('\n')  

print("數組a的ID:", id(a))  

b = a   

print("\n賦值操作 b = a:")  

print("\nb的ID:",id(b))  

b.shape = 4,3;  

print("\nb上的修改也反映到a上:")  
print(a)  

複製

輸出

原始數組:
 [[ 1  2  3  4]
  [ 9  0  2  3]
  [ 1  2  3 19]]

數組a的ID: 140377691416656

賦值操作 b = a:

b的ID: 140377691416656

b上的修改也反映到a上:
[[ 1  2  3]
 [ 4  9  0]
 [ 2  3  1]
 [ 2  3 19]]

複製

ndarray.view()

view()方法返回新的數組對象,但數組元素數據與原始數組共享,因此是淺拷貝。與前面的情況不同,新數組的維數更改不會影響原數組的維數。

示例

import numpy as np  

a = np.array([[1,2,3,4],[9,0,2,3],[1,2,3,19]])  

print("原始數組:\n",a)  

print("\na的ID:",id(a))  

b = a.view()  

print("\nb的ID:",id(b))  

print("\n打印b的view")  
print(b)  

b.shape = 4,3;  

print("\nb的維數更改不影響a")  
print("\n原始數組 \n",a)  
print("\nview\n",b)  


b[0, 0] = 100

print("\nb的元素更改會影響a")  
print("\n原始數組 \n",a)  
print("\nview\n",b)  

複製

輸出

原始數組:
 [[ 1  2  3  4]
 [ 9  0  2  3]
 [ 1  2  3 19]]

a的ID: 140249104167360

b的ID: 140249103376752

打印b的view
[[ 1  2  3  4]
 [ 9  0  2  3]
 [ 1  2  3 19]]

b的維數更改不影響a

原始數組
 [[ 1  2  3  4]
 [ 9  0  2  3]
 [ 1  2  3 19]]

view
 [[ 1  2  3]
 [ 4  9  0]
 [ 2  3  1]
 [ 2  3 19]]

b的元素更改會影響a

原始數組
 [[100   2   3   4]
 [  9   0   2   3]
 [  1   2   3  19]]

view
 [[100   2   3]
 [  4   9   0]
 [  2   3   1]
 [  2   3  19]]

複製

ndarray.copy()

copy()返回原始數組的深層副本,該副本不與原始數組共享任何內存,是深拷貝。對數組副本所做的修改不會影響原始數組。

示例

import numpy as np  

a = np.array([[1,2,3,4],[9,0,2,3],[1,2,3,19]])  

print("原始數組:\n", a)  

print("\na的ID:", id(a))  

b = a.copy()  

print("\nb的ID:", id(b))  

print("\n打印b")  
print(b)  

b.shape = 4,3;  

print("\nb的維數更改不影響a")  
print("\n原始數組a \n", a)  
print("\n數組副本b \n", b)  


b[0, 0] = 100

print("\nb的元素更改不影響a")  
print("\n原始數組a \n", a)  
print("\n數組副本b \n", b)  

複製

輸出

原始數組:
 [[ 1  2  3  4]
 [ 9  0  2  3]
 [ 1  2  3 19]]

a的ID: 140312719819200

b的ID: 140312509357872

打印b
[[ 1  2  3  4]
 [ 9  0  2  3]
 [ 1  2  3 19]]

b的維數更改不影響a

原始數組a
 [[ 1  2  3  4]
 [ 9  0  2  3]
 [ 1  2  3 19]]

數組副本b
 [[ 1  2  3]
 [ 4  9  0]
 [ 2  3  1]
 [ 2  3 19]]

b的元素更改不影響a

原始數組a
 [[ 1  2  3  4]
 [ 9  0  2  3]
 [ 1  2  3 19]]

數組副本b
 [[100   2   3]
 [  4   9   0]
 [  2   3   1]
 [  2   3  19]]

numpy 切片

numpy切片和python切片不同的是,numpy切片是視圖,而python切片是副本

矩陣庫和線性代數

numpy保護兩種數據對象,數組和矩陣

矩陣庫

numpy.matlib
不推薦使用

線性代數函數

reference

numpy 中文網 www.numpy.org.cn

<<python 數據科學手冊>>

https://www.qikegu.com/docs/3466

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章